summaryrefslogtreecommitdiff
path: root/data/lighttpd/lighttpd-1.4.53/src
diff options
context:
space:
mode:
Diffstat (limited to 'data/lighttpd/lighttpd-1.4.53/src')
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/CMakeLists.txt1080
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/Makefile.am586
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/Makefile.in4913
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/SConscript337
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/algo_sha1.c173
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/algo_sha1.h82
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/array.c606
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/array.h98
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/base.h468
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/base64.c235
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/base64.h20
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/base_decls.h30
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/buffer.c1028
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/buffer.h226
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/burl.c512
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/burl.h46
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/chunk.c830
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/chunk.h111
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/config.h.cmake169
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/configfile-glue.c584
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/configfile.c1665
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/configfile.h140
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/configparser.c1870
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/configparser.h26
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/configparser.y795
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/connections-glue.c506
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/connections.c1409
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/connections.h23
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/crc32.c84
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/crc32.h7
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/data_array.c70
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/data_config.c221
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/data_integer.c71
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/data_string.c98
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/etag.c180
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/etag.h16
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fastcgi.h139
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent.c1033
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent.h97
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_freebsd_kqueue.c232
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_impl.h154
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_libev.c177
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_linux_sysepoll.c166
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_poll.c211
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_select.c133
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_devpoll.c172
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_port.c175
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/first.h97
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/gw_backend.c2604
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/gw_backend.h348
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http-header-glue.c1527
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_auth.c171
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_auth.h52
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_chunk.c236
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_chunk.h14
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_header.c190
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_header.h59
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_kv.c176
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_kv.h69
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.c35
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.h21
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.c76
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.h9
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/joblist.c66
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/joblist.h14
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/keyvalue.c460
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/keyvalue.h31
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/lemon.c4436
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/lempar.c699
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c167
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/log.c216
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/log.h16
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/md5.c343
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/md5.h45
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/meson.build981
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_access.c216
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_accesslog.c1167
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_alias.c219
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_auth.c888
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_authn_file.c734
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_authn_gssapi.c801
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_authn_ldap.c694
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_authn_mysql.c550
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_authn_pam.c185
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_authn_sasl.c284
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_cgi.c1081
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_cml.c340
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_cml.h42
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.c269
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.h16
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_cml_lua.c325
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_compress.c1034
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_deflate.c1243
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_dirlisting.c1216
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_evasive.c208
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_evhost.c363
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_expire.c424
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_extforward.c1645
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_fastcgi.c542
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_flv_streaming.c224
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_geoip.c305
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_indexfile.c235
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_magnet.c1071
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.c129
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.h32
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_mysql_vhost.c380
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_openssl.c2139
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_proxy.c1038
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_redirect.c203
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_rewrite.c340
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_rrdtool.c482
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_scgi.c327
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_secdownload.c571
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_setenv.c314
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_simple_vhost.c287
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_skeleton.c183
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_sockproxy.c180
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi.c1365
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi.h53
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.c330
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.h32
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.c962
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.h12
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.y120
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_staticfile.c221
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_status.c977
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_trigger_b4_dl.c607
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_uploadprogress.c413
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_userdir.c349
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_usertrack.c285
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb.c239
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_dbi.c331
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_ldap.c556
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_mysql.c295
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_pgsql.c272
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_webdav.c2820
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/mod_wstunnel.c1363
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/network.c540
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/network.h17
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/network_write.c738
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/network_write.h9
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/plugin.c544
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/plugin.h96
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/rand.c232
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/rand.h11
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/request.c1201
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/request.h12
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/response.c702
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/response.h57
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/safe_memclear.c47
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/safe_memclear.h7
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/server.c2119
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/server.h7
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/settings.h29
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sock_addr.c689
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sock_addr.h51
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/splaytree.c209
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/splaytree.h25
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/stat_cache.c859
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/stat_cache.h45
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/status_counter.h42
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/stream.c157
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/stream.h16
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sys-crypto.h19
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sys-endian.h71
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sys-mmap.h23
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sys-socket.h45
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/sys-strings.h20
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_array.c104
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_base64.c60
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_buffer.c157
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_burl.c143
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_configfile.c73
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_keyvalue.c124
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_mod_access.c55
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_mod_evhost.c80
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_mod_simple_vhost.c53
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/t/test_request.c490
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/vector.c23
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/vector.h68
180 files changed, 79759 insertions, 0 deletions
diff --git a/data/lighttpd/lighttpd-1.4.53/src/CMakeLists.txt b/data/lighttpd/lighttpd-1.4.53/src/CMakeLists.txt
new file mode 100644
index 000000000..db5f8a5ad
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/CMakeLists.txt
@@ -0,0 +1,1080 @@
+include(CheckCSourceCompiles)
+include(CheckIncludeFiles)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(CheckVariableExists)
+include(CheckTypeSize)
+include(CheckLibraryExists)
+include(CMakeDetermineCCompiler)
+include(FindThreads)
+include(FindPkgConfig)
+
+include(LighttpdMacros)
+
+add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES)
+
+option(WITH_XATTR "with xattr-support for the stat-cache [default: off]")
+option(WITH_MYSQL "with mysql-support for mod_vhostdb_mysql [default: off]")
+option(WITH_PGSQL "with postgres-support for mod_vhostdb_pgsql [default: off]")
+option(WITH_DBI "with dbi-support for mod_vhostdb_dbi [default: off]")
+option(WITH_OPENSSL "with openssl-support [default: off]")
+option(WITH_WOLFSSL "with wolfSSL-support [default: off]")
+option(WITH_PCRE "with regex support [default: on]" ON)
+option(WITH_WEBDAV_PROPS "with property-support for mod_webdav [default: off]")
+option(WITH_WEBDAV_LOCKS "locks in webdav [default: off]")
+option(WITH_BZIP "with bzip2-support for mod_compress [default: off]")
+option(WITH_ZLIB "with deflate-support for mod_compress [default: on]" ON)
+option(WITH_KRB5 "with Kerberos5-support for mod_auth [default: off]")
+option(WITH_LDAP "with LDAP-support for mod_auth mod_vhostdb_ldap [default: off]")
+option(WITH_PAM "with PAM-support for mod_auth [default: off]")
+option(WITH_LUA "with lua 5.1 for mod_magnet [default: off]")
+# option(WITH_VALGRIND "with internal support for valgrind [default: off]")
+option(WITH_FAM "fam/gamin for reducing number of stat() calls [default: off]")
+option(WITH_GDBM "gdbm storage for mod_trigger_b4_dl [default: off]")
+option(WITH_MEMCACHED "memcached storage for mod_trigger_b4_dl [default: off]")
+option(WITH_LIBEV "libev support for fdevent handlers [default: off]")
+option(WITH_LIBUNWIND "with libunwind to print backtraces in asserts [default: off]")
+option(WITH_GEOIP "with GeoIP-support mod_geoip [default: off]")
+option(WITH_SASL "with SASL-support for mod_authn_sasl [default: off]")
+
+if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ option(BUILD_EXTRA_WARNINGS "extra warnings")
+
+ if(BUILD_EXTRA_WARNINGS)
+ set(WARN_CFLAGS "-g -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Wsign-compare -Wnested-externs -Wpointer-arith -D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security")
+ set(WARN_LDFLAGS "-Wl,--as-needed")
+ # -Werror -Wbad-function-cast -Wmissing-prototypes
+ endif()
+endif()
+
+option(BUILD_STATIC "build a static lighttpd with all modules added")
+
+if(BUILD_STATIC)
+ set(LIGHTTPD_STATIC 1)
+elseif(APPLE)
+ set(CMAKE_SHARED_MODULE_PREFIX "")
+else()
+ set(CMAKE_SHARED_LIBRARY_PREFIX "")
+endif()
+
+if(WITH_LIBEV)
+ find_package(LibEV REQUIRED)
+ set(HAVE_LIBEV 1)
+endif()
+
+if(WITH_LIBUNWIND)
+ pkg_check_modules(LIBUNWIND REQUIRED libunwind)
+ set(HAVE_LIBUNWIND 1)
+endif()
+
+if(WITH_WEBDAV_PROPS)
+ set(WITH_XML 1)
+ set(WITH_SQLITE3 1)
+endif()
+
+if(WITH_WEBDAV_LOCKS)
+ set(WITH_UUID 1)
+endif()
+
+check_include_files(sys/devpoll.h HAVE_SYS_DEVPOLL_H)
+check_include_files(sys/epoll.h HAVE_SYS_EPOLL_H)
+check_include_files(sys/event.h HAVE_SYS_EVENT_H)
+check_include_files(sys/mman.h HAVE_SYS_MMAN_H)
+check_include_files(sys/poll.h HAVE_SYS_POLL_H)
+check_include_files(sys/port.h HAVE_SYS_PORT_H)
+check_include_files(sys/prctl.h HAVE_SYS_PRCTL_H)
+check_include_files(sys/resource.h HAVE_SYS_RESOURCE_H)
+check_include_files(sys/sendfile.h HAVE_SYS_SENDFILE_H)
+check_include_files(sys/select.h HAVE_SYS_SELECT_H)
+check_include_files(sys/types.h HAVE_SYS_TYPES_H)
+check_include_files(sys/uio.h HAVE_SYS_UIO_H)
+check_include_files(sys/un.h HAVE_SYS_UN_H)
+check_include_files(sys/wait.h HAVE_SYS_WAIT_H)
+check_include_files(sys/time.h HAVE_SYS_TIME_H)
+check_include_files(unistd.h HAVE_UNISTD_H)
+check_include_files(pthread.h HAVE_PTHREAD_H)
+check_include_files(getopt.h HAVE_GETOPT_H)
+check_include_files(inttypes.h HAVE_INTTYPES_H)
+check_include_files(poll.h HAVE_POLL_H)
+check_include_files(pwd.h HAVE_PWD_H)
+check_include_files(stddef.h HAVE_STDDEF_H)
+check_include_files(stdint.h HAVE_STDINT_H)
+check_include_files(strings.h HAVE_STRINGS_H)
+check_include_files(syslog.h HAVE_SYSLOG_H)
+
+# check for fastcgi lib, for the tests only
+check_include_files(fastcgi.h HAVE_FASTCGI_H)
+check_include_files(fastcgi/fastcgi.h HAVE_FASTCGI_FASTCGI_H)
+
+# will be needed for auth
+check_include_files(crypt.h HAVE_CRYPT_H)
+# check if we need libcrypt for crypt_r()
+check_library_exists(crypt crypt_r "" HAVE_LIBCRYPT_CRYPT_R)
+if(HAVE_LIBCRYPT_CRYPT_R)
+ set(HAVE_CRYPT_R 1)
+ set(HAVE_LIBCRYPT 1)
+else()
+ check_library_exists(crypt crypt "" HAVE_LIBCRYPT)
+endif()
+check_function_exists(crypt_r HAVE_CRYPT_R)
+check_function_exists(crypt HAVE_CRYPT)
+
+check_include_files(sys/inotify.h HAVE_SYS_INOTIFY_H)
+if(HAVE_SYS_INOTIFY_H)
+ check_function_exists(inotify_init HAVE_INOTIFY_INIT)
+endif()
+
+set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
+check_type_size(socklen_t HAVE_SOCKLEN_T)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+
+check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
+set(CMAKE_EXTRA_INCLUDE_FILES sys/random.h)
+check_function_exists(getentropy HAVE_GETENTROPY)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+
+check_include_files(linux/random.h HAVE_LINUX_RANDOM_H)
+set(CMAKE_EXTRA_INCLUDE_FILES linux/random.h)
+check_function_exists(getrandom HAVE_GETRANDOM)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+
+check_type_size(long SIZEOF_LONG)
+check_type_size(off_t SIZEOF_OFF_T)
+
+check_function_exists(arc4random_buf HAVE_ARC4RANDOM_BUF)
+check_function_exists(chroot HAVE_CHROOT)
+check_function_exists(epoll_ctl HAVE_EPOLL_CTL)
+check_function_exists(fork HAVE_FORK)
+check_function_exists(getloadavg HAVE_GETLOADAVG)
+check_function_exists(getrlimit HAVE_GETRLIMIT)
+check_function_exists(getuid HAVE_GETUID)
+check_function_exists(gmtime_r HAVE_GMTIME_R)
+check_function_exists(inet_ntop HAVE_INET_NTOP)
+check_function_exists(jrand48 HAVE_JRAND48)
+check_function_exists(kqueue HAVE_KQUEUE)
+check_function_exists(localtime_r HAVE_LOCALTIME_R)
+check_function_exists(lstat HAVE_LSTAT)
+check_function_exists(madvise HAVE_MADVISE)
+check_function_exists(memcpy HAVE_MEMCPY)
+check_function_exists(memset HAVE_MEMSET)
+check_function_exists(mmap HAVE_MMAP)
+check_function_exists(pathconf HAVE_PATHCONF)
+check_function_exists(pipe2 HAVE_PIPE2)
+check_function_exists(poll HAVE_POLL)
+check_function_exists(port_create HAVE_PORT_CREATE)
+check_function_exists(prctl HAVE_PRCTL)
+check_function_exists(pread HAVE_PREAD)
+check_function_exists(posix_fadvise HAVE_POSIX_FADVISE)
+check_function_exists(select HAVE_SELECT)
+check_function_exists(sendfile HAVE_SENDFILE)
+check_function_exists(send_file HAVE_SEND_FILE)
+check_function_exists(sendfile64 HAVE_SENDFILE64)
+check_function_exists(sendfilev HAVE_SENDFILEV)
+check_function_exists(sigaction HAVE_SIGACTION)
+check_function_exists(signal HAVE_SIGNAL)
+check_function_exists(sigtimedwait HAVE_SIGTIMEDWAIT)
+check_function_exists(srandom HAVE_SRANDOM)
+check_function_exists(strptime HAVE_STRPTIME)
+check_function_exists(syslog HAVE_SYSLOG)
+check_function_exists(writev HAVE_WRITEV)
+check_function_exists(inet_aton HAVE_INET_ATON)
+check_function_exists(issetugid HAVE_ISSETUGID)
+check_function_exists(inet_pton HAVE_INET_PTON)
+check_function_exists(memset_s HAVE_MEMSET_S)
+check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
+check_symbol_exists(clock_gettime "time.h" HAVE_CLOCK_GETTIME)
+if (NOT HAVE_CLOCK_GETTIME)
+ check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME)
+endif()
+check_c_source_compiles("
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+
+ int main() {
+ struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0;
+ return 0;
+ }" HAVE_IPV6)
+check_c_source_compiles("
+ __attribute__((weak)) void __dummy(void *x) { }
+ int main() {
+ void *x;
+ __dummy(x);
+ }
+ " HAVE_WEAK_SYMBOLS)
+check_c_source_compiles("
+ #include <time.h>
+ int main(void) {
+ struct tm t;
+ t.tm_gmtoff = 0;
+ return 0;
+ }
+ " HAVE_STRUCT_TM_GMTOFF)
+
+## refactor me
+macro(XCONFIG _package _include_DIR _link_DIR _link_FLAGS _cflags)
+# reset the variables at the beginning
+ set(${_include_DIR})
+ set(${_link_DIR})
+ set(${_link_FLAGS})
+ set(${_cflags})
+
+ find_program(${_package}CONFIG_EXECUTABLE NAMES ${_package} PATHS /usr/local/bin )
+
+ # if pkg-config has been found
+ if(${_package}CONFIG_EXECUTABLE)
+ set(XCONFIG_EXECUTABLE "${${_package}CONFIG_EXECUTABLE}")
+ message(STATUS "found ${_package}: ${XCONFIG_EXECUTABLE}")
+
+ exec_program(${XCONFIG_EXECUTABLE} ARGS --libs OUTPUT_VARIABLE __link_FLAGS)
+ string(REPLACE "\n" "" ${_link_FLAGS} ${__link_FLAGS})
+ exec_program(${XCONFIG_EXECUTABLE} ARGS --cflags OUTPUT_VARIABLE __cflags)
+ string(REPLACE "\n" "" ${_cflags} ${__cflags})
+ else()
+ message(STATUS "found ${_package}: no")
+ endif()
+endmacro(XCONFIG _package _include_DIR _link_DIR _link_FLAGS _cflags)
+
+if(WITH_XATTR)
+ check_include_files("sys/types.h;attr/attributes.h" HAVE_ATTR_ATTRIBUTES_H)
+ if(HAVE_ATTR_ATTRIBUTES_H)
+ check_library_exists(attr attr_get "" HAVE_XATTR)
+ endif()
+else()
+ unset(HAVE_ATTR_ATTRIBUTES_H)
+ unset(HAVE_XATTR)
+endif()
+
+if(WITH_MYSQL)
+ xconfig(mysql_config MYSQL_INCDIR MYSQL_LIBDIR MYSQL_LDFLAGS MYSQL_CFLAGS)
+
+ set(CMAKE_REQUIRED_INCLUDES /usr/include/mysql)
+ check_include_files(mysql.h HAVE_MYSQL_H)
+ set(CMAKE_REQUIRED_INCLUDES)
+ if(HAVE_MYSQL_H)
+ check_library_exists(mysqlclient mysql_real_connect "" HAVE_MYSQL)
+ endif()
+else()
+ unset(HAVE_MYSQL_H)
+ unset(HAVE_MYSQL)
+endif()
+
+if(WITH_PGSQL)
+ xconfig(pg_config PGSQL_INCDIR PGSQL_LIBDIR PGSQL_LDFLAGS PGSQL_CFLAGS)
+
+ check_include_files(libpq-fe.h HAVE_PGSQL_H)
+ if(HAVE_PGSQL_H)
+ check_library_exists(pq PQsetdbLogin "" HAVE_PGSQL)
+ endif()
+else()
+ unset(HAVE_PGSQL_H)
+ unset(HAVE_PGSQL)
+endif()
+
+if(WITH_DBI)
+ check_include_files(dbi/dbi.h HAVE_DBI_H)
+ if(HAVE_DBI_H)
+ check_library_exists(dbi dbi_conn_connect "" HAVE_DBI)
+ endif()
+else()
+ unset(HAVE_DBI_H)
+ unset(HAVE_DBI)
+endif()
+
+set(CRYPTO_LIBRARY "")
+
+if(WITH_OPENSSL)
+ if(APPLE)
+ set(CMAKE_REQUIRED_INCLUDES /opt/local/include)
+ endif()
+ check_include_files(openssl/ssl.h HAVE_OPENSSL_SSL_H)
+ if(APPLE)
+ set(CMAKE_REQUIRED_INCLUDES)
+ endif()
+ if(HAVE_OPENSSL_SSL_H)
+ check_library_exists(crypto BIO_f_base64 "" HAVE_LIBCRYPTO)
+ if(HAVE_LIBCRYPTO)
+ set(CRYPTO_LIBRARY crypto)
+ check_library_exists(ssl SSL_new "" HAVE_LIBSSL)
+ endif()
+ endif()
+else()
+ unset(HAVE_OPENSSL_SSL_H)
+ unset(HAVE_LIBSSL)
+endif()
+
+if(WITH_WOLFSSL)
+ if(NOT ${WITH_WOLFSSL} EQUAL "")
+ find_path(WOLFSSL_INCLUDE_DIR wolfssl/ssl.h ${WITH_WOLFSSL}/include)
+ elseif(APPLE)
+ find_path(WOLFSSL_INCLUDE_DIR wolfssl/ssl.h /opt/local/include)
+ else()
+ find_path(WOLFSSL_INCLUDE_DIR wolfssl/ssl.h /usr/local/include)
+ endif()
+
+ if(NOT ${WITH_WOLFSSL} EQUAL "")
+ find_library(WOLFSSL_LIBRARY
+ NAMES wolfssl
+ PATHS ${WITH_WOLFSSL}/lib
+ )
+ else()
+ find_library(WOLFSSL_LIBRARY
+ NAMES wolfssl
+ PATHS /usr/local/lib /opt/local/lib /usr/lib
+ )
+ endif()
+
+ if(WOLFSSL_INCLUDE_DIR AND WOLFSSL_LIBRARY)
+ set(CMAKE_REQUIRED_INCLUDES ${WOLFSSL_INCLUDE_DIR})
+ check_include_files(wolfssl/ssl.h HAVE_WOLFSSL_SSL_H)
+
+ check_c_source_compiles("
+ #include <wolfssl/options.h>
+ #if !defined(HAVE_LIGHTY) && !defined(OPENSSL_ALL)
+ #error HAVE_LIGHTY macro not defined
+ #endif
+ int main() { return 0; }
+ " CHECK_HAVE_LIGHTY)
+ if (NOT CHECK_HAVE_LIGHTY)
+ message(FATAL_ERROR "wolfssl must be built with ./configure --enable-lighty")
+ endif()
+ unset(CHECK_HAVE_LIGHTY)
+
+ set(CMAKE_REQUIRED_LIBRARIES ${WOLFSSL_LIBRARY})
+ check_library_exists(${WOLFSSL_LIBRARY} wolfSSL_Init "" HAVE_LIBCRYPTO)
+ if(HAVE_LIBCRYPTO)
+ set(CRYPTO_LIBRARY ${WOLFSSL_LIBRARY})
+ add_definitions(-DHAVE_WOLFSSL_SSL_H)
+ endif()
+ set(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ include_directories(${WOLFSSL_INCLUDE_DIR} ${WOLFSSL_INCLUDE_DIR}/wolfssl)
+ endif()
+ unset(WOLFSSL_LIBRARY)
+ unset(WOLFSSL_INCLUDE_DIR)
+else()
+ unset(HAVE_WOLFSSL_SSL_H)
+endif()
+
+if(WITH_OPENSSL AND WITH_WOLFSSL)
+ message(FATAL_ERROR "lighttpd should not be built with both --with-openssl and --with-wolfssl")
+endif()
+
+if(WITH_PCRE)
+ ## if we have pcre-config, use it
+ xconfig(pcre-config PCRE_INCDIR PCRE_LIBDIR PCRE_LDFLAGS PCRE_CFLAGS)
+ if(PCRE_LDFLAGS OR PCRE_CFLAGS)
+ message(STATUS "found pcre at: LDFLAGS: ${PCRE_LDFLAGS} CFLAGS: ${PCRE_CFLAGS}")
+
+ if(NOT PCRE_CFLAGS STREQUAL "\n")
+ ## if it is empty we'll get newline returned
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PCRE_CFLAGS}")
+ endif()
+
+ set(HAVE_PCRE_H 1)
+ set(HAVE_LIBPCRE 1)
+ else()
+ if(NOT WIN32)
+ check_include_files(pcre.h HAVE_PCRE_H)
+ check_library_exists(pcre pcre_exec "" HAVE_LIBPCRE)
+ set(PCRE_LDFLAGS -lpcre)
+ else()
+ find_path(PCRE_INCLUDE_DIR pcre.h
+ /usr/local/include
+ /usr/include
+ )
+
+ set(PCRE_NAMES pcre)
+ find_library(PCRE_LIBRARY
+ NAMES ${PCRE_NAMES}
+ PATHS /usr/lib /usr/local/lib
+ )
+
+ if(PCRE_INCLUDE_DIR AND PCRE_LIBRARY)
+ set(CMAKE_REQUIRED_INCLUDES ${PCRE_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${PCRE_LIBRARY})
+ check_include_files(pcre.h HAVE_PCRE_H)
+ check_library_exists(pcre pcre_exec "" HAVE_LIBPCRE)
+ set(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ include_directories(${PCRE_INCLUDE_DIR})
+ endif()
+ endif()
+ endif()
+
+ if(NOT HAVE_PCRE_H)
+ message(FATAL_ERROR "pcre.h couldn't be found")
+ endif()
+ if(NOT HAVE_LIBPCRE)
+ message(FATAL_ERROR "libpcre couldn't be found")
+ endif()
+else()
+ unset(HAVE_PCRE_H)
+ unset(HAVE_LIBPCRE)
+endif()
+
+if(WITH_SASL)
+ check_include_files(sasl/sasl.h HAVE_SASL_SASL_H)
+ if(HAVE_SASL_SASL_H)
+ check_library_exists(sasl2 sasl_server_init "" HAVE_SASL)
+ endif()
+else()
+ unset(HAVE_SASL_SASL_H)
+ unset(HAVE_SASL)
+endif()
+
+
+if(WITH_XML)
+ xconfig(xml2-config XML2_INCDIR XML2_LIBDIR XML2_LDFLAGS XML2_CFLAGS)
+ if(XML2_LDFLAGS OR XML2_CFLAGS)
+ message(STATUS "found xml2 at: LDFLAGS: ${XML2_LDFLAGS} CFLAGS: ${XML2_CFLAGS}")
+
+ ## if it is empty we'll get newline returned
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${XML2_CFLAGS}")
+
+ check_include_files(libxml/tree.h HAVE_LIBXML_H)
+
+ set(CMAKE_REQUIRED_FLAGS ${XML2_LDFLAGS})
+ check_library_exists(xml2 xmlParseChunk "" HAVE_LIBXML)
+ set(CMAKE_REQUIRED_FLAGS)
+ else()
+ check_include_files(libxml.h HAVE_LIBXML_H)
+ check_library_exists(xml2 xmlParseChunk "" HAVE_LIBXML)
+ endif()
+
+ if(NOT HAVE_LIBXML_H)
+ message(FATAL_ERROR "libxml/tree.h couldn't be found")
+ endif()
+ if(NOT HAVE_LIBXML)
+ message(FATAL_ERROR "libxml2 couldn't be found")
+ endif()
+else()
+ unset(HAVE_LIBXML_H)
+ unset(HAVE_LIBXML)
+endif()
+
+if(WITH_SQLITE3)
+ check_include_files(sqlite3.h HAVE_SQLITE3_H)
+ check_library_exists(sqlite3 sqlite3_reset "" HAVE_SQLITE3)
+else()
+ unset(HAVE_SQLITE3_H)
+ unset(HAVE_SQLITE3)
+endif()
+
+if(WITH_UUID)
+ check_include_files(uuid/uuid.h HAVE_UUID_UUID_H)
+ check_library_exists(uuid uuid_generate "" NEED_LIBUUID)
+ if(NOT NEED_LIBUUID)
+ check_function_exists(uuid_generate HAVE_LIBUUID)
+ else()
+ set(HAVE_LIBUUID 1)
+ endif()
+else()
+ unset(HAVE_UUID_UUID_H)
+ unset(NEED_LIBUUID)
+ unset(HAVE_LIBUUID)
+endif()
+
+if(WITH_ZLIB)
+ if(NOT WIN32)
+ check_include_files(zlib.h HAVE_ZLIB_H)
+ check_library_exists(z deflate "" HAVE_LIBZ)
+ set(ZLIB_LIBRARY z)
+ else()
+ find_path(ZLIB_INCLUDE_DIR zlib.h
+ /usr/local/include
+ /usr/include
+ )
+
+ set(ZLIB_NAMES z zlib zdll)
+ find_library(ZLIB_LIBRARY
+ NAMES ${ZLIB_NAMES}
+ PATHS /usr/lib /usr/local/lib
+ )
+
+ if(ZLIB_INCLUDE_DIR AND ZLIB_LIBRARY)
+ set(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARY})
+ get_filename_component(ZLIB_NAME ${ZLIB_LIBRARY} NAME)
+ check_include_files(zlib.h HAVE_ZLIB_H)
+ check_library_exists(${ZLIB_NAME} deflate "" HAVE_LIBZ)
+ set(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ include_directories(${ZLIB_INCLUDE_DIR})
+ endif()
+ endif()
+else()
+ unset(HAVE_ZLIB_H)
+ unset(HAVE_LIBZ)
+ unset(ZLIB_INCLUDE_DIR)
+ unset(ZLIB_LIBRARY)
+endif()
+
+if(WITH_BZIP)
+ check_include_files(bzlib.h HAVE_BZLIB_H)
+ check_library_exists(bz2 BZ2_bzCompress "" HAVE_LIBBZ2)
+else()
+ unset(HAVE_BZLIB_H)
+ unset(HAVE_LIBBZ2)
+endif()
+
+if(WITH_LDAP)
+ check_include_files(ldap.h HAVE_LDAP_H)
+ check_library_exists(ldap ldap_bind "" HAVE_LIBLDAP)
+ check_include_files(lber.h HAVE_LBER_H)
+ check_library_exists(lber ber_printf "" HAVE_LIBLBER)
+else()
+ unset(HAVE_LDAP_H)
+ unset(HAVE_LIBLDAP)
+ unset(HAVE_LBER_H)
+ unset(HAVE_LIBLBER)
+endif()
+
+if(WITH_PAM)
+ check_include_files(security/pam_appl.h HAVE_SECURITY_PAM_APPL_H)
+ check_library_exists(pam pam_start "" HAVE_PAM)
+else()
+ unset(HAVE_SECURITY_PAM_APPL_H)
+ unset(HAVE_PAM)
+endif()
+
+if(WITH_LUA)
+ pkg_search_module(LUA REQUIRED lua5.3 lua-5.3 lua5.2 lua-5.2 lua5.1 lua-5.1 lua)
+ message(STATUS "found lua at: INCDIR: ${LUA_INCLUDE_DIRS} LIBDIR: ${LUA_LIBRARY_DIRS} LDFLAGS: ${LUA_LDFLAGS} CFLAGS: ${LUA_CFLAGS}")
+ set(HAVE_LIBLUA 1 "Have liblua")
+ set(HAVE_LUA_H 1 "Have liblua header")
+else()
+ unset(HAVE_LIBLUA)
+ unset(HAVE_LUA_H)
+endif()
+
+if(WITH_FAM)
+ check_include_files(fam.h HAVE_FAM_H)
+ check_library_exists(fam FAMOpen2 "" HAVE_LIBFAM)
+ if(HAVE_LIBFAM)
+ set(CMAKE_REQUIRED_LIBRARIES fam)
+ check_function_exists(FAMNoExists HAVE_FAMNOEXISTS)
+ endif()
+else()
+ unset(HAVE_FAM_H)
+ unset(HAVE_LIBFAM)
+ unset(HAVE_FAMNOEXISTS)
+endif()
+
+if(WITH_GDBM)
+ check_include_files(gdbm.h HAVE_GDBM_H)
+ check_library_exists(gdbm gdbm_open "" HAVE_GDBM)
+else()
+ unset(HAVE_GDBM_H)
+ unset(HAVE_GDBM)
+endif()
+
+if(WITH_MEMCACHED)
+ check_include_files(libmemcached/memcached.h HAVE_LIBMEMCACHED_MEMCACHED_H)
+ check_library_exists(memcached memcached "" HAVE_LIBMEMCACHED)
+ if(HAVE_LIBMEMCACHED_MEMCACHED_H AND HAVE_LIBMEMCACHED)
+ set(USE_MEMCACHED 1)
+ else()
+ message(FATAL_ERROR "didn't find libmemcached")
+ endif()
+endif()
+
+if(WITH_GEOIP)
+ check_library_exists(geoip GeoIP_country_name_by_addr "" HAVE_GEOIP)
+endif()
+
+if(NOT BUILD_STATIC)
+ check_include_files(dlfcn.h HAVE_DLFCN_H)
+else()
+ unset(HAVE_DLFCN_H)
+endif()
+
+if(HAVE_DLFCN_H)
+ check_library_exists(dl dlopen "" HAVE_LIBDL)
+else()
+ unset(HAVE_LIBDL)
+endif()
+
+set(LIGHTTPD_VERSION_ID 10400)
+set(PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
+set(PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
+
+if(NOT SBINDIR)
+ set(SBINDIR "sbin")
+endif()
+
+if(NOT LIGHTTPD_MODULES_DIR)
+ set(LIGHTTPD_MODULES_DIR "lib${LIB_SUFFIX}/lighttpd")
+endif()
+
+if(NOT WIN32)
+ set(LIGHTTPD_LIBRARY_DIR "${CMAKE_INSTALL_PREFIX}/${LIGHTTPD_MODULES_DIR}")
+else()
+ ## We use relative path in windows
+ set(LIGHTTPD_LIBRARY_DIR "lib")
+endif()
+
+## Write out config.h
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+add_definitions(-DHAVE_CONFIG_H)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(COMMON_SRC
+ base64.c buffer.c burl.c log.c
+ http_header.c http_kv.c keyvalue.c chunk.c
+ http_chunk.c stream.c fdevent.c gw_backend.c
+ stat_cache.c plugin.c joblist.c etag.c array.c
+ data_string.c data_array.c
+ data_integer.c algo_sha1.c md5.c
+ vector.c
+ fdevent_select.c fdevent_libev.c
+ fdevent_poll.c fdevent_linux_sysepoll.c
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c
+ fdevent_freebsd_kqueue.c
+ data_config.c
+ crc32.c
+ connections-glue.c
+ configfile-glue.c
+ http-header-glue.c
+ http_auth.c
+ http_vhostdb.c
+ request.c
+ sock_addr.c
+ splaytree.c
+ rand.c
+ safe_memclear.c
+)
+
+if(WIN32)
+ message(STATUS "Adding local getopt implementation.")
+ set(COMMON_SRC ${COMMON_SRC} xgetopt.c)
+endif()
+
+add_executable(lemon lemon.c)
+
+## Build parsers by using lemon...
+lemon_parser(configparser.y)
+lemon_parser(mod_ssi_exprparser.y)
+
+set(L_INSTALL_TARGETS)
+
+add_executable(lighttpd-angel lighttpd-angel.c)
+set(L_INSTALL_TARGETS ${L_INSTALL_TARGETS} lighttpd-angel)
+add_target_properties(lighttpd-angel COMPILE_FLAGS "-DSBIN_DIR=\\\\\"${CMAKE_INSTALL_PREFIX}/${SBINDIR}\\\\\"")
+
+add_executable(lighttpd
+ server.c
+ response.c
+ connections.c
+ inet_ntop_cache.c
+ network.c
+ network_write.c
+ configfile.c
+ configparser.c
+ ${COMMON_SRC}
+)
+set(L_INSTALL_TARGETS ${L_INSTALL_TARGETS} lighttpd)
+
+add_and_install_library(mod_access mod_access.c)
+add_and_install_library(mod_accesslog mod_accesslog.c)
+add_and_install_library(mod_alias mod_alias.c)
+add_and_install_library(mod_auth "mod_auth.c")
+add_and_install_library(mod_authn_file "mod_authn_file.c")
+if(NOT WIN32)
+ add_and_install_library(mod_cgi mod_cgi.c)
+endif()
+add_and_install_library(mod_compress mod_compress.c)
+add_and_install_library(mod_deflate mod_deflate.c)
+add_and_install_library(mod_dirlisting mod_dirlisting.c)
+add_and_install_library(mod_evasive mod_evasive.c)
+add_and_install_library(mod_evhost mod_evhost.c)
+add_and_install_library(mod_expire mod_expire.c)
+add_and_install_library(mod_extforward mod_extforward.c)
+add_and_install_library(mod_fastcgi mod_fastcgi.c)
+add_and_install_library(mod_flv_streaming mod_flv_streaming.c)
+add_and_install_library(mod_indexfile mod_indexfile.c)
+add_and_install_library(mod_proxy mod_proxy.c)
+add_and_install_library(mod_redirect mod_redirect.c)
+add_and_install_library(mod_rewrite mod_rewrite.c)
+add_and_install_library(mod_rrdtool mod_rrdtool.c)
+add_and_install_library(mod_scgi mod_scgi.c)
+add_and_install_library(mod_secdownload mod_secdownload.c)
+add_and_install_library(mod_setenv mod_setenv.c)
+add_and_install_library(mod_simple_vhost mod_simple_vhost.c)
+add_and_install_library(mod_sockproxy mod_sockproxy.c)
+add_and_install_library(mod_ssi "mod_ssi_exprparser.c;mod_ssi_expr.c;mod_ssi.c")
+add_and_install_library(mod_staticfile mod_staticfile.c)
+add_and_install_library(mod_status mod_status.c)
+add_and_install_library(mod_uploadprogress mod_uploadprogress.c)
+add_and_install_library(mod_userdir mod_userdir.c)
+add_and_install_library(mod_usertrack mod_usertrack.c)
+add_and_install_library(mod_vhostdb mod_vhostdb.c)
+add_and_install_library(mod_webdav mod_webdav.c)
+add_and_install_library(mod_wstunnel mod_wstunnel.c)
+
+add_executable(test_array
+ t/test_array.c
+ array.c
+ data_array.c
+ data_integer.c
+ data_string.c
+ buffer.c
+)
+add_test(NAME test_array COMMAND test_array)
+
+add_executable(test_buffer
+ t/test_buffer.c
+ buffer.c
+)
+add_test(NAME test_buffer COMMAND test_buffer)
+
+add_executable(test_burl
+ t/test_burl.c
+ burl.c
+ buffer.c
+ base64.c
+)
+add_test(NAME test_burl COMMAND test_burl)
+
+add_executable(test_base64
+ t/test_base64.c
+ buffer.c
+ base64.c
+)
+add_test(NAME test_base64 COMMAND test_base64)
+
+add_executable(test_configfile
+ t/test_configfile.c
+ buffer.c
+ array.c
+ data_config.c
+ data_integer.c
+ data_string.c
+ http_header.c
+ http_kv.c
+ vector.c
+ log.c
+ sock_addr.c
+)
+add_test(NAME test_configfile COMMAND test_configfile)
+
+add_executable(test_keyvalue
+ t/test_keyvalue.c
+ burl.c
+ buffer.c
+ base64.c
+ array.c
+ data_integer.c
+ data_string.c
+ log.c
+)
+add_test(NAME test_keyvalue COMMAND test_keyvalue)
+
+add_executable(test_mod_access
+ t/test_mod_access.c
+ configfile-glue.c
+ buffer.c
+ array.c
+ data_config.c
+ data_integer.c
+ data_string.c
+ http_header.c
+ http_kv.c
+ vector.c
+ log.c
+ sock_addr.c
+)
+add_test(NAME test_mod_access COMMAND test_mod_access)
+
+add_executable(test_mod_evhost
+ t/test_mod_evhost.c
+ configfile-glue.c
+ buffer.c
+ array.c
+ data_config.c
+ data_integer.c
+ data_string.c
+ http_header.c
+ http_kv.c
+ vector.c
+ log.c
+ sock_addr.c
+)
+add_test(NAME test_mod_evhost COMMAND test_mod_evhost)
+
+add_executable(test_mod_simple_vhost
+ t/test_mod_simple_vhost.c
+ configfile-glue.c
+ buffer.c
+ array.c
+ data_config.c
+ data_integer.c
+ data_string.c
+ http_header.c
+ http_kv.c
+ vector.c
+ log.c
+ sock_addr.c
+)
+add_test(NAME test_mod_simple_vhost COMMAND test_mod_simple_vhost)
+
+add_executable(test_request
+ t/test_request.c
+ request.c
+ buffer.c
+ array.c
+ data_integer.c
+ data_string.c
+ http_header.c
+ http_kv.c
+ log.c
+ sock_addr.c
+)
+add_test(NAME test_request COMMAND test_request)
+
+if(HAVE_PCRE_H)
+ target_link_libraries(lighttpd ${PCRE_LDFLAGS})
+ add_target_properties(lighttpd COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(mod_rewrite ${PCRE_LDFLAGS})
+ add_target_properties(mod_rewrite COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(mod_dirlisting ${PCRE_LDFLAGS})
+ add_target_properties(mod_dirlisting COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(mod_redirect ${PCRE_LDFLAGS})
+ add_target_properties(mod_redirect COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(test_configfile ${PCRE_LDFLAGS})
+ add_target_properties(test_configfile COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(test_keyvalue ${PCRE_LDFLAGS})
+ add_target_properties(test_keyvalue COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(test_mod_access ${PCRE_LDFLAGS})
+ add_target_properties(test_mod_access COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(test_mod_evhost ${PCRE_LDFLAGS})
+ add_target_properties(test_mod_evhost COMPILE_FLAGS ${PCRE_CFLAGS})
+ target_link_libraries(test_mod_simple_vhost ${PCRE_LDFLAGS})
+ add_target_properties(test_mod_simple_vhost COMPILE_FLAGS ${PCRE_CFLAGS})
+endif()
+
+if(WITH_PCRE AND (WITH_MEMCACHED OR WITH_GDBM))
+ add_and_install_library(mod_trigger_b4_dl mod_trigger_b4_dl.c)
+ target_link_libraries(mod_trigger_b4_dl ${PCRE_LDFLAGS})
+ add_target_properties(mod_trigger_b4_dl COMPILE_FLAGS ${PCRE_CFLAGS})
+endif()
+
+if(WITH_LUA)
+ add_and_install_library(mod_magnet "mod_magnet.c;mod_magnet_cache.c")
+ target_link_libraries(mod_magnet ${LUA_LDFLAGS})
+ add_target_properties(mod_magnet COMPILE_FLAGS ${LUA_CFLAGS})
+
+ add_and_install_library(mod_cml "mod_cml.c;mod_cml_lua.c;mod_cml_funcs.c")
+ target_link_libraries(mod_cml ${LUA_LDFLAGS})
+ add_target_properties(mod_cml COMPILE_FLAGS ${LUA_CFLAGS})
+ if(WITH_MEMCACHED)
+ target_link_libraries(mod_cml memcached)
+ endif()
+endif()
+
+if(WITH_GEOIP)
+ add_and_install_library(mod_geoip mod_geoip.c)
+ target_link_libraries(mod_geoip GeoIP)
+endif()
+
+if(HAVE_MYSQL_H AND HAVE_MYSQL)
+ add_and_install_library(mod_mysql_vhost "mod_mysql_vhost.c")
+ target_link_libraries(mod_mysql_vhost mysqlclient)
+ add_and_install_library(mod_vhostdb_mysql "mod_vhostdb_mysql.c")
+ target_link_libraries(mod_vhostdb_mysql mysqlclient)
+ include_directories(/usr/include/mysql)
+
+ add_and_install_library(mod_authn_mysql "mod_authn_mysql.c")
+ set(L_MOD_AUTHN_MYSQL)
+ if(HAVE_LIBCRYPT)
+ set(L_MOD_AUTHN_MYSQL ${L_MOD_AUTHN_MYSQL} crypt)
+ endif()
+ target_link_libraries(mod_authn_mysql ${L_MOD_AUTHN_MYSQL} mysqlclient)
+endif()
+
+if(HAVE_PGSQL_H AND HAVE_PGSQL)
+ add_and_install_library(mod_vhostdb_pgsql "mod_vhostdb_pgsql.c")
+ target_link_libraries(mod_vhostdb_pgsql pq)
+endif()
+
+if(HAVE_DBI_H AND HAVE_DBI)
+ add_and_install_library(mod_vhostdb_dbi "mod_vhostdb_dbi.c")
+ target_link_libraries(mod_vhostdb_dbi dbi)
+endif()
+
+set(L_MOD_WEBDAV)
+if(HAVE_SQLITE3_H)
+ set(L_MOD_WEBDAV ${L_MOD_WEBDAV} sqlite3)
+endif()
+if(HAVE_LIBXML_H)
+ target_link_libraries(mod_webdav ${XML2_LDFLAGS})
+endif()
+if(HAVE_UUID_H)
+ if(NEED_LIBUUID)
+ set(L_MOD_WEBDAV ${L_MOD_WEBDAV} uuid)
+ endif()
+endif()
+
+target_link_libraries(mod_webdav ${L_MOD_WEBDAV})
+
+set(L_MOD_AUTHN_FILE)
+if(HAVE_LIBCRYPT)
+ set(L_MOD_AUTHN_FILE ${L_MOD_AUTHN_FILE} crypt)
+endif()
+target_link_libraries(mod_authn_file ${L_MOD_AUTHN_FILE})
+
+if(WITH_KRB5)
+ check_library_exists(krb5 krb5_init_context "" HAVE_KRB5)
+ add_and_install_library(mod_authn_gssapi "mod_authn_gssapi.c")
+ set(L_MOD_AUTHN_GSSAPI ${L_MOD_AUTHN_GSSAPI} krb5 gssapi_krb5)
+ target_link_libraries(mod_authn_gssapi ${L_MOD_AUTHN_GSSAPI})
+endif()
+
+if(WITH_LDAP)
+ set(L_MOD_AUTHN_LDAP ${L_MOD_AUTHN_LDAP} ldap lber)
+ add_and_install_library(mod_authn_ldap "mod_authn_ldap.c")
+ target_link_libraries(mod_authn_ldap ${L_MOD_AUTHN_LDAP})
+ add_and_install_library(mod_vhostdb_ldap "mod_vhostdb_ldap.c")
+ target_link_libraries(mod_vhostdb_ldap ${L_MOD_AUTHN_LDAP})
+endif()
+
+if(WITH_PAM)
+ add_and_install_library(mod_authn_pam "mod_authn_pam.c")
+ set(L_MOD_AUTHN_PAM ${L_MOD_AUTHN_PAM} pam)
+ target_link_libraries(mod_authn_pam ${L_MOD_AUTHN_PAM})
+endif()
+
+if(WITH_SASL)
+ add_and_install_library(mod_authn_sasl "mod_authn_sasl.c")
+ set(L_MOD_AUTHN_SASL ${L_MOD_AUTHN_SASL} sasl2)
+ target_link_libraries(mod_authn_sasl ${L_MOD_AUTHN_SASL})
+endif()
+
+if(HAVE_ZLIB_H)
+ if(HAVE_BZLIB_H)
+ target_link_libraries(mod_compress ${ZLIB_LIBRARY} bz2)
+ target_link_libraries(mod_deflate ${ZLIB_LIBRARY} bz2)
+ else()
+ target_link_libraries(mod_compress ${ZLIB_LIBRARY})
+ target_link_libraries(mod_deflate ${ZLIB_LIBRARY})
+ endif()
+endif()
+
+if(HAVE_LIBFAM)
+ target_link_libraries(lighttpd fam)
+endif()
+
+if(HAVE_GDBM_H)
+ target_link_libraries(mod_trigger_b4_dl gdbm)
+endif()
+
+if(WITH_MEMCACHED)
+ target_link_libraries(mod_trigger_b4_dl memcached)
+endif()
+
+if(HAVE_XATTR)
+ target_link_libraries(lighttpd attr)
+endif()
+
+if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -g -Wshadow -W -pedantic ${WARN_CFLAGS}")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_WITHDEBINFO} -O2")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WARN_LDFLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WARN_LDFLAGS}")
+endif()
+
+if((NOT APPLE) OR CMAKE_C_COMPILER_ID MATCHES "GNU")
+ add_target_properties(lighttpd LINK_FLAGS "-Wl,-export-dynamic")
+endif()
+
+set_target_properties(lighttpd PROPERTIES CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+if(WIN32)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNVALGRIND")
+ add_target_properties(lighttpd COMPILE_FLAGS "-DLI_DECLARE_EXPORTS")
+ target_link_libraries(lighttpd ws2_32)
+ target_link_libraries(mod_proxy ws2_32)
+ target_link_libraries(mod_fcgi ws2_32)
+ target_link_libraries(mod_scgi ws2_32)
+ target_link_libraries(mod_ssi ws2_32)
+
+ if(MINGW)
+ target_link_libraries(lighttpd msvcr70)
+ add_target_properties(lighttpd LINK_FLAGS "-Wl,-subsystem,console")
+ endif()
+endif()
+
+if(NOT BUILD_STATIC)
+ if(HAVE_LIBDL)
+ target_link_libraries(lighttpd dl)
+ endif()
+endif()
+
+if(NOT ${CRYPTO_LIBRARY} EQUAL "")
+ if(NOT WITH_WOLFSSL)
+ target_link_libraries(lighttpd ssl)
+ endif()
+ target_link_libraries(lighttpd ${CRYPTO_LIBRARY})
+ add_and_install_library(mod_openssl "mod_openssl.c")
+ if(NOT WITH_WOLFSSL)
+ set(L_MOD_OPENSSL ${L_MOD_OPENSSL} ssl)
+ endif()
+ set(L_MOD_OPENSSL ${L_MOD_OPENSSL} ${CRYPTO_LIBRARY})
+ target_link_libraries(mod_openssl ${L_MOD_OPENSSL})
+ set(L_MOD_AUTHN_FILE ${L_MOD_AUTHN_FILE} ${CRYPTO_LIBRARY})
+ target_link_libraries(mod_authn_file ${L_MOD_AUTHN_FILE})
+ target_link_libraries(mod_secdownload ${CRYPTO_LIBRARY})
+ target_link_libraries(mod_wstunnel ${CRYPTO_LIBRARY})
+endif()
+
+if(WITH_LIBEV)
+ target_link_libraries(lighttpd ${LIBEV_LDFLAGS})
+ add_target_properties(lighttpd COMPILE_FLAGS ${LIBEV_CFLAGS})
+endif()
+
+if(WITH_LIBUNWIND)
+ target_link_libraries(lighttpd ${LIBUNWIND_LDFLAGS})
+ add_target_properties(lighttpd COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
+
+ target_link_libraries(test_array ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_array COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_buffer ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_buffer COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_burl ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_burl COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_base64 ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_base64 COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_configfile ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_configfile COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_keyvalue ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_keyvalue COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_mod_access ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_mod_access COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_mod_evhost ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_mod_evhost COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_mod_simple_vhost ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_mod_simple_vhost COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS})
+ target_link_libraries(test_request ${LIBUNWIND_LDFLAGS})
+ add_target_properties(test_request COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
+endif()
+
+if(NOT WIN32)
+install(TARGETS ${L_INSTALL_TARGETS}
+ RUNTIME DESTINATION ${SBINDIR}
+ LIBRARY DESTINATION ${LIGHTTPD_MODULES_DIR}
+ ARCHIVE DESTINATION ${LIGHTTPD_MODULES_DIR}/static)
+else()
+## HACK to make win32 to install our libraries in desired directory..
+install(TARGETS lighttpd
+ RUNTIME DESTINATION ${SBINDIR}
+ ARCHIVE DESTINATION lib/static)
+list(REMOVE_ITEM L_INSTALL_TARGETS lighttpd)
+install(TARGETS ${L_INSTALL_TARGETS}
+ RUNTIME DESTINATION ${SBINDIR}/lib
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib/static)
+endif()
diff --git a/data/lighttpd/lighttpd-1.4.53/src/Makefile.am b/data/lighttpd/lighttpd-1.4.53/src/Makefile.am
new file mode 100644
index 000000000..80feb0af5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/Makefile.am
@@ -0,0 +1,586 @@
+AM_CFLAGS = $(FAM_CFLAGS) $(LIBUNWIND_CFLAGS)
+
+noinst_PROGRAMS=\
+ t/test_array \
+ t/test_buffer \
+ t/test_burl \
+ t/test_base64 \
+ t/test_configfile \
+ t/test_keyvalue \
+ t/test_mod_access \
+ t/test_mod_evhost \
+ t/test_mod_simple_vhost \
+ t/test_request
+
+sbin_PROGRAMS=lighttpd lighttpd-angel
+LEMON=$(top_builddir)/src/lemon$(BUILD_EXEEXT)
+
+TESTS=\
+ t/test_array$(EXEEXT) \
+ t/test_buffer$(EXEEXT) \
+ t/test_burl$(EXEEXT) \
+ t/test_base64$(EXEEXT) \
+ t/test_configfile$(EXEEXT) \
+ t/test_keyvalue$(EXEEXT) \
+ t/test_mod_access$(EXEEXT) \
+ t/test_mod_evhost$(EXEEXT) \
+ t/test_mod_simple_vhost$(EXEEXT) \
+ t/test_request$(EXEEXT)
+
+lemon$(BUILD_EXEEXT): lemon.c
+ $(AM_V_CC)$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $(srcdir)/lemon.c
+
+lighttpd_angel_SOURCES=lighttpd-angel.c
+
+.PHONY: versionstamp parsers
+
+versionstamp:
+ @test -f versionstamp.h || touch versionstamp.h; \
+ REVISION=""; \
+ if test -d "$(top_srcdir)/.svn" -a -x "`which svnversion`"; then \
+ REVISION="$$(LANG= LC_ALL=C svnversion "$(top_srcdir)" 2>/dev/null || echo exported)"; \
+ if test "$$REVISION" = "exported"; then \
+ REVISION=""; \
+ fi; \
+ fi; \
+ if test -z "$$REVISION" -a -d "$(top_srcdir)/.git" -a -x "`which git`"; then \
+ REVISION="$$(cd "$(top_srcdir)"; LANG= LC_ALL=C git describe --always 2>/dev/null || echo)"; \
+ fi; \
+ if test -n "$$REVISION"; then \
+ echo "#define REPO_VERSION \"-devel-$$REVISION\"" > versionstamp.h.tmp; \
+ else \
+ echo "#define REPO_VERSION \"\"" > versionstamp.h.tmp; \
+ fi; \
+ if ! diff versionstamp.h.tmp versionstamp.h >/dev/null 2>/dev/null; then \
+ mv versionstamp.h.tmp versionstamp.h; \
+ else \
+ rm versionstamp.h.tmp; \
+ fi
+
+configparser.h: configparser.c
+configparser.c: $(srcdir)/configparser.y $(srcdir)/lempar.c lemon$(BUILD_EXEEXT)
+ rm -f configparser.h
+ $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
+
+mod_ssi_exprparser.h: mod_ssi_exprparser.c
+mod_ssi_exprparser.c: $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c lemon$(BUILD_EXEEXT)
+ rm -f mod_ssi_exprparser.h
+ $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
+
+parsers: configparser.c mod_ssi_exprparser.c
+
+BUILT_SOURCES = parsers versionstamp
+MAINTAINERCLEANFILES = configparser.c configparser.h mod_ssi_exprparser.c mod_ssi_exprparser.h
+CLEANFILES = versionstamp.h versionstamp.h.tmp lemon$(BUILD_EXEEXT)
+
+common_src=base64.c buffer.c burl.c log.c \
+ http_header.c http_kv.c keyvalue.c chunk.c \
+ http_chunk.c stream.c fdevent.c gw_backend.c \
+ stat_cache.c plugin.c joblist.c etag.c array.c \
+ data_string.c data_array.c \
+ data_integer.c algo_sha1.c md5.c \
+ vector.c \
+ fdevent_select.c fdevent_libev.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
+ data_config.c \
+ crc32.c \
+ connections-glue.c \
+ configfile-glue.c \
+ http-header-glue.c \
+ http_auth.c \
+ http_vhostdb.c \
+ rand.c \
+ request.c \
+ sock_addr.c \
+ splaytree.c \
+ safe_memclear.c
+
+src = server.c response.c connections.c \
+ inet_ntop_cache.c \
+ network.c \
+ network_write.c \
+ configfile.c configparser.c
+
+lib_LTLIBRARIES =
+
+if NO_RDYNAMIC
+# if the linker doesn't allow referencing symbols of the binary
+# we have to put everything into a shared-lib and link it into
+# everything
+common_ldflags = -avoid-version -no-undefined
+lib_LTLIBRARIES += liblightcomp.la
+liblightcomp_la_SOURCES=$(common_src)
+liblightcomp_la_CFLAGS=$(AM_CFLAGS) $(LIBEV_CFLAGS)
+liblightcomp_la_LDFLAGS = $(common_ldflags)
+liblightcomp_la_LIBADD = $(PCRE_LIB) $(CRYPTO_LIB) $(FAM_LIBS) $(LIBEV_LIBS) $(ATTR_LIB)
+common_libadd = liblightcomp.la
+else
+src += $(common_src)
+common_ldflags = -avoid-version
+common_libadd =
+endif
+common_module_ldflags = -module -export-dynamic $(common_ldflags)
+
+lib_LTLIBRARIES += mod_flv_streaming.la
+mod_flv_streaming_la_SOURCES = mod_flv_streaming.c
+mod_flv_streaming_la_LDFLAGS = $(common_module_ldflags)
+mod_flv_streaming_la_LIBADD = $(common_libadd)
+
+if BUILD_WITH_GEOIP
+lib_LTLIBRARIES += mod_geoip.la
+mod_geoip_la_SOURCES = mod_geoip.c
+mod_geoip_la_LDFLAGS = $(common_module_ldflags)
+mod_geoip_la_LIBADD = $(common_libadd) $(GEOIP_LIB)
+endif
+
+lib_LTLIBRARIES += mod_evasive.la
+mod_evasive_la_SOURCES = mod_evasive.c
+mod_evasive_la_LDFLAGS = $(common_module_ldflags)
+mod_evasive_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_webdav.la
+mod_webdav_la_SOURCES = mod_webdav.c
+mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
+mod_webdav_la_LDFLAGS = $(common_module_ldflags)
+mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS)
+
+if BUILD_WITH_LUA
+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 = $(common_module_ldflags)
+mod_magnet_la_LIBADD = $(common_libadd) $(LUA_LIBS) -lm
+endif
+
+if BUILD_WITH_LUA
+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)
+mod_cml_la_LDFLAGS = $(common_module_ldflags)
+mod_cml_la_LIBADD = $(MEMCACHED_LIB) $(common_libadd) $(LUA_LIBS) -lm
+endif
+
+if BUILD_MOD_TRIGGER_B4_DL
+lib_LTLIBRARIES += mod_trigger_b4_dl.la
+mod_trigger_b4_dl_la_SOURCES = mod_trigger_b4_dl.c
+mod_trigger_b4_dl_la_LDFLAGS = $(common_module_ldflags)
+mod_trigger_b4_dl_la_LIBADD = $(GDBM_LIB) $(MEMCACHED_LIB) $(PCRE_LIB) $(common_libadd)
+endif
+
+lib_LTLIBRARIES += mod_vhostdb.la
+mod_vhostdb_la_SOURCES = mod_vhostdb.c
+mod_vhostdb_la_LDFLAGS = $(common_module_ldflags)
+mod_vhostdb_la_LIBADD = $(common_libadd)
+
+if BUILD_WITH_LDAP
+lib_LTLIBRARIES += mod_vhostdb_ldap.la
+mod_vhostdb_ldap_la_SOURCES = mod_vhostdb_ldap.c
+mod_vhostdb_ldap_la_LDFLAGS = $(common_module_ldflags)
+mod_vhostdb_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
+endif
+
+if BUILD_WITH_MYSQL
+lib_LTLIBRARIES += mod_mysql_vhost.la
+mod_mysql_vhost_la_SOURCES = mod_mysql_vhost.c
+mod_mysql_vhost_la_LDFLAGS = $(common_module_ldflags)
+mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
+mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_CFLAGS)
+endif
+
+if BUILD_WITH_MYSQL
+lib_LTLIBRARIES += mod_vhostdb_mysql.la
+mod_vhostdb_mysql_la_SOURCES = mod_vhostdb_mysql.c
+mod_vhostdb_mysql_la_LDFLAGS = $(common_module_ldflags)
+mod_vhostdb_mysql_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
+mod_vhostdb_mysql_la_CPPFLAGS = $(MYSQL_CFLAGS)
+endif
+
+if BUILD_WITH_PGSQL
+lib_LTLIBRARIES += mod_vhostdb_pgsql.la
+mod_vhostdb_pgsql_la_SOURCES = mod_vhostdb_pgsql.c
+mod_vhostdb_pgsql_la_LDFLAGS = $(common_module_ldflags)
+mod_vhostdb_pgsql_la_LIBADD = $(PGSQL_LIBS) $(common_libadd)
+mod_vhostdb_pgsql_la_CPPFLAGS = $(PGSQL_INCLUDE)
+endif
+
+if BUILD_WITH_DBI
+lib_LTLIBRARIES += mod_vhostdb_dbi.la
+mod_vhostdb_dbi_la_SOURCES = mod_vhostdb_dbi.c
+mod_vhostdb_dbi_la_LDFLAGS = $(common_module_ldflags)
+mod_vhostdb_dbi_la_LIBADD = $(DBI_LIBS) $(common_libadd)
+mod_vhostdb_dbi_la_CPPFLAGS = $(DBI_CFLAGS)
+endif
+
+lib_LTLIBRARIES += mod_cgi.la
+mod_cgi_la_SOURCES = mod_cgi.c
+mod_cgi_la_LDFLAGS = $(common_module_ldflags)
+mod_cgi_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_scgi.la
+mod_scgi_la_SOURCES = mod_scgi.c
+mod_scgi_la_LDFLAGS = $(common_module_ldflags)
+mod_scgi_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_staticfile.la
+mod_staticfile_la_SOURCES = mod_staticfile.c
+mod_staticfile_la_LDFLAGS = $(common_module_ldflags)
+mod_staticfile_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_dirlisting.la
+mod_dirlisting_la_SOURCES = mod_dirlisting.c
+mod_dirlisting_la_LDFLAGS = $(common_module_ldflags)
+mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB)
+
+lib_LTLIBRARIES += mod_indexfile.la
+mod_indexfile_la_SOURCES = mod_indexfile.c
+mod_indexfile_la_LDFLAGS = $(common_module_ldflags)
+mod_indexfile_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_setenv.la
+mod_setenv_la_SOURCES = mod_setenv.c
+mod_setenv_la_LDFLAGS = $(common_module_ldflags)
+mod_setenv_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_alias.la
+mod_alias_la_SOURCES = mod_alias.c
+mod_alias_la_LDFLAGS = $(common_module_ldflags)
+mod_alias_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_userdir.la
+mod_userdir_la_SOURCES = mod_userdir.c
+mod_userdir_la_LDFLAGS = $(common_module_ldflags)
+mod_userdir_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_rrdtool.la
+mod_rrdtool_la_SOURCES = mod_rrdtool.c
+mod_rrdtool_la_LDFLAGS = $(common_module_ldflags)
+mod_rrdtool_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_usertrack.la
+mod_usertrack_la_SOURCES = mod_usertrack.c
+mod_usertrack_la_LDFLAGS = $(common_module_ldflags)
+mod_usertrack_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_proxy.la
+mod_proxy_la_SOURCES = mod_proxy.c
+mod_proxy_la_LDFLAGS = $(common_module_ldflags)
+mod_proxy_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_sockproxy.la
+mod_sockproxy_la_SOURCES = mod_sockproxy.c
+mod_sockproxy_la_LDFLAGS = $(common_module_ldflags)
+mod_sockproxy_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_ssi.la
+mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
+mod_ssi_la_LDFLAGS = $(common_module_ldflags)
+mod_ssi_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_secdownload.la
+mod_secdownload_la_SOURCES = mod_secdownload.c
+mod_secdownload_la_LDFLAGS = $(common_module_ldflags)
+mod_secdownload_la_LIBADD = $(common_libadd) $(CRYPTO_LIB)
+
+#lib_LTLIBRARIES += mod_httptls.la
+#mod_httptls_la_SOURCES = mod_httptls.c
+#mod_httptls_la_LDFLAGS = $(common_module_ldflags)
+#mod_httptls_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_expire.la
+mod_expire_la_SOURCES = mod_expire.c
+mod_expire_la_LDFLAGS = $(common_module_ldflags)
+mod_expire_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_evhost.la
+mod_evhost_la_SOURCES = mod_evhost.c
+mod_evhost_la_LDFLAGS = $(common_module_ldflags)
+mod_evhost_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_simple_vhost.la
+mod_simple_vhost_la_SOURCES = mod_simple_vhost.c
+mod_simple_vhost_la_LDFLAGS = $(common_module_ldflags)
+mod_simple_vhost_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_fastcgi.la
+mod_fastcgi_la_SOURCES = mod_fastcgi.c
+mod_fastcgi_la_LDFLAGS = $(common_module_ldflags)
+mod_fastcgi_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_extforward.la
+mod_extforward_la_SOURCES = mod_extforward.c
+mod_extforward_la_LDFLAGS = $(common_module_ldflags)
+mod_extforward_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_access.la
+mod_access_la_SOURCES = mod_access.c
+mod_access_la_LDFLAGS = $(common_module_ldflags)
+mod_access_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_compress.la
+mod_compress_la_SOURCES = mod_compress.c
+mod_compress_la_LDFLAGS = $(common_module_ldflags)
+mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
+
+lib_LTLIBRARIES += mod_deflate.la
+mod_deflate_la_SOURCES = mod_deflate.c
+mod_deflate_la_LDFLAGS = $(common_module_ldflags)
+mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
+
+lib_LTLIBRARIES += mod_auth.la
+mod_auth_la_SOURCES = mod_auth.c
+mod_auth_la_LDFLAGS = $(common_module_ldflags)
+mod_auth_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_authn_file.la
+mod_authn_file_la_SOURCES = mod_authn_file.c
+mod_authn_file_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_file_la_LIBADD = $(CRYPT_LIB) $(CRYPTO_LIB) $(common_libadd)
+
+if BUILD_WITH_KRB5
+lib_LTLIBRARIES += mod_authn_gssapi.la
+mod_authn_gssapi_la_SOURCES = mod_authn_gssapi.c
+mod_authn_gssapi_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_gssapi_la_LIBADD = $(KRB5_LIB) $(common_libadd)
+endif
+
+if BUILD_WITH_LDAP
+lib_LTLIBRARIES += mod_authn_ldap.la
+mod_authn_ldap_la_SOURCES = mod_authn_ldap.c
+mod_authn_ldap_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
+endif
+
+if BUILD_WITH_PAM
+lib_LTLIBRARIES += mod_authn_pam.la
+mod_authn_pam_la_SOURCES = mod_authn_pam.c
+mod_authn_pam_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_pam_la_LIBADD = $(PAM_LIB) $(common_libadd)
+endif
+
+if BUILD_WITH_MYSQL
+lib_LTLIBRARIES += mod_authn_mysql.la
+mod_authn_mysql_la_SOURCES = mod_authn_mysql.c
+mod_authn_mysql_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_mysql_la_LIBADD = $(CRYPT_LIB) $(MYSQL_LIBS) $(common_libadd)
+mod_authn_mysql_la_CPPFLAGS = $(MYSQL_CFLAGS)
+endif
+
+if BUILD_WITH_SASL
+lib_LTLIBRARIES += mod_authn_sasl.la
+mod_authn_sasl_la_SOURCES = mod_authn_sasl.c
+mod_authn_sasl_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_sasl_la_LIBADD = $(SASL_LIBS) $(common_libadd)
+mod_authn_sasl_la_CPPFLAGS = $(SASL_CFLAGS)
+endif
+
+if BUILD_WITH_OPENSSL
+lib_LTLIBRARIES += mod_openssl.la
+mod_openssl_la_SOURCES = mod_openssl.c
+mod_openssl_la_LDFLAGS = $(common_module_ldflags)
+mod_openssl_la_LIBADD = $(SSL_LIB) $(common_libadd)
+endif
+
+lib_LTLIBRARIES += mod_rewrite.la
+mod_rewrite_la_SOURCES = mod_rewrite.c
+mod_rewrite_la_LDFLAGS = $(common_module_ldflags)
+mod_rewrite_la_LIBADD = $(PCRE_LIB) $(common_libadd)
+
+lib_LTLIBRARIES += mod_redirect.la
+mod_redirect_la_SOURCES = mod_redirect.c
+mod_redirect_la_LDFLAGS = $(common_module_ldflags)
+mod_redirect_la_LIBADD = $(PCRE_LIB) $(common_libadd)
+
+lib_LTLIBRARIES += mod_status.la
+mod_status_la_SOURCES = mod_status.c
+mod_status_la_LDFLAGS = $(common_module_ldflags)
+mod_status_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_accesslog.la
+mod_accesslog_la_SOURCES = mod_accesslog.c
+mod_accesslog_la_LDFLAGS = $(common_module_ldflags)
+mod_accesslog_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_uploadprogress.la
+mod_uploadprogress_la_SOURCES = mod_uploadprogress.c
+mod_uploadprogress_la_LDFLAGS = $(common_module_ldflags)
+mod_uploadprogress_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_wstunnel.la
+mod_wstunnel_la_SOURCES = mod_wstunnel.c
+mod_wstunnel_la_LDFLAGS = $(common_module_ldflags)
+mod_wstunnel_la_LIBADD = $(common_libadd) $(CRYPTO_LIB)
+
+
+hdr = server.h base64.h buffer.h burl.h network.h log.h http_kv.h keyvalue.h \
+ response.h request.h fastcgi.h chunk.h \
+ first.h settings.h http_chunk.h \
+ algo_sha1.h md5.h http_auth.h http_header.h http_vhostdb.h stream.h \
+ fdevent.h gw_backend.h connections.h base.h base_decls.h stat_cache.h \
+ plugin.h \
+ etag.h joblist.h array.h vector.h crc32.h \
+ fdevent_impl.h network_write.h configfile.h \
+ mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
+ configparser.h mod_ssi_exprparser.h \
+ rand.h \
+ sys-crypto.h sys-endian.h sys-mmap.h sys-socket.h sys-strings.h \
+ mod_cml.h mod_cml_funcs.h \
+ safe_memclear.h sock_addr.h splaytree.h status_counter.h \
+ mod_magnet_cache.h
+
+
+DEFS= @DEFS@ -DHAVE_VERSIONSTAMP_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
+
+
+if LIGHTTPD_STATIC
+
+## static lighttpd server (used in conjunction with -DLIGHTTPD_STATIC)
+## (order is not important)
+lighttpd_SOURCES = \
+ $(src) \
+ mod_access.c \
+ mod_accesslog.c \
+ mod_alias.c \
+ mod_auth.c \
+ mod_authn_file.c \
+ mod_cgi.c \
+ mod_compress.c \
+ mod_deflate.c \
+ mod_dirlisting.c \
+ mod_evasive.c \
+ mod_expire.c \
+ mod_extforward.c \
+ mod_fastcgi.c \
+ mod_flv_streaming.c \
+ mod_indexfile.c \
+ mod_proxy.c \
+ mod_redirect.c \
+ mod_rewrite.c \
+ mod_rrdtool.c \
+ mod_scgi.c \
+ mod_secdownload.c \
+ mod_setenv.c \
+ mod_simple_vhost.c \
+ mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c \
+ mod_staticfile.c \
+ mod_status.c \
+ mod_uploadprogress.c \
+ mod_userdir.c \
+ mod_usertrack.c \
+ mod_vhostdb.c \
+ mod_webdav.c
+lighttpd_CPPFLAGS = \
+ -DLIGHTTPD_STATIC \
+ $(XML_CFLAGS) $(SQLITE_CFLAGS) \
+ $(FAM_CFLAGS) $(LIBEV_CFLAGS) $(LIBUNWIND_CFLAGS)
+lighttpd_LDADD = \
+ $(common_libadd) \
+ $(CRYPT_LIB) $(CRYPTO_LIB) \
+ $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS) \
+ $(PCRE_LIB) $(Z_LIB) $(BZ_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) \
+ $(FAM_LIBS) $(LIBEV_LIBS) $(LIBUNWIND_LIBS)
+lighttpd_LDFLAGS = -export-dynamic
+
+if BUILD_WITH_GEOIP
+lighttpd_SOURCES += mod_geoip.c
+lighttpd_LDADD += $(GEOIP_LIB)
+endif
+if BUILD_WITH_LUA
+lighttpd_SOURCES += mod_cml.c mod_cml_lua.c mod_cml_funcs.c \
+ mod_magnet.c mod_magnet_cache.c
+lighttpd_CPPFLAGS += $(LUA_CFLAGS)
+lighttpd_LDADD += $(LUA_LIBS) -lm
+endif
+if BUILD_WITH_KRB5
+lighttpd_SOURCES += mod_authn_gssapi.c
+lighttpd_LDADD += $(KRB5_LIB)
+endif
+if BUILD_WITH_LDAP
+lighttpd_SOURCES += mod_authn_ldap.c mod_vhostdb_ldap.c
+lighttpd_LDADD += $(LDAP_LIB) $(LBER_LIB)
+endif
+if BUILD_WITH_PAM
+lighttpd_SOURCES += mod_authn_pam.c
+lighttpd_LDADD += $(PAM_LIB)
+endif
+if BUILD_WITH_MYSQL
+lighttpd_SOURCES += mod_authn_mysql.c mod_mysql_vhost.c mod_vhostdb_mysql.c
+lighttpd_CPPFLAGS += $(MYSQL_CFLAGS)
+lighttpd_LDADD += $(MYSQL_LIBS)
+endif
+if BUILD_WITH_PGSQL
+lighttpd_SOURCES += mod_vhostdb_pgsql.c
+lighttpd_CPPFLAGS += $(PGSQL_INCLUDE)
+lighttpd_LDADD += $(PGSQL_LIBS)
+endif
+if BUILD_WITH_DBI
+lighttpd_SOURCES += mod_vhostdb_dbi.c
+lighttpd_CPPFLAGS += $(DBI_CFLAGS)
+lighttpd_LDADD += $(DBI_LIBS)
+endif
+if BUILD_WITH_OPENSSL
+lighttpd_SOURCES += mod_openssl.c
+lighttpd_LDADD += $(SSL_LIB)
+endif
+if BUILD_WITH_MEMCACHED
+lighttpd_CPPFLAGS += $(MEMCACHED_CFLAGS)
+lighttpd_LDADD += $(MEMCACHED_LIB)
+endif
+if BUILD_WITH_GDBM
+lighttpd_LDADD += $(GDBM_LIB)
+endif
+if BUILD_MOD_TRIGGER_B4_DL
+lighttpd_SOURCES += mod_trigger_b4_dl.c
+endif
+
+else
+
+## default lighttpd server
+lighttpd_SOURCES = $(src)
+lighttpd_CPPFLAGS = $(FAM_CFLAGS) $(LIBEV_CFLAGS)
+lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(CRYPTO_LIB) $(FAM_LIBS) $(LIBEV_LIBS) $(LIBUNWIND_LIBS)
+lighttpd_LDFLAGS = -export-dynamic
+
+endif
+
+t_test_array_SOURCES = t/test_array.c array.c data_array.c data_integer.c data_string.c buffer.c
+t_test_array_LDADD = $(LIBUNWIND_LIBS)
+
+t_test_buffer_SOURCES = t/test_buffer.c buffer.c
+t_test_buffer_LDADD = $(LIBUNWIND_LIBS)
+
+t_test_base64_SOURCES = t/test_base64.c base64.c buffer.c
+t_test_base64_LDADD = $(LIBUNWIND_LIBS)
+
+t_test_burl_SOURCES = t/test_burl.c burl.c buffer.c base64.c
+t_test_burl_LDADD = $(LIBUNWIND_LIBS)
+
+t_test_configfile_SOURCES = t/test_configfile.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_configfile_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+
+t_test_keyvalue_SOURCES = t/test_keyvalue.c burl.c buffer.c base64.c array.c data_integer.c data_string.c log.c
+t_test_keyvalue_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+
+t_test_mod_access_SOURCES = t/test_mod_access.c configfile-glue.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_mod_access_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+
+t_test_mod_evhost_SOURCES = t/test_mod_evhost.c configfile-glue.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_mod_evhost_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+
+t_test_mod_simple_vhost_SOURCES = t/test_mod_simple_vhost.c configfile-glue.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_mod_simple_vhost_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+
+t_test_request_SOURCES = t/test_request.c request.c buffer.c array.c data_integer.c data_string.c http_header.c http_kv.c log.c sock_addr.c
+t_test_request_LDADD = $(LIBUNWIND_LIBS)
+
+noinst_HEADERS = $(hdr)
+EXTRA_DIST = \
+ mod_skeleton.c \
+ configparser.y \
+ mod_ssi_exprparser.y \
+ lemon.c \
+ lempar.c \
+ SConscript \
+ CMakeLists.txt config.h.cmake \
+ meson.build
diff --git a/data/lighttpd/lighttpd-1.4.53/src/Makefile.in b/data/lighttpd/lighttpd-1.4.53/src/Makefile.in
new file mode 100644
index 000000000..9e36531e6
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/Makefile.in
@@ -0,0 +1,4913 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = t/test_array$(EXEEXT) t/test_buffer$(EXEEXT) \
+ t/test_burl$(EXEEXT) t/test_base64$(EXEEXT) \
+ t/test_configfile$(EXEEXT) t/test_keyvalue$(EXEEXT) \
+ t/test_mod_access$(EXEEXT) t/test_mod_evhost$(EXEEXT) \
+ t/test_mod_simple_vhost$(EXEEXT) t/test_request$(EXEEXT)
+sbin_PROGRAMS = lighttpd$(EXEEXT) lighttpd-angel$(EXEEXT)
+@NO_RDYNAMIC_TRUE@am__append_1 = liblightcomp.la
+@NO_RDYNAMIC_FALSE@am__append_2 = $(common_src)
+@BUILD_WITH_GEOIP_TRUE@am__append_3 = mod_geoip.la
+@BUILD_WITH_LUA_TRUE@am__append_4 = mod_magnet.la mod_cml.la
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@am__append_5 = mod_trigger_b4_dl.la
+@BUILD_WITH_LDAP_TRUE@am__append_6 = mod_vhostdb_ldap.la
+@BUILD_WITH_MYSQL_TRUE@am__append_7 = mod_mysql_vhost.la \
+@BUILD_WITH_MYSQL_TRUE@ mod_vhostdb_mysql.la
+@BUILD_WITH_PGSQL_TRUE@am__append_8 = mod_vhostdb_pgsql.la
+@BUILD_WITH_DBI_TRUE@am__append_9 = mod_vhostdb_dbi.la
+@BUILD_WITH_KRB5_TRUE@am__append_10 = mod_authn_gssapi.la
+@BUILD_WITH_LDAP_TRUE@am__append_11 = mod_authn_ldap.la
+@BUILD_WITH_PAM_TRUE@am__append_12 = mod_authn_pam.la
+@BUILD_WITH_MYSQL_TRUE@am__append_13 = mod_authn_mysql.la
+@BUILD_WITH_SASL_TRUE@am__append_14 = mod_authn_sasl.la
+@BUILD_WITH_OPENSSL_TRUE@am__append_15 = mod_openssl.la
+@BUILD_WITH_GEOIP_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_16 = mod_geoip.c
+@BUILD_WITH_GEOIP_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_17 = $(GEOIP_LIB)
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_18 = mod_cml.c mod_cml_lua.c mod_cml_funcs.c \
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@ mod_magnet.c mod_magnet_cache.c
+
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_19 = $(LUA_CFLAGS)
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_20 = $(LUA_LIBS) -lm
+@BUILD_WITH_KRB5_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_21 = mod_authn_gssapi.c
+@BUILD_WITH_KRB5_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_22 = $(KRB5_LIB)
+@BUILD_WITH_LDAP_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_23 = mod_authn_ldap.c mod_vhostdb_ldap.c
+@BUILD_WITH_LDAP_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_24 = $(LDAP_LIB) $(LBER_LIB)
+@BUILD_WITH_PAM_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_25 = mod_authn_pam.c
+@BUILD_WITH_PAM_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_26 = $(PAM_LIB)
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_27 = mod_authn_mysql.c mod_mysql_vhost.c mod_vhostdb_mysql.c
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_28 = $(MYSQL_CFLAGS)
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_29 = $(MYSQL_LIBS)
+@BUILD_WITH_PGSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_30 = mod_vhostdb_pgsql.c
+@BUILD_WITH_PGSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_31 = $(PGSQL_INCLUDE)
+@BUILD_WITH_PGSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_32 = $(PGSQL_LIBS)
+@BUILD_WITH_DBI_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_33 = mod_vhostdb_dbi.c
+@BUILD_WITH_DBI_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_34 = $(DBI_CFLAGS)
+@BUILD_WITH_DBI_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_35 = $(DBI_LIBS)
+@BUILD_WITH_OPENSSL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_36 = mod_openssl.c
+@BUILD_WITH_OPENSSL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_37 = $(SSL_LIB)
+@BUILD_WITH_MEMCACHED_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_38 = $(MEMCACHED_CFLAGS)
+@BUILD_WITH_MEMCACHED_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_39 = $(MEMCACHED_LIB)
+@BUILD_WITH_GDBM_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_40 = $(GDBM_LIB)
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@@LIGHTTPD_STATIC_TRUE@am__append_41 = mod_trigger_b4_dl.c
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/scripts/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)"
+PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@NO_RDYNAMIC_TRUE@liblightcomp_la_DEPENDENCIES = \
+@NO_RDYNAMIC_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@NO_RDYNAMIC_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@NO_RDYNAMIC_TRUE@ $(am__DEPENDENCIES_1)
+am__liblightcomp_la_SOURCES_DIST = base64.c buffer.c burl.c log.c \
+ http_header.c http_kv.c keyvalue.c chunk.c http_chunk.c \
+ stream.c fdevent.c gw_backend.c stat_cache.c plugin.c \
+ joblist.c etag.c array.c data_string.c data_array.c \
+ data_integer.c algo_sha1.c md5.c vector.c fdevent_select.c \
+ fdevent_libev.c fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c data_config.c crc32.c \
+ connections-glue.c configfile-glue.c http-header-glue.c \
+ http_auth.c http_vhostdb.c rand.c request.c sock_addr.c \
+ splaytree.c safe_memclear.c
+am__objects_1 = liblightcomp_la-base64.lo liblightcomp_la-buffer.lo \
+ liblightcomp_la-burl.lo liblightcomp_la-log.lo \
+ liblightcomp_la-http_header.lo liblightcomp_la-http_kv.lo \
+ liblightcomp_la-keyvalue.lo liblightcomp_la-chunk.lo \
+ liblightcomp_la-http_chunk.lo liblightcomp_la-stream.lo \
+ liblightcomp_la-fdevent.lo liblightcomp_la-gw_backend.lo \
+ liblightcomp_la-stat_cache.lo liblightcomp_la-plugin.lo \
+ liblightcomp_la-joblist.lo liblightcomp_la-etag.lo \
+ liblightcomp_la-array.lo liblightcomp_la-data_string.lo \
+ liblightcomp_la-data_array.lo liblightcomp_la-data_integer.lo \
+ liblightcomp_la-algo_sha1.lo liblightcomp_la-md5.lo \
+ liblightcomp_la-vector.lo liblightcomp_la-fdevent_select.lo \
+ liblightcomp_la-fdevent_libev.lo \
+ liblightcomp_la-fdevent_poll.lo \
+ liblightcomp_la-fdevent_linux_sysepoll.lo \
+ liblightcomp_la-fdevent_solaris_devpoll.lo \
+ liblightcomp_la-fdevent_solaris_port.lo \
+ liblightcomp_la-fdevent_freebsd_kqueue.lo \
+ liblightcomp_la-data_config.lo liblightcomp_la-crc32.lo \
+ liblightcomp_la-connections-glue.lo \
+ liblightcomp_la-configfile-glue.lo \
+ liblightcomp_la-http-header-glue.lo \
+ liblightcomp_la-http_auth.lo liblightcomp_la-http_vhostdb.lo \
+ liblightcomp_la-rand.lo liblightcomp_la-request.lo \
+ liblightcomp_la-sock_addr.lo liblightcomp_la-splaytree.lo \
+ liblightcomp_la-safe_memclear.lo
+@NO_RDYNAMIC_TRUE@am_liblightcomp_la_OBJECTS = $(am__objects_1)
+liblightcomp_la_OBJECTS = $(am_liblightcomp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liblightcomp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(liblightcomp_la_CFLAGS) $(CFLAGS) $(liblightcomp_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@NO_RDYNAMIC_TRUE@am_liblightcomp_la_rpath = -rpath $(libdir)
+@NO_RDYNAMIC_TRUE@am__DEPENDENCIES_2 = liblightcomp.la
+mod_access_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_access_la_OBJECTS = mod_access.lo
+mod_access_la_OBJECTS = $(am_mod_access_la_OBJECTS)
+mod_access_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_access_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_accesslog_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_accesslog_la_OBJECTS = mod_accesslog.lo
+mod_accesslog_la_OBJECTS = $(am_mod_accesslog_la_OBJECTS)
+mod_accesslog_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_accesslog_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_alias_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_alias_la_OBJECTS = mod_alias.lo
+mod_alias_la_OBJECTS = $(am_mod_alias_la_OBJECTS)
+mod_alias_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_alias_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_auth_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_auth_la_OBJECTS = mod_auth.lo
+mod_auth_la_OBJECTS = $(am_mod_auth_la_OBJECTS)
+mod_auth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_auth_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_authn_file_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+am_mod_authn_file_la_OBJECTS = mod_authn_file.lo
+mod_authn_file_la_OBJECTS = $(am_mod_authn_file_la_OBJECTS)
+mod_authn_file_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_authn_file_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@BUILD_WITH_KRB5_TRUE@mod_authn_gssapi_la_DEPENDENCIES = \
+@BUILD_WITH_KRB5_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_KRB5_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_authn_gssapi_la_SOURCES_DIST = mod_authn_gssapi.c
+@BUILD_WITH_KRB5_TRUE@am_mod_authn_gssapi_la_OBJECTS = \
+@BUILD_WITH_KRB5_TRUE@ mod_authn_gssapi.lo
+mod_authn_gssapi_la_OBJECTS = $(am_mod_authn_gssapi_la_OBJECTS)
+mod_authn_gssapi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_authn_gssapi_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_KRB5_TRUE@am_mod_authn_gssapi_la_rpath = -rpath $(libdir)
+@BUILD_WITH_LDAP_TRUE@mod_authn_ldap_la_DEPENDENCIES = \
+@BUILD_WITH_LDAP_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_LDAP_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_LDAP_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_authn_ldap_la_SOURCES_DIST = mod_authn_ldap.c
+@BUILD_WITH_LDAP_TRUE@am_mod_authn_ldap_la_OBJECTS = \
+@BUILD_WITH_LDAP_TRUE@ mod_authn_ldap.lo
+mod_authn_ldap_la_OBJECTS = $(am_mod_authn_ldap_la_OBJECTS)
+mod_authn_ldap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_authn_ldap_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@BUILD_WITH_LDAP_TRUE@am_mod_authn_ldap_la_rpath = -rpath $(libdir)
+@BUILD_WITH_MYSQL_TRUE@mod_authn_mysql_la_DEPENDENCIES = \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_authn_mysql_la_SOURCES_DIST = mod_authn_mysql.c
+@BUILD_WITH_MYSQL_TRUE@am_mod_authn_mysql_la_OBJECTS = \
+@BUILD_WITH_MYSQL_TRUE@ mod_authn_mysql_la-mod_authn_mysql.lo
+mod_authn_mysql_la_OBJECTS = $(am_mod_authn_mysql_la_OBJECTS)
+mod_authn_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_authn_mysql_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_MYSQL_TRUE@am_mod_authn_mysql_la_rpath = -rpath $(libdir)
+@BUILD_WITH_PAM_TRUE@mod_authn_pam_la_DEPENDENCIES = \
+@BUILD_WITH_PAM_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_PAM_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_authn_pam_la_SOURCES_DIST = mod_authn_pam.c
+@BUILD_WITH_PAM_TRUE@am_mod_authn_pam_la_OBJECTS = mod_authn_pam.lo
+mod_authn_pam_la_OBJECTS = $(am_mod_authn_pam_la_OBJECTS)
+mod_authn_pam_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_authn_pam_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@BUILD_WITH_PAM_TRUE@am_mod_authn_pam_la_rpath = -rpath $(libdir)
+@BUILD_WITH_SASL_TRUE@mod_authn_sasl_la_DEPENDENCIES = \
+@BUILD_WITH_SASL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_SASL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_authn_sasl_la_SOURCES_DIST = mod_authn_sasl.c
+@BUILD_WITH_SASL_TRUE@am_mod_authn_sasl_la_OBJECTS = \
+@BUILD_WITH_SASL_TRUE@ mod_authn_sasl_la-mod_authn_sasl.lo
+mod_authn_sasl_la_OBJECTS = $(am_mod_authn_sasl_la_OBJECTS)
+mod_authn_sasl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_authn_sasl_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@BUILD_WITH_SASL_TRUE@am_mod_authn_sasl_la_rpath = -rpath $(libdir)
+mod_cgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_cgi_la_OBJECTS = mod_cgi.lo
+mod_cgi_la_OBJECTS = $(am_mod_cgi_la_OBJECTS)
+mod_cgi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_cgi_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_WITH_LUA_TRUE@mod_cml_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@BUILD_WITH_LUA_TRUE@ $(am__DEPENDENCIES_2) \
+@BUILD_WITH_LUA_TRUE@ $(am__DEPENDENCIES_1)
+am__mod_cml_la_SOURCES_DIST = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
+@BUILD_WITH_LUA_TRUE@am_mod_cml_la_OBJECTS = mod_cml_la-mod_cml.lo \
+@BUILD_WITH_LUA_TRUE@ mod_cml_la-mod_cml_lua.lo \
+@BUILD_WITH_LUA_TRUE@ mod_cml_la-mod_cml_funcs.lo
+mod_cml_la_OBJECTS = $(am_mod_cml_la_OBJECTS)
+mod_cml_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mod_cml_la_CFLAGS) \
+ $(CFLAGS) $(mod_cml_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_WITH_LUA_TRUE@am_mod_cml_la_rpath = -rpath $(libdir)
+mod_compress_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+am_mod_compress_la_OBJECTS = mod_compress.lo
+mod_compress_la_OBJECTS = $(am_mod_compress_la_OBJECTS)
+mod_compress_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_compress_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_deflate_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+am_mod_deflate_la_OBJECTS = mod_deflate.lo
+mod_deflate_la_OBJECTS = $(am_mod_deflate_la_OBJECTS)
+mod_deflate_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_deflate_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo
+mod_dirlisting_la_OBJECTS = $(am_mod_dirlisting_la_OBJECTS)
+mod_dirlisting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_dirlisting_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_evasive_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_evasive_la_OBJECTS = mod_evasive.lo
+mod_evasive_la_OBJECTS = $(am_mod_evasive_la_OBJECTS)
+mod_evasive_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_evasive_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_evhost_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_evhost_la_OBJECTS = mod_evhost.lo
+mod_evhost_la_OBJECTS = $(am_mod_evhost_la_OBJECTS)
+mod_evhost_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_evhost_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_expire_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_expire_la_OBJECTS = mod_expire.lo
+mod_expire_la_OBJECTS = $(am_mod_expire_la_OBJECTS)
+mod_expire_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_expire_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_extforward_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_extforward_la_OBJECTS = mod_extforward.lo
+mod_extforward_la_OBJECTS = $(am_mod_extforward_la_OBJECTS)
+mod_extforward_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_extforward_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_fastcgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_fastcgi_la_OBJECTS = mod_fastcgi.lo
+mod_fastcgi_la_OBJECTS = $(am_mod_fastcgi_la_OBJECTS)
+mod_fastcgi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_fastcgi_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_flv_streaming_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_flv_streaming_la_OBJECTS = mod_flv_streaming.lo
+mod_flv_streaming_la_OBJECTS = $(am_mod_flv_streaming_la_OBJECTS)
+mod_flv_streaming_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_flv_streaming_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_GEOIP_TRUE@mod_geoip_la_DEPENDENCIES = \
+@BUILD_WITH_GEOIP_TRUE@ $(am__DEPENDENCIES_2) \
+@BUILD_WITH_GEOIP_TRUE@ $(am__DEPENDENCIES_1)
+am__mod_geoip_la_SOURCES_DIST = mod_geoip.c
+@BUILD_WITH_GEOIP_TRUE@am_mod_geoip_la_OBJECTS = mod_geoip.lo
+mod_geoip_la_OBJECTS = $(am_mod_geoip_la_OBJECTS)
+mod_geoip_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_geoip_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_WITH_GEOIP_TRUE@am_mod_geoip_la_rpath = -rpath $(libdir)
+mod_indexfile_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_indexfile_la_OBJECTS = mod_indexfile.lo
+mod_indexfile_la_OBJECTS = $(am_mod_indexfile_la_OBJECTS)
+mod_indexfile_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_indexfile_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+@BUILD_WITH_LUA_TRUE@mod_magnet_la_DEPENDENCIES = \
+@BUILD_WITH_LUA_TRUE@ $(am__DEPENDENCIES_2) \
+@BUILD_WITH_LUA_TRUE@ $(am__DEPENDENCIES_1)
+am__mod_magnet_la_SOURCES_DIST = mod_magnet.c mod_magnet_cache.c
+@BUILD_WITH_LUA_TRUE@am_mod_magnet_la_OBJECTS = \
+@BUILD_WITH_LUA_TRUE@ mod_magnet_la-mod_magnet.lo \
+@BUILD_WITH_LUA_TRUE@ mod_magnet_la-mod_magnet_cache.lo
+mod_magnet_la_OBJECTS = $(am_mod_magnet_la_OBJECTS)
+mod_magnet_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mod_magnet_la_CFLAGS) \
+ $(CFLAGS) $(mod_magnet_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_WITH_LUA_TRUE@am_mod_magnet_la_rpath = -rpath $(libdir)
+@BUILD_WITH_MYSQL_TRUE@mod_mysql_vhost_la_DEPENDENCIES = \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_mysql_vhost_la_SOURCES_DIST = mod_mysql_vhost.c
+@BUILD_WITH_MYSQL_TRUE@am_mod_mysql_vhost_la_OBJECTS = \
+@BUILD_WITH_MYSQL_TRUE@ mod_mysql_vhost_la-mod_mysql_vhost.lo
+mod_mysql_vhost_la_OBJECTS = $(am_mod_mysql_vhost_la_OBJECTS)
+mod_mysql_vhost_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_mysql_vhost_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_MYSQL_TRUE@am_mod_mysql_vhost_la_rpath = -rpath $(libdir)
+@BUILD_WITH_OPENSSL_TRUE@mod_openssl_la_DEPENDENCIES = \
+@BUILD_WITH_OPENSSL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_OPENSSL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_openssl_la_SOURCES_DIST = mod_openssl.c
+@BUILD_WITH_OPENSSL_TRUE@am_mod_openssl_la_OBJECTS = mod_openssl.lo
+mod_openssl_la_OBJECTS = $(am_mod_openssl_la_OBJECTS)
+mod_openssl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_openssl_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+@BUILD_WITH_OPENSSL_TRUE@am_mod_openssl_la_rpath = -rpath $(libdir)
+mod_proxy_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_proxy_la_OBJECTS = mod_proxy.lo
+mod_proxy_la_OBJECTS = $(am_mod_proxy_la_OBJECTS)
+mod_proxy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_proxy_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_redirect_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_mod_redirect_la_OBJECTS = mod_redirect.lo
+mod_redirect_la_OBJECTS = $(am_mod_redirect_la_OBJECTS)
+mod_redirect_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_redirect_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_rewrite_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_mod_rewrite_la_OBJECTS = mod_rewrite.lo
+mod_rewrite_la_OBJECTS = $(am_mod_rewrite_la_OBJECTS)
+mod_rewrite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_rewrite_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_rrdtool_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_rrdtool_la_OBJECTS = mod_rrdtool.lo
+mod_rrdtool_la_OBJECTS = $(am_mod_rrdtool_la_OBJECTS)
+mod_rrdtool_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_rrdtool_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_scgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_scgi_la_OBJECTS = mod_scgi.lo
+mod_scgi_la_OBJECTS = $(am_mod_scgi_la_OBJECTS)
+mod_scgi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_scgi_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_secdownload_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am_mod_secdownload_la_OBJECTS = mod_secdownload.lo
+mod_secdownload_la_OBJECTS = $(am_mod_secdownload_la_OBJECTS)
+mod_secdownload_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_secdownload_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+mod_setenv_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_setenv_la_OBJECTS = mod_setenv.lo
+mod_setenv_la_OBJECTS = $(am_mod_setenv_la_OBJECTS)
+mod_setenv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_setenv_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_simple_vhost_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_simple_vhost_la_OBJECTS = mod_simple_vhost.lo
+mod_simple_vhost_la_OBJECTS = $(am_mod_simple_vhost_la_OBJECTS)
+mod_simple_vhost_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_simple_vhost_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+mod_sockproxy_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_sockproxy_la_OBJECTS = mod_sockproxy.lo
+mod_sockproxy_la_OBJECTS = $(am_mod_sockproxy_la_OBJECTS)
+mod_sockproxy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_sockproxy_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_ssi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_ssi_la_OBJECTS = mod_ssi_exprparser.lo mod_ssi_expr.lo \
+ mod_ssi.lo
+mod_ssi_la_OBJECTS = $(am_mod_ssi_la_OBJECTS)
+mod_ssi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_ssi_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_staticfile_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_staticfile_la_OBJECTS = mod_staticfile.lo
+mod_staticfile_la_OBJECTS = $(am_mod_staticfile_la_OBJECTS)
+mod_staticfile_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_staticfile_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_status_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_status_la_OBJECTS = mod_status.lo
+mod_status_la_OBJECTS = $(am_mod_status_la_OBJECTS)
+mod_status_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_status_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@mod_trigger_b4_dl_la_DEPENDENCIES = \
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_trigger_b4_dl_la_SOURCES_DIST = mod_trigger_b4_dl.c
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@am_mod_trigger_b4_dl_la_OBJECTS = \
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@ mod_trigger_b4_dl.lo
+mod_trigger_b4_dl_la_OBJECTS = $(am_mod_trigger_b4_dl_la_OBJECTS)
+mod_trigger_b4_dl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_trigger_b4_dl_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@am_mod_trigger_b4_dl_la_rpath = -rpath \
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@ $(libdir)
+mod_uploadprogress_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_uploadprogress_la_OBJECTS = mod_uploadprogress.lo
+mod_uploadprogress_la_OBJECTS = $(am_mod_uploadprogress_la_OBJECTS)
+mod_uploadprogress_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_uploadprogress_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+mod_userdir_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_userdir_la_OBJECTS = mod_userdir.lo
+mod_userdir_la_OBJECTS = $(am_mod_userdir_la_OBJECTS)
+mod_userdir_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_userdir_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_usertrack_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_usertrack_la_OBJECTS = mod_usertrack.lo
+mod_usertrack_la_OBJECTS = $(am_mod_usertrack_la_OBJECTS)
+mod_usertrack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_usertrack_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_vhostdb_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_vhostdb_la_OBJECTS = mod_vhostdb.lo
+mod_vhostdb_la_OBJECTS = $(am_mod_vhostdb_la_OBJECTS)
+mod_vhostdb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_vhostdb_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+@BUILD_WITH_DBI_TRUE@mod_vhostdb_dbi_la_DEPENDENCIES = \
+@BUILD_WITH_DBI_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_DBI_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_vhostdb_dbi_la_SOURCES_DIST = mod_vhostdb_dbi.c
+@BUILD_WITH_DBI_TRUE@am_mod_vhostdb_dbi_la_OBJECTS = \
+@BUILD_WITH_DBI_TRUE@ mod_vhostdb_dbi_la-mod_vhostdb_dbi.lo
+mod_vhostdb_dbi_la_OBJECTS = $(am_mod_vhostdb_dbi_la_OBJECTS)
+mod_vhostdb_dbi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_vhostdb_dbi_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_DBI_TRUE@am_mod_vhostdb_dbi_la_rpath = -rpath $(libdir)
+@BUILD_WITH_LDAP_TRUE@mod_vhostdb_ldap_la_DEPENDENCIES = \
+@BUILD_WITH_LDAP_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_LDAP_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_LDAP_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_vhostdb_ldap_la_SOURCES_DIST = mod_vhostdb_ldap.c
+@BUILD_WITH_LDAP_TRUE@am_mod_vhostdb_ldap_la_OBJECTS = \
+@BUILD_WITH_LDAP_TRUE@ mod_vhostdb_ldap.lo
+mod_vhostdb_ldap_la_OBJECTS = $(am_mod_vhostdb_ldap_la_OBJECTS)
+mod_vhostdb_ldap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_vhostdb_ldap_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_LDAP_TRUE@am_mod_vhostdb_ldap_la_rpath = -rpath $(libdir)
+@BUILD_WITH_MYSQL_TRUE@mod_vhostdb_mysql_la_DEPENDENCIES = \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_MYSQL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_vhostdb_mysql_la_SOURCES_DIST = mod_vhostdb_mysql.c
+@BUILD_WITH_MYSQL_TRUE@am_mod_vhostdb_mysql_la_OBJECTS = mod_vhostdb_mysql_la-mod_vhostdb_mysql.lo
+mod_vhostdb_mysql_la_OBJECTS = $(am_mod_vhostdb_mysql_la_OBJECTS)
+mod_vhostdb_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_vhostdb_mysql_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_MYSQL_TRUE@am_mod_vhostdb_mysql_la_rpath = -rpath \
+@BUILD_WITH_MYSQL_TRUE@ $(libdir)
+@BUILD_WITH_PGSQL_TRUE@mod_vhostdb_pgsql_la_DEPENDENCIES = \
+@BUILD_WITH_PGSQL_TRUE@ $(am__DEPENDENCIES_1) \
+@BUILD_WITH_PGSQL_TRUE@ $(am__DEPENDENCIES_2)
+am__mod_vhostdb_pgsql_la_SOURCES_DIST = mod_vhostdb_pgsql.c
+@BUILD_WITH_PGSQL_TRUE@am_mod_vhostdb_pgsql_la_OBJECTS = mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.lo
+mod_vhostdb_pgsql_la_OBJECTS = $(am_mod_vhostdb_pgsql_la_OBJECTS)
+mod_vhostdb_pgsql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_vhostdb_pgsql_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@BUILD_WITH_PGSQL_TRUE@am_mod_vhostdb_pgsql_la_rpath = -rpath \
+@BUILD_WITH_PGSQL_TRUE@ $(libdir)
+mod_webdav_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_mod_webdav_la_OBJECTS = mod_webdav_la-mod_webdav.lo
+mod_webdav_la_OBJECTS = $(am_mod_webdav_la_OBJECTS)
+mod_webdav_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mod_webdav_la_CFLAGS) \
+ $(CFLAGS) $(mod_webdav_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_wstunnel_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am_mod_wstunnel_la_OBJECTS = mod_wstunnel.lo
+mod_wstunnel_la_OBJECTS = $(am_mod_wstunnel_la_OBJECTS)
+mod_wstunnel_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_wstunnel_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+am__lighttpd_SOURCES_DIST = server.c response.c connections.c \
+ inet_ntop_cache.c network.c network_write.c configfile.c \
+ configparser.c base64.c buffer.c burl.c log.c http_header.c \
+ http_kv.c keyvalue.c chunk.c http_chunk.c stream.c fdevent.c \
+ gw_backend.c stat_cache.c plugin.c joblist.c etag.c array.c \
+ data_string.c data_array.c data_integer.c algo_sha1.c md5.c \
+ vector.c fdevent_select.c fdevent_libev.c fdevent_poll.c \
+ fdevent_linux_sysepoll.c fdevent_solaris_devpoll.c \
+ fdevent_solaris_port.c fdevent_freebsd_kqueue.c data_config.c \
+ crc32.c connections-glue.c configfile-glue.c \
+ http-header-glue.c http_auth.c http_vhostdb.c rand.c request.c \
+ sock_addr.c splaytree.c safe_memclear.c mod_access.c \
+ mod_accesslog.c mod_alias.c mod_auth.c mod_authn_file.c \
+ mod_cgi.c mod_compress.c mod_deflate.c mod_dirlisting.c \
+ mod_evasive.c mod_expire.c mod_extforward.c mod_fastcgi.c \
+ mod_flv_streaming.c mod_indexfile.c mod_proxy.c mod_redirect.c \
+ mod_rewrite.c mod_rrdtool.c mod_scgi.c mod_secdownload.c \
+ mod_setenv.c mod_simple_vhost.c mod_ssi_exprparser.c \
+ mod_ssi_expr.c mod_ssi.c mod_staticfile.c mod_status.c \
+ mod_uploadprogress.c mod_userdir.c mod_usertrack.c \
+ mod_vhostdb.c mod_webdav.c mod_geoip.c mod_cml.c mod_cml_lua.c \
+ mod_cml_funcs.c mod_magnet.c mod_magnet_cache.c \
+ mod_authn_gssapi.c mod_authn_ldap.c mod_vhostdb_ldap.c \
+ mod_authn_pam.c mod_authn_mysql.c mod_mysql_vhost.c \
+ mod_vhostdb_mysql.c mod_vhostdb_pgsql.c mod_vhostdb_dbi.c \
+ mod_openssl.c mod_trigger_b4_dl.c
+am__objects_2 = lighttpd-base64.$(OBJEXT) lighttpd-buffer.$(OBJEXT) \
+ lighttpd-burl.$(OBJEXT) lighttpd-log.$(OBJEXT) \
+ lighttpd-http_header.$(OBJEXT) lighttpd-http_kv.$(OBJEXT) \
+ lighttpd-keyvalue.$(OBJEXT) lighttpd-chunk.$(OBJEXT) \
+ lighttpd-http_chunk.$(OBJEXT) lighttpd-stream.$(OBJEXT) \
+ lighttpd-fdevent.$(OBJEXT) lighttpd-gw_backend.$(OBJEXT) \
+ lighttpd-stat_cache.$(OBJEXT) lighttpd-plugin.$(OBJEXT) \
+ lighttpd-joblist.$(OBJEXT) lighttpd-etag.$(OBJEXT) \
+ lighttpd-array.$(OBJEXT) lighttpd-data_string.$(OBJEXT) \
+ lighttpd-data_array.$(OBJEXT) lighttpd-data_integer.$(OBJEXT) \
+ lighttpd-algo_sha1.$(OBJEXT) lighttpd-md5.$(OBJEXT) \
+ lighttpd-vector.$(OBJEXT) lighttpd-fdevent_select.$(OBJEXT) \
+ lighttpd-fdevent_libev.$(OBJEXT) \
+ lighttpd-fdevent_poll.$(OBJEXT) \
+ lighttpd-fdevent_linux_sysepoll.$(OBJEXT) \
+ lighttpd-fdevent_solaris_devpoll.$(OBJEXT) \
+ lighttpd-fdevent_solaris_port.$(OBJEXT) \
+ lighttpd-fdevent_freebsd_kqueue.$(OBJEXT) \
+ lighttpd-data_config.$(OBJEXT) lighttpd-crc32.$(OBJEXT) \
+ lighttpd-connections-glue.$(OBJEXT) \
+ lighttpd-configfile-glue.$(OBJEXT) \
+ lighttpd-http-header-glue.$(OBJEXT) \
+ lighttpd-http_auth.$(OBJEXT) lighttpd-http_vhostdb.$(OBJEXT) \
+ lighttpd-rand.$(OBJEXT) lighttpd-request.$(OBJEXT) \
+ lighttpd-sock_addr.$(OBJEXT) lighttpd-splaytree.$(OBJEXT) \
+ lighttpd-safe_memclear.$(OBJEXT)
+@NO_RDYNAMIC_FALSE@am__objects_3 = $(am__objects_2)
+am__objects_4 = lighttpd-server.$(OBJEXT) lighttpd-response.$(OBJEXT) \
+ lighttpd-connections.$(OBJEXT) \
+ lighttpd-inet_ntop_cache.$(OBJEXT) lighttpd-network.$(OBJEXT) \
+ lighttpd-network_write.$(OBJEXT) lighttpd-configfile.$(OBJEXT) \
+ lighttpd-configparser.$(OBJEXT) $(am__objects_3)
+@BUILD_WITH_GEOIP_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_5 = lighttpd-mod_geoip.$(OBJEXT)
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_6 = lighttpd-mod_cml.$(OBJEXT) \
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_cml_lua.$(OBJEXT) \
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_cml_funcs.$(OBJEXT) \
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_magnet.$(OBJEXT) \
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_magnet_cache.$(OBJEXT)
+@BUILD_WITH_KRB5_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_7 = lighttpd-mod_authn_gssapi.$(OBJEXT)
+@BUILD_WITH_LDAP_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_8 = lighttpd-mod_authn_ldap.$(OBJEXT) \
+@BUILD_WITH_LDAP_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_vhostdb_ldap.$(OBJEXT)
+@BUILD_WITH_PAM_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_9 = lighttpd-mod_authn_pam.$(OBJEXT)
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_10 = lighttpd-mod_authn_mysql.$(OBJEXT) \
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_mysql_vhost.$(OBJEXT) \
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_vhostdb_mysql.$(OBJEXT)
+@BUILD_WITH_PGSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_11 = lighttpd-mod_vhostdb_pgsql.$(OBJEXT)
+@BUILD_WITH_DBI_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_12 = lighttpd-mod_vhostdb_dbi.$(OBJEXT)
+@BUILD_WITH_OPENSSL_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_13 = lighttpd-mod_openssl.$(OBJEXT)
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@@LIGHTTPD_STATIC_TRUE@am__objects_14 = lighttpd-mod_trigger_b4_dl.$(OBJEXT)
+@LIGHTTPD_STATIC_FALSE@am_lighttpd_OBJECTS = $(am__objects_4)
+@LIGHTTPD_STATIC_TRUE@am_lighttpd_OBJECTS = $(am__objects_4) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_access.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_accesslog.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_alias.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_auth.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_authn_file.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_cgi.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_compress.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_deflate.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_dirlisting.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_evasive.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_expire.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_extforward.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_fastcgi.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_flv_streaming.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_indexfile.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_proxy.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_redirect.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_rewrite.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_rrdtool.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_scgi.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_secdownload.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_setenv.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_simple_vhost.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_ssi_exprparser.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_ssi_expr.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_ssi.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_staticfile.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_status.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_uploadprogress.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_userdir.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_usertrack.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_vhostdb.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ lighttpd-mod_webdav.$(OBJEXT) \
+@LIGHTTPD_STATIC_TRUE@ $(am__objects_5) $(am__objects_6) \
+@LIGHTTPD_STATIC_TRUE@ $(am__objects_7) $(am__objects_8) \
+@LIGHTTPD_STATIC_TRUE@ $(am__objects_9) $(am__objects_10) \
+@LIGHTTPD_STATIC_TRUE@ $(am__objects_11) $(am__objects_12) \
+@LIGHTTPD_STATIC_TRUE@ $(am__objects_13) $(am__objects_14)
+lighttpd_OBJECTS = $(am_lighttpd_OBJECTS)
+@BUILD_WITH_GEOIP_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_LUA_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_KRB5_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_LDAP_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1) \
+@BUILD_WITH_LDAP_TRUE@@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1)
+@BUILD_WITH_PAM_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_MYSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_PGSQL_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_DBI_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_10 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_OPENSSL_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_11 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_MEMCACHED_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_12 = $(am__DEPENDENCIES_1)
+@BUILD_WITH_GDBM_TRUE@@LIGHTTPD_STATIC_TRUE@am__DEPENDENCIES_13 = $(am__DEPENDENCIES_1)
+@LIGHTTPD_STATIC_FALSE@lighttpd_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_2) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_FALSE@ $(am__DEPENDENCIES_1)
+@LIGHTTPD_STATIC_TRUE@lighttpd_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_1) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_3) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_4) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_5) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_6) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_7) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_8) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_9) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_10) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_11) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_12) \
+@LIGHTTPD_STATIC_TRUE@ $(am__DEPENDENCIES_13)
+lighttpd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(lighttpd_LDFLAGS) $(LDFLAGS) -o $@
+am_lighttpd_angel_OBJECTS = lighttpd-angel.$(OBJEXT)
+lighttpd_angel_OBJECTS = $(am_lighttpd_angel_OBJECTS)
+lighttpd_angel_LDADD = $(LDADD)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_t_test_array_OBJECTS = t/test_array.$(OBJEXT) array.$(OBJEXT) \
+ data_array.$(OBJEXT) data_integer.$(OBJEXT) \
+ data_string.$(OBJEXT) buffer.$(OBJEXT)
+t_test_array_OBJECTS = $(am_t_test_array_OBJECTS)
+t_test_array_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_t_test_base64_OBJECTS = t/test_base64.$(OBJEXT) base64.$(OBJEXT) \
+ buffer.$(OBJEXT)
+t_test_base64_OBJECTS = $(am_t_test_base64_OBJECTS)
+t_test_base64_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_t_test_buffer_OBJECTS = t/test_buffer.$(OBJEXT) buffer.$(OBJEXT)
+t_test_buffer_OBJECTS = $(am_t_test_buffer_OBJECTS)
+t_test_buffer_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_t_test_burl_OBJECTS = t/test_burl.$(OBJEXT) burl.$(OBJEXT) \
+ buffer.$(OBJEXT) base64.$(OBJEXT)
+t_test_burl_OBJECTS = $(am_t_test_burl_OBJECTS)
+t_test_burl_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_t_test_configfile_OBJECTS = t/test_configfile.$(OBJEXT) \
+ buffer.$(OBJEXT) array.$(OBJEXT) data_config.$(OBJEXT) \
+ data_integer.$(OBJEXT) data_string.$(OBJEXT) \
+ http_header.$(OBJEXT) http_kv.$(OBJEXT) vector.$(OBJEXT) \
+ log.$(OBJEXT) sock_addr.$(OBJEXT)
+t_test_configfile_OBJECTS = $(am_t_test_configfile_OBJECTS)
+t_test_configfile_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_t_test_keyvalue_OBJECTS = t/test_keyvalue.$(OBJEXT) burl.$(OBJEXT) \
+ buffer.$(OBJEXT) base64.$(OBJEXT) array.$(OBJEXT) \
+ data_integer.$(OBJEXT) data_string.$(OBJEXT) log.$(OBJEXT)
+t_test_keyvalue_OBJECTS = $(am_t_test_keyvalue_OBJECTS)
+t_test_keyvalue_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_t_test_mod_access_OBJECTS = t/test_mod_access.$(OBJEXT) \
+ configfile-glue.$(OBJEXT) buffer.$(OBJEXT) array.$(OBJEXT) \
+ data_config.$(OBJEXT) data_integer.$(OBJEXT) \
+ data_string.$(OBJEXT) http_header.$(OBJEXT) http_kv.$(OBJEXT) \
+ vector.$(OBJEXT) log.$(OBJEXT) sock_addr.$(OBJEXT)
+t_test_mod_access_OBJECTS = $(am_t_test_mod_access_OBJECTS)
+t_test_mod_access_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_t_test_mod_evhost_OBJECTS = t/test_mod_evhost.$(OBJEXT) \
+ configfile-glue.$(OBJEXT) buffer.$(OBJEXT) array.$(OBJEXT) \
+ data_config.$(OBJEXT) data_integer.$(OBJEXT) \
+ data_string.$(OBJEXT) http_header.$(OBJEXT) http_kv.$(OBJEXT) \
+ vector.$(OBJEXT) log.$(OBJEXT) sock_addr.$(OBJEXT)
+t_test_mod_evhost_OBJECTS = $(am_t_test_mod_evhost_OBJECTS)
+t_test_mod_evhost_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_t_test_mod_simple_vhost_OBJECTS = \
+ t/test_mod_simple_vhost.$(OBJEXT) configfile-glue.$(OBJEXT) \
+ buffer.$(OBJEXT) array.$(OBJEXT) data_config.$(OBJEXT) \
+ data_integer.$(OBJEXT) data_string.$(OBJEXT) \
+ http_header.$(OBJEXT) http_kv.$(OBJEXT) vector.$(OBJEXT) \
+ log.$(OBJEXT) sock_addr.$(OBJEXT)
+t_test_mod_simple_vhost_OBJECTS = \
+ $(am_t_test_mod_simple_vhost_OBJECTS)
+t_test_mod_simple_vhost_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_t_test_request_OBJECTS = t/test_request.$(OBJEXT) request.$(OBJEXT) \
+ buffer.$(OBJEXT) array.$(OBJEXT) data_integer.$(OBJEXT) \
+ data_string.$(OBJEXT) http_header.$(OBJEXT) http_kv.$(OBJEXT) \
+ log.$(OBJEXT) sock_addr.$(OBJEXT)
+t_test_request_OBJECTS = $(am_t_test_request_OBJECTS)
+t_test_request_DEPENDENCIES = $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/array.Po ./$(DEPDIR)/base64.Po \
+ ./$(DEPDIR)/buffer.Po ./$(DEPDIR)/burl.Po \
+ ./$(DEPDIR)/configfile-glue.Po ./$(DEPDIR)/data_array.Po \
+ ./$(DEPDIR)/data_config.Po ./$(DEPDIR)/data_integer.Po \
+ ./$(DEPDIR)/data_string.Po ./$(DEPDIR)/http_header.Po \
+ ./$(DEPDIR)/http_kv.Po \
+ ./$(DEPDIR)/liblightcomp_la-algo_sha1.Plo \
+ ./$(DEPDIR)/liblightcomp_la-array.Plo \
+ ./$(DEPDIR)/liblightcomp_la-base64.Plo \
+ ./$(DEPDIR)/liblightcomp_la-buffer.Plo \
+ ./$(DEPDIR)/liblightcomp_la-burl.Plo \
+ ./$(DEPDIR)/liblightcomp_la-chunk.Plo \
+ ./$(DEPDIR)/liblightcomp_la-configfile-glue.Plo \
+ ./$(DEPDIR)/liblightcomp_la-connections-glue.Plo \
+ ./$(DEPDIR)/liblightcomp_la-crc32.Plo \
+ ./$(DEPDIR)/liblightcomp_la-data_array.Plo \
+ ./$(DEPDIR)/liblightcomp_la-data_config.Plo \
+ ./$(DEPDIR)/liblightcomp_la-data_integer.Plo \
+ ./$(DEPDIR)/liblightcomp_la-data_string.Plo \
+ ./$(DEPDIR)/liblightcomp_la-etag.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_libev.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_poll.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_select.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo \
+ ./$(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo \
+ ./$(DEPDIR)/liblightcomp_la-gw_backend.Plo \
+ ./$(DEPDIR)/liblightcomp_la-http-header-glue.Plo \
+ ./$(DEPDIR)/liblightcomp_la-http_auth.Plo \
+ ./$(DEPDIR)/liblightcomp_la-http_chunk.Plo \
+ ./$(DEPDIR)/liblightcomp_la-http_header.Plo \
+ ./$(DEPDIR)/liblightcomp_la-http_kv.Plo \
+ ./$(DEPDIR)/liblightcomp_la-http_vhostdb.Plo \
+ ./$(DEPDIR)/liblightcomp_la-joblist.Plo \
+ ./$(DEPDIR)/liblightcomp_la-keyvalue.Plo \
+ ./$(DEPDIR)/liblightcomp_la-log.Plo \
+ ./$(DEPDIR)/liblightcomp_la-md5.Plo \
+ ./$(DEPDIR)/liblightcomp_la-plugin.Plo \
+ ./$(DEPDIR)/liblightcomp_la-rand.Plo \
+ ./$(DEPDIR)/liblightcomp_la-request.Plo \
+ ./$(DEPDIR)/liblightcomp_la-safe_memclear.Plo \
+ ./$(DEPDIR)/liblightcomp_la-sock_addr.Plo \
+ ./$(DEPDIR)/liblightcomp_la-splaytree.Plo \
+ ./$(DEPDIR)/liblightcomp_la-stat_cache.Plo \
+ ./$(DEPDIR)/liblightcomp_la-stream.Plo \
+ ./$(DEPDIR)/liblightcomp_la-vector.Plo \
+ ./$(DEPDIR)/lighttpd-algo_sha1.Po \
+ ./$(DEPDIR)/lighttpd-angel.Po ./$(DEPDIR)/lighttpd-array.Po \
+ ./$(DEPDIR)/lighttpd-base64.Po ./$(DEPDIR)/lighttpd-buffer.Po \
+ ./$(DEPDIR)/lighttpd-burl.Po ./$(DEPDIR)/lighttpd-chunk.Po \
+ ./$(DEPDIR)/lighttpd-configfile-glue.Po \
+ ./$(DEPDIR)/lighttpd-configfile.Po \
+ ./$(DEPDIR)/lighttpd-configparser.Po \
+ ./$(DEPDIR)/lighttpd-connections-glue.Po \
+ ./$(DEPDIR)/lighttpd-connections.Po \
+ ./$(DEPDIR)/lighttpd-crc32.Po \
+ ./$(DEPDIR)/lighttpd-data_array.Po \
+ ./$(DEPDIR)/lighttpd-data_config.Po \
+ ./$(DEPDIR)/lighttpd-data_integer.Po \
+ ./$(DEPDIR)/lighttpd-data_string.Po \
+ ./$(DEPDIR)/lighttpd-etag.Po ./$(DEPDIR)/lighttpd-fdevent.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_libev.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_poll.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_select.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Po \
+ ./$(DEPDIR)/lighttpd-fdevent_solaris_port.Po \
+ ./$(DEPDIR)/lighttpd-gw_backend.Po \
+ ./$(DEPDIR)/lighttpd-http-header-glue.Po \
+ ./$(DEPDIR)/lighttpd-http_auth.Po \
+ ./$(DEPDIR)/lighttpd-http_chunk.Po \
+ ./$(DEPDIR)/lighttpd-http_header.Po \
+ ./$(DEPDIR)/lighttpd-http_kv.Po \
+ ./$(DEPDIR)/lighttpd-http_vhostdb.Po \
+ ./$(DEPDIR)/lighttpd-inet_ntop_cache.Po \
+ ./$(DEPDIR)/lighttpd-joblist.Po \
+ ./$(DEPDIR)/lighttpd-keyvalue.Po ./$(DEPDIR)/lighttpd-log.Po \
+ ./$(DEPDIR)/lighttpd-md5.Po ./$(DEPDIR)/lighttpd-mod_access.Po \
+ ./$(DEPDIR)/lighttpd-mod_accesslog.Po \
+ ./$(DEPDIR)/lighttpd-mod_alias.Po \
+ ./$(DEPDIR)/lighttpd-mod_auth.Po \
+ ./$(DEPDIR)/lighttpd-mod_authn_file.Po \
+ ./$(DEPDIR)/lighttpd-mod_authn_gssapi.Po \
+ ./$(DEPDIR)/lighttpd-mod_authn_ldap.Po \
+ ./$(DEPDIR)/lighttpd-mod_authn_mysql.Po \
+ ./$(DEPDIR)/lighttpd-mod_authn_pam.Po \
+ ./$(DEPDIR)/lighttpd-mod_cgi.Po \
+ ./$(DEPDIR)/lighttpd-mod_cml.Po \
+ ./$(DEPDIR)/lighttpd-mod_cml_funcs.Po \
+ ./$(DEPDIR)/lighttpd-mod_cml_lua.Po \
+ ./$(DEPDIR)/lighttpd-mod_compress.Po \
+ ./$(DEPDIR)/lighttpd-mod_deflate.Po \
+ ./$(DEPDIR)/lighttpd-mod_dirlisting.Po \
+ ./$(DEPDIR)/lighttpd-mod_evasive.Po \
+ ./$(DEPDIR)/lighttpd-mod_expire.Po \
+ ./$(DEPDIR)/lighttpd-mod_extforward.Po \
+ ./$(DEPDIR)/lighttpd-mod_fastcgi.Po \
+ ./$(DEPDIR)/lighttpd-mod_flv_streaming.Po \
+ ./$(DEPDIR)/lighttpd-mod_geoip.Po \
+ ./$(DEPDIR)/lighttpd-mod_indexfile.Po \
+ ./$(DEPDIR)/lighttpd-mod_magnet.Po \
+ ./$(DEPDIR)/lighttpd-mod_magnet_cache.Po \
+ ./$(DEPDIR)/lighttpd-mod_mysql_vhost.Po \
+ ./$(DEPDIR)/lighttpd-mod_openssl.Po \
+ ./$(DEPDIR)/lighttpd-mod_proxy.Po \
+ ./$(DEPDIR)/lighttpd-mod_redirect.Po \
+ ./$(DEPDIR)/lighttpd-mod_rewrite.Po \
+ ./$(DEPDIR)/lighttpd-mod_rrdtool.Po \
+ ./$(DEPDIR)/lighttpd-mod_scgi.Po \
+ ./$(DEPDIR)/lighttpd-mod_secdownload.Po \
+ ./$(DEPDIR)/lighttpd-mod_setenv.Po \
+ ./$(DEPDIR)/lighttpd-mod_simple_vhost.Po \
+ ./$(DEPDIR)/lighttpd-mod_ssi.Po \
+ ./$(DEPDIR)/lighttpd-mod_ssi_expr.Po \
+ ./$(DEPDIR)/lighttpd-mod_ssi_exprparser.Po \
+ ./$(DEPDIR)/lighttpd-mod_staticfile.Po \
+ ./$(DEPDIR)/lighttpd-mod_status.Po \
+ ./$(DEPDIR)/lighttpd-mod_trigger_b4_dl.Po \
+ ./$(DEPDIR)/lighttpd-mod_uploadprogress.Po \
+ ./$(DEPDIR)/lighttpd-mod_userdir.Po \
+ ./$(DEPDIR)/lighttpd-mod_usertrack.Po \
+ ./$(DEPDIR)/lighttpd-mod_vhostdb.Po \
+ ./$(DEPDIR)/lighttpd-mod_vhostdb_dbi.Po \
+ ./$(DEPDIR)/lighttpd-mod_vhostdb_ldap.Po \
+ ./$(DEPDIR)/lighttpd-mod_vhostdb_mysql.Po \
+ ./$(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Po \
+ ./$(DEPDIR)/lighttpd-mod_webdav.Po \
+ ./$(DEPDIR)/lighttpd-network.Po \
+ ./$(DEPDIR)/lighttpd-network_write.Po \
+ ./$(DEPDIR)/lighttpd-plugin.Po ./$(DEPDIR)/lighttpd-rand.Po \
+ ./$(DEPDIR)/lighttpd-request.Po \
+ ./$(DEPDIR)/lighttpd-response.Po \
+ ./$(DEPDIR)/lighttpd-safe_memclear.Po \
+ ./$(DEPDIR)/lighttpd-server.Po \
+ ./$(DEPDIR)/lighttpd-sock_addr.Po \
+ ./$(DEPDIR)/lighttpd-splaytree.Po \
+ ./$(DEPDIR)/lighttpd-stat_cache.Po \
+ ./$(DEPDIR)/lighttpd-stream.Po ./$(DEPDIR)/lighttpd-vector.Po \
+ ./$(DEPDIR)/log.Po ./$(DEPDIR)/mod_access.Plo \
+ ./$(DEPDIR)/mod_accesslog.Plo ./$(DEPDIR)/mod_alias.Plo \
+ ./$(DEPDIR)/mod_auth.Plo ./$(DEPDIR)/mod_authn_file.Plo \
+ ./$(DEPDIR)/mod_authn_gssapi.Plo \
+ ./$(DEPDIR)/mod_authn_ldap.Plo \
+ ./$(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Plo \
+ ./$(DEPDIR)/mod_authn_pam.Plo \
+ ./$(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Plo \
+ ./$(DEPDIR)/mod_cgi.Plo ./$(DEPDIR)/mod_cml_la-mod_cml.Plo \
+ ./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo \
+ ./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo \
+ ./$(DEPDIR)/mod_compress.Plo ./$(DEPDIR)/mod_deflate.Plo \
+ ./$(DEPDIR)/mod_dirlisting.Plo ./$(DEPDIR)/mod_evasive.Plo \
+ ./$(DEPDIR)/mod_evhost.Plo ./$(DEPDIR)/mod_expire.Plo \
+ ./$(DEPDIR)/mod_extforward.Plo ./$(DEPDIR)/mod_fastcgi.Plo \
+ ./$(DEPDIR)/mod_flv_streaming.Plo ./$(DEPDIR)/mod_geoip.Plo \
+ ./$(DEPDIR)/mod_indexfile.Plo \
+ ./$(DEPDIR)/mod_magnet_la-mod_magnet.Plo \
+ ./$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo \
+ ./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo \
+ ./$(DEPDIR)/mod_openssl.Plo ./$(DEPDIR)/mod_proxy.Plo \
+ ./$(DEPDIR)/mod_redirect.Plo ./$(DEPDIR)/mod_rewrite.Plo \
+ ./$(DEPDIR)/mod_rrdtool.Plo ./$(DEPDIR)/mod_scgi.Plo \
+ ./$(DEPDIR)/mod_secdownload.Plo ./$(DEPDIR)/mod_setenv.Plo \
+ ./$(DEPDIR)/mod_simple_vhost.Plo ./$(DEPDIR)/mod_sockproxy.Plo \
+ ./$(DEPDIR)/mod_ssi.Plo ./$(DEPDIR)/mod_ssi_expr.Plo \
+ ./$(DEPDIR)/mod_ssi_exprparser.Plo \
+ ./$(DEPDIR)/mod_staticfile.Plo ./$(DEPDIR)/mod_status.Plo \
+ ./$(DEPDIR)/mod_trigger_b4_dl.Plo \
+ ./$(DEPDIR)/mod_uploadprogress.Plo ./$(DEPDIR)/mod_userdir.Plo \
+ ./$(DEPDIR)/mod_usertrack.Plo ./$(DEPDIR)/mod_vhostdb.Plo \
+ ./$(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Plo \
+ ./$(DEPDIR)/mod_vhostdb_ldap.Plo \
+ ./$(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Plo \
+ ./$(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Plo \
+ ./$(DEPDIR)/mod_webdav_la-mod_webdav.Plo \
+ ./$(DEPDIR)/mod_wstunnel.Plo ./$(DEPDIR)/request.Po \
+ ./$(DEPDIR)/sock_addr.Po ./$(DEPDIR)/vector.Po \
+ t/$(DEPDIR)/test_array.Po t/$(DEPDIR)/test_base64.Po \
+ t/$(DEPDIR)/test_buffer.Po t/$(DEPDIR)/test_burl.Po \
+ t/$(DEPDIR)/test_configfile.Po t/$(DEPDIR)/test_keyvalue.Po \
+ t/$(DEPDIR)/test_mod_access.Po t/$(DEPDIR)/test_mod_evhost.Po \
+ t/$(DEPDIR)/test_mod_simple_vhost.Po \
+ t/$(DEPDIR)/test_request.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \
+ $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) \
+ $(mod_auth_la_SOURCES) $(mod_authn_file_la_SOURCES) \
+ $(mod_authn_gssapi_la_SOURCES) $(mod_authn_ldap_la_SOURCES) \
+ $(mod_authn_mysql_la_SOURCES) $(mod_authn_pam_la_SOURCES) \
+ $(mod_authn_sasl_la_SOURCES) $(mod_cgi_la_SOURCES) \
+ $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \
+ $(mod_deflate_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
+ $(mod_expire_la_SOURCES) $(mod_extforward_la_SOURCES) \
+ $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) \
+ $(mod_geoip_la_SOURCES) $(mod_indexfile_la_SOURCES) \
+ $(mod_magnet_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
+ $(mod_openssl_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_sockproxy_la_SOURCES) \
+ $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
+ $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
+ $(mod_uploadprogress_la_SOURCES) $(mod_userdir_la_SOURCES) \
+ $(mod_usertrack_la_SOURCES) $(mod_vhostdb_la_SOURCES) \
+ $(mod_vhostdb_dbi_la_SOURCES) $(mod_vhostdb_ldap_la_SOURCES) \
+ $(mod_vhostdb_mysql_la_SOURCES) \
+ $(mod_vhostdb_pgsql_la_SOURCES) $(mod_webdav_la_SOURCES) \
+ $(mod_wstunnel_la_SOURCES) $(lighttpd_SOURCES) \
+ $(lighttpd_angel_SOURCES) $(t_test_array_SOURCES) \
+ $(t_test_base64_SOURCES) $(t_test_buffer_SOURCES) \
+ $(t_test_burl_SOURCES) $(t_test_configfile_SOURCES) \
+ $(t_test_keyvalue_SOURCES) $(t_test_mod_access_SOURCES) \
+ $(t_test_mod_evhost_SOURCES) \
+ $(t_test_mod_simple_vhost_SOURCES) $(t_test_request_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_authn_file_la_SOURCES) \
+ $(am__mod_authn_gssapi_la_SOURCES_DIST) \
+ $(am__mod_authn_ldap_la_SOURCES_DIST) \
+ $(am__mod_authn_mysql_la_SOURCES_DIST) \
+ $(am__mod_authn_pam_la_SOURCES_DIST) \
+ $(am__mod_authn_sasl_la_SOURCES_DIST) $(mod_cgi_la_SOURCES) \
+ $(am__mod_cml_la_SOURCES_DIST) $(mod_compress_la_SOURCES) \
+ $(mod_deflate_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
+ $(mod_expire_la_SOURCES) $(mod_extforward_la_SOURCES) \
+ $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) \
+ $(am__mod_geoip_la_SOURCES_DIST) $(mod_indexfile_la_SOURCES) \
+ $(am__mod_magnet_la_SOURCES_DIST) \
+ $(am__mod_mysql_vhost_la_SOURCES_DIST) \
+ $(am__mod_openssl_la_SOURCES_DIST) $(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_sockproxy_la_SOURCES) \
+ $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
+ $(mod_status_la_SOURCES) \
+ $(am__mod_trigger_b4_dl_la_SOURCES_DIST) \
+ $(mod_uploadprogress_la_SOURCES) $(mod_userdir_la_SOURCES) \
+ $(mod_usertrack_la_SOURCES) $(mod_vhostdb_la_SOURCES) \
+ $(am__mod_vhostdb_dbi_la_SOURCES_DIST) \
+ $(am__mod_vhostdb_ldap_la_SOURCES_DIST) \
+ $(am__mod_vhostdb_mysql_la_SOURCES_DIST) \
+ $(am__mod_vhostdb_pgsql_la_SOURCES_DIST) \
+ $(mod_webdav_la_SOURCES) $(mod_wstunnel_la_SOURCES) \
+ $(am__lighttpd_SOURCES_DIST) $(lighttpd_angel_SOURCES) \
+ $(t_test_array_SOURCES) $(t_test_base64_SOURCES) \
+ $(t_test_buffer_SOURCES) $(t_test_burl_SOURCES) \
+ $(t_test_configfile_SOURCES) $(t_test_keyvalue_SOURCES) \
+ $(t_test_mod_access_SOURCES) $(t_test_mod_evhost_SOURCES) \
+ $(t_test_mod_simple_vhost_SOURCES) $(t_test_request_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ATTR_LIB = @ATTR_LIB@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZ_LIB = @BZ_LIB@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CRYPTO_LIB = @CRYPTO_LIB@
+CRYPT_LIB = @CRYPT_LIB@
+CYGPATH_W = @CYGPATH_W@
+DBI_CFLAGS = @DBI_CFLAGS@
+DBI_LIBS = @DBI_LIBS@
+DEFS = @DEFS@ -DHAVE_VERSIONSTAMP_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DL_LIB = @DL_LIB@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FAM_CFLAGS = @FAM_CFLAGS@
+FAM_LIBS = @FAM_LIBS@
+FGREP = @FGREP@
+GDBM_LIB = @GDBM_LIB@
+GEOIP_LIB = @GEOIP_LIB@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KRB5_LIB = @KRB5_LIB@
+LBER_LIB = @LBER_LIB@
+LD = @LD@
+LDAP_LIB = @LDAP_LIB@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBEV_CFLAGS = @LIBEV_CFLAGS@
+LIBEV_LIBS = @LIBEV_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MEMCACHED_LIB = @MEMCACHED_LIB@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_CONFIG = @MYSQL_CONFIG@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIB = @PAM_LIB@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCRECONFIG = @PCRECONFIG@
+PCRE_LIB = @PCRE_LIB@
+PGSQL_CONFIG = @PGSQL_CONFIG@
+PGSQL_INCLUDE = @PGSQL_INCLUDE@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SASL_CFLAGS = @SASL_CFLAGS@
+SASL_LIBS = @SASL_LIBS@
+SED = @SED@
+SENDFILE_LIB = @SENDFILE_LIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CFLAGS = @SQLITE_CFLAGS@
+SQLITE_LIBS = @SQLITE_LIBS@
+SSL_LIB = @SSL_LIB@
+STRIP = @STRIP@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+XML_CFLAGS = @XML_CFLAGS@
+XML_LIBS = @XML_LIBS@
+Z_LIB = @Z_LIB@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CFLAGS = $(FAM_CFLAGS) $(LIBUNWIND_CFLAGS)
+LEMON = $(top_builddir)/src/lemon$(BUILD_EXEEXT)
+TESTS = \
+ t/test_array$(EXEEXT) \
+ t/test_buffer$(EXEEXT) \
+ t/test_burl$(EXEEXT) \
+ t/test_base64$(EXEEXT) \
+ t/test_configfile$(EXEEXT) \
+ t/test_keyvalue$(EXEEXT) \
+ t/test_mod_access$(EXEEXT) \
+ t/test_mod_evhost$(EXEEXT) \
+ t/test_mod_simple_vhost$(EXEEXT) \
+ t/test_request$(EXEEXT)
+
+lighttpd_angel_SOURCES = lighttpd-angel.c
+BUILT_SOURCES = parsers versionstamp
+MAINTAINERCLEANFILES = configparser.c configparser.h mod_ssi_exprparser.c mod_ssi_exprparser.h
+CLEANFILES = versionstamp.h versionstamp.h.tmp lemon$(BUILD_EXEEXT)
+common_src = base64.c buffer.c burl.c log.c \
+ http_header.c http_kv.c keyvalue.c chunk.c \
+ http_chunk.c stream.c fdevent.c gw_backend.c \
+ stat_cache.c plugin.c joblist.c etag.c array.c \
+ data_string.c data_array.c \
+ data_integer.c algo_sha1.c md5.c \
+ vector.c \
+ fdevent_select.c fdevent_libev.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
+ data_config.c \
+ crc32.c \
+ connections-glue.c \
+ configfile-glue.c \
+ http-header-glue.c \
+ http_auth.c \
+ http_vhostdb.c \
+ rand.c \
+ request.c \
+ sock_addr.c \
+ splaytree.c \
+ safe_memclear.c
+
+src = server.c response.c connections.c inet_ntop_cache.c network.c \
+ network_write.c configfile.c configparser.c $(am__append_2)
+
+#lib_LTLIBRARIES += mod_httptls.la
+#mod_httptls_la_SOURCES = mod_httptls.c
+#mod_httptls_la_LDFLAGS = $(common_module_ldflags)
+#mod_httptls_la_LIBADD = $(common_libadd)
+lib_LTLIBRARIES = $(am__append_1) mod_flv_streaming.la $(am__append_3) \
+ mod_evasive.la mod_webdav.la $(am__append_4) $(am__append_5) \
+ mod_vhostdb.la $(am__append_6) $(am__append_7) $(am__append_8) \
+ $(am__append_9) mod_cgi.la mod_scgi.la mod_staticfile.la \
+ mod_dirlisting.la mod_indexfile.la mod_setenv.la mod_alias.la \
+ mod_userdir.la mod_rrdtool.la mod_usertrack.la mod_proxy.la \
+ mod_sockproxy.la mod_ssi.la mod_secdownload.la mod_expire.la \
+ mod_evhost.la mod_simple_vhost.la mod_fastcgi.la \
+ mod_extforward.la mod_access.la mod_compress.la mod_deflate.la \
+ mod_auth.la mod_authn_file.la $(am__append_10) \
+ $(am__append_11) $(am__append_12) $(am__append_13) \
+ $(am__append_14) $(am__append_15) mod_rewrite.la \
+ mod_redirect.la mod_status.la mod_accesslog.la \
+ mod_uploadprogress.la mod_wstunnel.la
+@NO_RDYNAMIC_FALSE@common_ldflags = -avoid-version
+
+# if the linker doesn't allow referencing symbols of the binary
+# we have to put everything into a shared-lib and link it into
+# everything
+@NO_RDYNAMIC_TRUE@common_ldflags = -avoid-version -no-undefined
+@NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src)
+@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) $(LIBEV_CFLAGS)
+@NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = $(common_ldflags)
+@NO_RDYNAMIC_TRUE@liblightcomp_la_LIBADD = $(PCRE_LIB) $(CRYPTO_LIB) $(FAM_LIBS) $(LIBEV_LIBS) $(ATTR_LIB)
+@NO_RDYNAMIC_FALSE@common_libadd =
+@NO_RDYNAMIC_TRUE@common_libadd = liblightcomp.la
+common_module_ldflags = -module -export-dynamic $(common_ldflags)
+mod_flv_streaming_la_SOURCES = mod_flv_streaming.c
+mod_flv_streaming_la_LDFLAGS = $(common_module_ldflags)
+mod_flv_streaming_la_LIBADD = $(common_libadd)
+@BUILD_WITH_GEOIP_TRUE@mod_geoip_la_SOURCES = mod_geoip.c
+@BUILD_WITH_GEOIP_TRUE@mod_geoip_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_GEOIP_TRUE@mod_geoip_la_LIBADD = $(common_libadd) $(GEOIP_LIB)
+mod_evasive_la_SOURCES = mod_evasive.c
+mod_evasive_la_LDFLAGS = $(common_module_ldflags)
+mod_evasive_la_LIBADD = $(common_libadd)
+mod_webdav_la_SOURCES = mod_webdav.c
+mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
+mod_webdav_la_LDFLAGS = $(common_module_ldflags)
+mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS)
+@BUILD_WITH_LUA_TRUE@mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c
+@BUILD_WITH_LUA_TRUE@mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
+@BUILD_WITH_LUA_TRUE@mod_magnet_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_LUA_TRUE@mod_magnet_la_LIBADD = $(common_libadd) $(LUA_LIBS) -lm
+@BUILD_WITH_LUA_TRUE@mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
+@BUILD_WITH_LUA_TRUE@mod_cml_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
+@BUILD_WITH_LUA_TRUE@mod_cml_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_LUA_TRUE@mod_cml_la_LIBADD = $(MEMCACHED_LIB) $(common_libadd) $(LUA_LIBS) -lm
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@mod_trigger_b4_dl_la_SOURCES = mod_trigger_b4_dl.c
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@mod_trigger_b4_dl_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_MOD_TRIGGER_B4_DL_TRUE@mod_trigger_b4_dl_la_LIBADD = $(GDBM_LIB) $(MEMCACHED_LIB) $(PCRE_LIB) $(common_libadd)
+mod_vhostdb_la_SOURCES = mod_vhostdb.c
+mod_vhostdb_la_LDFLAGS = $(common_module_ldflags)
+mod_vhostdb_la_LIBADD = $(common_libadd)
+@BUILD_WITH_LDAP_TRUE@mod_vhostdb_ldap_la_SOURCES = mod_vhostdb_ldap.c
+@BUILD_WITH_LDAP_TRUE@mod_vhostdb_ldap_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_LDAP_TRUE@mod_vhostdb_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
+@BUILD_WITH_MYSQL_TRUE@mod_mysql_vhost_la_SOURCES = mod_mysql_vhost.c
+@BUILD_WITH_MYSQL_TRUE@mod_mysql_vhost_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_MYSQL_TRUE@mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
+@BUILD_WITH_MYSQL_TRUE@mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_CFLAGS)
+@BUILD_WITH_MYSQL_TRUE@mod_vhostdb_mysql_la_SOURCES = mod_vhostdb_mysql.c
+@BUILD_WITH_MYSQL_TRUE@mod_vhostdb_mysql_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_MYSQL_TRUE@mod_vhostdb_mysql_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
+@BUILD_WITH_MYSQL_TRUE@mod_vhostdb_mysql_la_CPPFLAGS = $(MYSQL_CFLAGS)
+@BUILD_WITH_PGSQL_TRUE@mod_vhostdb_pgsql_la_SOURCES = mod_vhostdb_pgsql.c
+@BUILD_WITH_PGSQL_TRUE@mod_vhostdb_pgsql_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_PGSQL_TRUE@mod_vhostdb_pgsql_la_LIBADD = $(PGSQL_LIBS) $(common_libadd)
+@BUILD_WITH_PGSQL_TRUE@mod_vhostdb_pgsql_la_CPPFLAGS = $(PGSQL_INCLUDE)
+@BUILD_WITH_DBI_TRUE@mod_vhostdb_dbi_la_SOURCES = mod_vhostdb_dbi.c
+@BUILD_WITH_DBI_TRUE@mod_vhostdb_dbi_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_DBI_TRUE@mod_vhostdb_dbi_la_LIBADD = $(DBI_LIBS) $(common_libadd)
+@BUILD_WITH_DBI_TRUE@mod_vhostdb_dbi_la_CPPFLAGS = $(DBI_CFLAGS)
+mod_cgi_la_SOURCES = mod_cgi.c
+mod_cgi_la_LDFLAGS = $(common_module_ldflags)
+mod_cgi_la_LIBADD = $(common_libadd)
+mod_scgi_la_SOURCES = mod_scgi.c
+mod_scgi_la_LDFLAGS = $(common_module_ldflags)
+mod_scgi_la_LIBADD = $(common_libadd)
+mod_staticfile_la_SOURCES = mod_staticfile.c
+mod_staticfile_la_LDFLAGS = $(common_module_ldflags)
+mod_staticfile_la_LIBADD = $(common_libadd)
+mod_dirlisting_la_SOURCES = mod_dirlisting.c
+mod_dirlisting_la_LDFLAGS = $(common_module_ldflags)
+mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB)
+mod_indexfile_la_SOURCES = mod_indexfile.c
+mod_indexfile_la_LDFLAGS = $(common_module_ldflags)
+mod_indexfile_la_LIBADD = $(common_libadd)
+mod_setenv_la_SOURCES = mod_setenv.c
+mod_setenv_la_LDFLAGS = $(common_module_ldflags)
+mod_setenv_la_LIBADD = $(common_libadd)
+mod_alias_la_SOURCES = mod_alias.c
+mod_alias_la_LDFLAGS = $(common_module_ldflags)
+mod_alias_la_LIBADD = $(common_libadd)
+mod_userdir_la_SOURCES = mod_userdir.c
+mod_userdir_la_LDFLAGS = $(common_module_ldflags)
+mod_userdir_la_LIBADD = $(common_libadd)
+mod_rrdtool_la_SOURCES = mod_rrdtool.c
+mod_rrdtool_la_LDFLAGS = $(common_module_ldflags)
+mod_rrdtool_la_LIBADD = $(common_libadd)
+mod_usertrack_la_SOURCES = mod_usertrack.c
+mod_usertrack_la_LDFLAGS = $(common_module_ldflags)
+mod_usertrack_la_LIBADD = $(common_libadd)
+mod_proxy_la_SOURCES = mod_proxy.c
+mod_proxy_la_LDFLAGS = $(common_module_ldflags)
+mod_proxy_la_LIBADD = $(common_libadd)
+mod_sockproxy_la_SOURCES = mod_sockproxy.c
+mod_sockproxy_la_LDFLAGS = $(common_module_ldflags)
+mod_sockproxy_la_LIBADD = $(common_libadd)
+mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
+mod_ssi_la_LDFLAGS = $(common_module_ldflags)
+mod_ssi_la_LIBADD = $(common_libadd)
+mod_secdownload_la_SOURCES = mod_secdownload.c
+mod_secdownload_la_LDFLAGS = $(common_module_ldflags)
+mod_secdownload_la_LIBADD = $(common_libadd) $(CRYPTO_LIB)
+mod_expire_la_SOURCES = mod_expire.c
+mod_expire_la_LDFLAGS = $(common_module_ldflags)
+mod_expire_la_LIBADD = $(common_libadd)
+mod_evhost_la_SOURCES = mod_evhost.c
+mod_evhost_la_LDFLAGS = $(common_module_ldflags)
+mod_evhost_la_LIBADD = $(common_libadd)
+mod_simple_vhost_la_SOURCES = mod_simple_vhost.c
+mod_simple_vhost_la_LDFLAGS = $(common_module_ldflags)
+mod_simple_vhost_la_LIBADD = $(common_libadd)
+mod_fastcgi_la_SOURCES = mod_fastcgi.c
+mod_fastcgi_la_LDFLAGS = $(common_module_ldflags)
+mod_fastcgi_la_LIBADD = $(common_libadd)
+mod_extforward_la_SOURCES = mod_extforward.c
+mod_extforward_la_LDFLAGS = $(common_module_ldflags)
+mod_extforward_la_LIBADD = $(common_libadd)
+mod_access_la_SOURCES = mod_access.c
+mod_access_la_LDFLAGS = $(common_module_ldflags)
+mod_access_la_LIBADD = $(common_libadd)
+mod_compress_la_SOURCES = mod_compress.c
+mod_compress_la_LDFLAGS = $(common_module_ldflags)
+mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
+mod_deflate_la_SOURCES = mod_deflate.c
+mod_deflate_la_LDFLAGS = $(common_module_ldflags)
+mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
+mod_auth_la_SOURCES = mod_auth.c
+mod_auth_la_LDFLAGS = $(common_module_ldflags)
+mod_auth_la_LIBADD = $(common_libadd)
+mod_authn_file_la_SOURCES = mod_authn_file.c
+mod_authn_file_la_LDFLAGS = $(common_module_ldflags)
+mod_authn_file_la_LIBADD = $(CRYPT_LIB) $(CRYPTO_LIB) $(common_libadd)
+@BUILD_WITH_KRB5_TRUE@mod_authn_gssapi_la_SOURCES = mod_authn_gssapi.c
+@BUILD_WITH_KRB5_TRUE@mod_authn_gssapi_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_KRB5_TRUE@mod_authn_gssapi_la_LIBADD = $(KRB5_LIB) $(common_libadd)
+@BUILD_WITH_LDAP_TRUE@mod_authn_ldap_la_SOURCES = mod_authn_ldap.c
+@BUILD_WITH_LDAP_TRUE@mod_authn_ldap_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_LDAP_TRUE@mod_authn_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
+@BUILD_WITH_PAM_TRUE@mod_authn_pam_la_SOURCES = mod_authn_pam.c
+@BUILD_WITH_PAM_TRUE@mod_authn_pam_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_PAM_TRUE@mod_authn_pam_la_LIBADD = $(PAM_LIB) $(common_libadd)
+@BUILD_WITH_MYSQL_TRUE@mod_authn_mysql_la_SOURCES = mod_authn_mysql.c
+@BUILD_WITH_MYSQL_TRUE@mod_authn_mysql_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_MYSQL_TRUE@mod_authn_mysql_la_LIBADD = $(CRYPT_LIB) $(MYSQL_LIBS) $(common_libadd)
+@BUILD_WITH_MYSQL_TRUE@mod_authn_mysql_la_CPPFLAGS = $(MYSQL_CFLAGS)
+@BUILD_WITH_SASL_TRUE@mod_authn_sasl_la_SOURCES = mod_authn_sasl.c
+@BUILD_WITH_SASL_TRUE@mod_authn_sasl_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_SASL_TRUE@mod_authn_sasl_la_LIBADD = $(SASL_LIBS) $(common_libadd)
+@BUILD_WITH_SASL_TRUE@mod_authn_sasl_la_CPPFLAGS = $(SASL_CFLAGS)
+@BUILD_WITH_OPENSSL_TRUE@mod_openssl_la_SOURCES = mod_openssl.c
+@BUILD_WITH_OPENSSL_TRUE@mod_openssl_la_LDFLAGS = $(common_module_ldflags)
+@BUILD_WITH_OPENSSL_TRUE@mod_openssl_la_LIBADD = $(SSL_LIB) $(common_libadd)
+mod_rewrite_la_SOURCES = mod_rewrite.c
+mod_rewrite_la_LDFLAGS = $(common_module_ldflags)
+mod_rewrite_la_LIBADD = $(PCRE_LIB) $(common_libadd)
+mod_redirect_la_SOURCES = mod_redirect.c
+mod_redirect_la_LDFLAGS = $(common_module_ldflags)
+mod_redirect_la_LIBADD = $(PCRE_LIB) $(common_libadd)
+mod_status_la_SOURCES = mod_status.c
+mod_status_la_LDFLAGS = $(common_module_ldflags)
+mod_status_la_LIBADD = $(common_libadd)
+mod_accesslog_la_SOURCES = mod_accesslog.c
+mod_accesslog_la_LDFLAGS = $(common_module_ldflags)
+mod_accesslog_la_LIBADD = $(common_libadd)
+mod_uploadprogress_la_SOURCES = mod_uploadprogress.c
+mod_uploadprogress_la_LDFLAGS = $(common_module_ldflags)
+mod_uploadprogress_la_LIBADD = $(common_libadd)
+mod_wstunnel_la_SOURCES = mod_wstunnel.c
+mod_wstunnel_la_LDFLAGS = $(common_module_ldflags)
+mod_wstunnel_la_LIBADD = $(common_libadd) $(CRYPTO_LIB)
+hdr = server.h base64.h buffer.h burl.h network.h log.h http_kv.h keyvalue.h \
+ response.h request.h fastcgi.h chunk.h \
+ first.h settings.h http_chunk.h \
+ algo_sha1.h md5.h http_auth.h http_header.h http_vhostdb.h stream.h \
+ fdevent.h gw_backend.h connections.h base.h base_decls.h stat_cache.h \
+ plugin.h \
+ etag.h joblist.h array.h vector.h crc32.h \
+ fdevent_impl.h network_write.h configfile.h \
+ mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
+ configparser.h mod_ssi_exprparser.h \
+ rand.h \
+ sys-crypto.h sys-endian.h sys-mmap.h sys-socket.h sys-strings.h \
+ mod_cml.h mod_cml_funcs.h \
+ safe_memclear.h sock_addr.h splaytree.h status_counter.h \
+ mod_magnet_cache.h
+
+@LIGHTTPD_STATIC_FALSE@lighttpd_SOURCES = $(src)
+@LIGHTTPD_STATIC_TRUE@lighttpd_SOURCES = $(src) mod_access.c \
+@LIGHTTPD_STATIC_TRUE@ mod_accesslog.c mod_alias.c mod_auth.c \
+@LIGHTTPD_STATIC_TRUE@ mod_authn_file.c mod_cgi.c \
+@LIGHTTPD_STATIC_TRUE@ mod_compress.c mod_deflate.c \
+@LIGHTTPD_STATIC_TRUE@ mod_dirlisting.c mod_evasive.c \
+@LIGHTTPD_STATIC_TRUE@ mod_expire.c mod_extforward.c \
+@LIGHTTPD_STATIC_TRUE@ mod_fastcgi.c mod_flv_streaming.c \
+@LIGHTTPD_STATIC_TRUE@ mod_indexfile.c mod_proxy.c \
+@LIGHTTPD_STATIC_TRUE@ mod_redirect.c mod_rewrite.c \
+@LIGHTTPD_STATIC_TRUE@ mod_rrdtool.c mod_scgi.c \
+@LIGHTTPD_STATIC_TRUE@ mod_secdownload.c mod_setenv.c \
+@LIGHTTPD_STATIC_TRUE@ mod_simple_vhost.c mod_ssi_exprparser.c \
+@LIGHTTPD_STATIC_TRUE@ mod_ssi_expr.c mod_ssi.c \
+@LIGHTTPD_STATIC_TRUE@ mod_staticfile.c mod_status.c \
+@LIGHTTPD_STATIC_TRUE@ mod_uploadprogress.c mod_userdir.c \
+@LIGHTTPD_STATIC_TRUE@ mod_usertrack.c mod_vhostdb.c \
+@LIGHTTPD_STATIC_TRUE@ mod_webdav.c $(am__append_16) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_18) $(am__append_21) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_23) $(am__append_25) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_27) $(am__append_30) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_33) $(am__append_36) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_41)
+@LIGHTTPD_STATIC_FALSE@lighttpd_CPPFLAGS = $(FAM_CFLAGS) $(LIBEV_CFLAGS)
+@LIGHTTPD_STATIC_TRUE@lighttpd_CPPFLAGS = -DLIGHTTPD_STATIC \
+@LIGHTTPD_STATIC_TRUE@ $(XML_CFLAGS) $(SQLITE_CFLAGS) \
+@LIGHTTPD_STATIC_TRUE@ $(FAM_CFLAGS) $(LIBEV_CFLAGS) \
+@LIGHTTPD_STATIC_TRUE@ $(LIBUNWIND_CFLAGS) $(am__append_19) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_28) $(am__append_31) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_34) $(am__append_38)
+@LIGHTTPD_STATIC_FALSE@lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(CRYPTO_LIB) $(FAM_LIBS) $(LIBEV_LIBS) $(LIBUNWIND_LIBS)
+@LIGHTTPD_STATIC_TRUE@lighttpd_LDADD = $(common_libadd) $(CRYPT_LIB) \
+@LIGHTTPD_STATIC_TRUE@ $(CRYPTO_LIB) $(XML_LIBS) $(SQLITE_LIBS) \
+@LIGHTTPD_STATIC_TRUE@ $(UUID_LIBS) $(PCRE_LIB) $(Z_LIB) \
+@LIGHTTPD_STATIC_TRUE@ $(BZ_LIB) $(DL_LIB) $(SENDFILE_LIB) \
+@LIGHTTPD_STATIC_TRUE@ $(ATTR_LIB) $(FAM_LIBS) $(LIBEV_LIBS) \
+@LIGHTTPD_STATIC_TRUE@ $(LIBUNWIND_LIBS) $(am__append_17) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_20) $(am__append_22) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_24) $(am__append_26) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_29) $(am__append_32) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_35) $(am__append_37) \
+@LIGHTTPD_STATIC_TRUE@ $(am__append_39) $(am__append_40)
+@LIGHTTPD_STATIC_FALSE@lighttpd_LDFLAGS = -export-dynamic
+@LIGHTTPD_STATIC_TRUE@lighttpd_LDFLAGS = -export-dynamic
+t_test_array_SOURCES = t/test_array.c array.c data_array.c data_integer.c data_string.c buffer.c
+t_test_array_LDADD = $(LIBUNWIND_LIBS)
+t_test_buffer_SOURCES = t/test_buffer.c buffer.c
+t_test_buffer_LDADD = $(LIBUNWIND_LIBS)
+t_test_base64_SOURCES = t/test_base64.c base64.c buffer.c
+t_test_base64_LDADD = $(LIBUNWIND_LIBS)
+t_test_burl_SOURCES = t/test_burl.c burl.c buffer.c base64.c
+t_test_burl_LDADD = $(LIBUNWIND_LIBS)
+t_test_configfile_SOURCES = t/test_configfile.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_configfile_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+t_test_keyvalue_SOURCES = t/test_keyvalue.c burl.c buffer.c base64.c array.c data_integer.c data_string.c log.c
+t_test_keyvalue_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+t_test_mod_access_SOURCES = t/test_mod_access.c configfile-glue.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_mod_access_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+t_test_mod_evhost_SOURCES = t/test_mod_evhost.c configfile-glue.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_mod_evhost_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+t_test_mod_simple_vhost_SOURCES = t/test_mod_simple_vhost.c configfile-glue.c buffer.c array.c data_config.c data_integer.c data_string.c http_header.c http_kv.c vector.c log.c sock_addr.c
+t_test_mod_simple_vhost_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS)
+t_test_request_SOURCES = t/test_request.c request.c buffer.c array.c data_integer.c data_string.c http_header.c http_kv.c log.c sock_addr.c
+t_test_request_LDADD = $(LIBUNWIND_LIBS)
+noinst_HEADERS = $(hdr)
+EXTRA_DIST = \
+ mod_skeleton.c \
+ configparser.y \
+ mod_ssi_exprparser.y \
+ lemon.c \
+ lempar.c \
+ SConscript \
+ CMakeLists.txt config.h.cmake \
+ meson.build
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liblightcomp.la: $(liblightcomp_la_OBJECTS) $(liblightcomp_la_DEPENDENCIES) $(EXTRA_liblightcomp_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(liblightcomp_la_LINK) $(am_liblightcomp_la_rpath) $(liblightcomp_la_OBJECTS) $(liblightcomp_la_LIBADD) $(LIBS)
+
+mod_access.la: $(mod_access_la_OBJECTS) $(mod_access_la_DEPENDENCIES) $(EXTRA_mod_access_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_access_la_LINK) -rpath $(libdir) $(mod_access_la_OBJECTS) $(mod_access_la_LIBADD) $(LIBS)
+
+mod_accesslog.la: $(mod_accesslog_la_OBJECTS) $(mod_accesslog_la_DEPENDENCIES) $(EXTRA_mod_accesslog_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_accesslog_la_LINK) -rpath $(libdir) $(mod_accesslog_la_OBJECTS) $(mod_accesslog_la_LIBADD) $(LIBS)
+
+mod_alias.la: $(mod_alias_la_OBJECTS) $(mod_alias_la_DEPENDENCIES) $(EXTRA_mod_alias_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_alias_la_LINK) -rpath $(libdir) $(mod_alias_la_OBJECTS) $(mod_alias_la_LIBADD) $(LIBS)
+
+mod_auth.la: $(mod_auth_la_OBJECTS) $(mod_auth_la_DEPENDENCIES) $(EXTRA_mod_auth_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_auth_la_LINK) -rpath $(libdir) $(mod_auth_la_OBJECTS) $(mod_auth_la_LIBADD) $(LIBS)
+
+mod_authn_file.la: $(mod_authn_file_la_OBJECTS) $(mod_authn_file_la_DEPENDENCIES) $(EXTRA_mod_authn_file_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_authn_file_la_LINK) -rpath $(libdir) $(mod_authn_file_la_OBJECTS) $(mod_authn_file_la_LIBADD) $(LIBS)
+
+mod_authn_gssapi.la: $(mod_authn_gssapi_la_OBJECTS) $(mod_authn_gssapi_la_DEPENDENCIES) $(EXTRA_mod_authn_gssapi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_authn_gssapi_la_LINK) $(am_mod_authn_gssapi_la_rpath) $(mod_authn_gssapi_la_OBJECTS) $(mod_authn_gssapi_la_LIBADD) $(LIBS)
+
+mod_authn_ldap.la: $(mod_authn_ldap_la_OBJECTS) $(mod_authn_ldap_la_DEPENDENCIES) $(EXTRA_mod_authn_ldap_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_authn_ldap_la_LINK) $(am_mod_authn_ldap_la_rpath) $(mod_authn_ldap_la_OBJECTS) $(mod_authn_ldap_la_LIBADD) $(LIBS)
+
+mod_authn_mysql.la: $(mod_authn_mysql_la_OBJECTS) $(mod_authn_mysql_la_DEPENDENCIES) $(EXTRA_mod_authn_mysql_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_authn_mysql_la_LINK) $(am_mod_authn_mysql_la_rpath) $(mod_authn_mysql_la_OBJECTS) $(mod_authn_mysql_la_LIBADD) $(LIBS)
+
+mod_authn_pam.la: $(mod_authn_pam_la_OBJECTS) $(mod_authn_pam_la_DEPENDENCIES) $(EXTRA_mod_authn_pam_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_authn_pam_la_LINK) $(am_mod_authn_pam_la_rpath) $(mod_authn_pam_la_OBJECTS) $(mod_authn_pam_la_LIBADD) $(LIBS)
+
+mod_authn_sasl.la: $(mod_authn_sasl_la_OBJECTS) $(mod_authn_sasl_la_DEPENDENCIES) $(EXTRA_mod_authn_sasl_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_authn_sasl_la_LINK) $(am_mod_authn_sasl_la_rpath) $(mod_authn_sasl_la_OBJECTS) $(mod_authn_sasl_la_LIBADD) $(LIBS)
+
+mod_cgi.la: $(mod_cgi_la_OBJECTS) $(mod_cgi_la_DEPENDENCIES) $(EXTRA_mod_cgi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_cgi_la_LINK) -rpath $(libdir) $(mod_cgi_la_OBJECTS) $(mod_cgi_la_LIBADD) $(LIBS)
+
+mod_cml.la: $(mod_cml_la_OBJECTS) $(mod_cml_la_DEPENDENCIES) $(EXTRA_mod_cml_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_cml_la_LINK) $(am_mod_cml_la_rpath) $(mod_cml_la_OBJECTS) $(mod_cml_la_LIBADD) $(LIBS)
+
+mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES) $(EXTRA_mod_compress_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_compress_la_LINK) -rpath $(libdir) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
+
+mod_deflate.la: $(mod_deflate_la_OBJECTS) $(mod_deflate_la_DEPENDENCIES) $(EXTRA_mod_deflate_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_deflate_la_LINK) -rpath $(libdir) $(mod_deflate_la_OBJECTS) $(mod_deflate_la_LIBADD) $(LIBS)
+
+mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES) $(EXTRA_mod_dirlisting_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_dirlisting_la_LINK) -rpath $(libdir) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
+
+mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES) $(EXTRA_mod_evasive_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_evasive_la_LINK) -rpath $(libdir) $(mod_evasive_la_OBJECTS) $(mod_evasive_la_LIBADD) $(LIBS)
+
+mod_evhost.la: $(mod_evhost_la_OBJECTS) $(mod_evhost_la_DEPENDENCIES) $(EXTRA_mod_evhost_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_evhost_la_LINK) -rpath $(libdir) $(mod_evhost_la_OBJECTS) $(mod_evhost_la_LIBADD) $(LIBS)
+
+mod_expire.la: $(mod_expire_la_OBJECTS) $(mod_expire_la_DEPENDENCIES) $(EXTRA_mod_expire_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_expire_la_LINK) -rpath $(libdir) $(mod_expire_la_OBJECTS) $(mod_expire_la_LIBADD) $(LIBS)
+
+mod_extforward.la: $(mod_extforward_la_OBJECTS) $(mod_extforward_la_DEPENDENCIES) $(EXTRA_mod_extforward_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_extforward_la_LINK) -rpath $(libdir) $(mod_extforward_la_OBJECTS) $(mod_extforward_la_LIBADD) $(LIBS)
+
+mod_fastcgi.la: $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_DEPENDENCIES) $(EXTRA_mod_fastcgi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_fastcgi_la_LINK) -rpath $(libdir) $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_LIBADD) $(LIBS)
+
+mod_flv_streaming.la: $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_DEPENDENCIES) $(EXTRA_mod_flv_streaming_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_flv_streaming_la_LINK) -rpath $(libdir) $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_LIBADD) $(LIBS)
+
+mod_geoip.la: $(mod_geoip_la_OBJECTS) $(mod_geoip_la_DEPENDENCIES) $(EXTRA_mod_geoip_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_geoip_la_LINK) $(am_mod_geoip_la_rpath) $(mod_geoip_la_OBJECTS) $(mod_geoip_la_LIBADD) $(LIBS)
+
+mod_indexfile.la: $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_DEPENDENCIES) $(EXTRA_mod_indexfile_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_indexfile_la_LINK) -rpath $(libdir) $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_LIBADD) $(LIBS)
+
+mod_magnet.la: $(mod_magnet_la_OBJECTS) $(mod_magnet_la_DEPENDENCIES) $(EXTRA_mod_magnet_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_magnet_la_LINK) $(am_mod_magnet_la_rpath) $(mod_magnet_la_OBJECTS) $(mod_magnet_la_LIBADD) $(LIBS)
+
+mod_mysql_vhost.la: $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_DEPENDENCIES) $(EXTRA_mod_mysql_vhost_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_mysql_vhost_la_LINK) $(am_mod_mysql_vhost_la_rpath) $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_LIBADD) $(LIBS)
+
+mod_openssl.la: $(mod_openssl_la_OBJECTS) $(mod_openssl_la_DEPENDENCIES) $(EXTRA_mod_openssl_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_openssl_la_LINK) $(am_mod_openssl_la_rpath) $(mod_openssl_la_OBJECTS) $(mod_openssl_la_LIBADD) $(LIBS)
+
+mod_proxy.la: $(mod_proxy_la_OBJECTS) $(mod_proxy_la_DEPENDENCIES) $(EXTRA_mod_proxy_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_proxy_la_LINK) -rpath $(libdir) $(mod_proxy_la_OBJECTS) $(mod_proxy_la_LIBADD) $(LIBS)
+
+mod_redirect.la: $(mod_redirect_la_OBJECTS) $(mod_redirect_la_DEPENDENCIES) $(EXTRA_mod_redirect_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_redirect_la_LINK) -rpath $(libdir) $(mod_redirect_la_OBJECTS) $(mod_redirect_la_LIBADD) $(LIBS)
+
+mod_rewrite.la: $(mod_rewrite_la_OBJECTS) $(mod_rewrite_la_DEPENDENCIES) $(EXTRA_mod_rewrite_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_rewrite_la_LINK) -rpath $(libdir) $(mod_rewrite_la_OBJECTS) $(mod_rewrite_la_LIBADD) $(LIBS)
+
+mod_rrdtool.la: $(mod_rrdtool_la_OBJECTS) $(mod_rrdtool_la_DEPENDENCIES) $(EXTRA_mod_rrdtool_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_rrdtool_la_LINK) -rpath $(libdir) $(mod_rrdtool_la_OBJECTS) $(mod_rrdtool_la_LIBADD) $(LIBS)
+
+mod_scgi.la: $(mod_scgi_la_OBJECTS) $(mod_scgi_la_DEPENDENCIES) $(EXTRA_mod_scgi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_scgi_la_LINK) -rpath $(libdir) $(mod_scgi_la_OBJECTS) $(mod_scgi_la_LIBADD) $(LIBS)
+
+mod_secdownload.la: $(mod_secdownload_la_OBJECTS) $(mod_secdownload_la_DEPENDENCIES) $(EXTRA_mod_secdownload_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_secdownload_la_LINK) -rpath $(libdir) $(mod_secdownload_la_OBJECTS) $(mod_secdownload_la_LIBADD) $(LIBS)
+
+mod_setenv.la: $(mod_setenv_la_OBJECTS) $(mod_setenv_la_DEPENDENCIES) $(EXTRA_mod_setenv_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_setenv_la_LINK) -rpath $(libdir) $(mod_setenv_la_OBJECTS) $(mod_setenv_la_LIBADD) $(LIBS)
+
+mod_simple_vhost.la: $(mod_simple_vhost_la_OBJECTS) $(mod_simple_vhost_la_DEPENDENCIES) $(EXTRA_mod_simple_vhost_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_simple_vhost_la_LINK) -rpath $(libdir) $(mod_simple_vhost_la_OBJECTS) $(mod_simple_vhost_la_LIBADD) $(LIBS)
+
+mod_sockproxy.la: $(mod_sockproxy_la_OBJECTS) $(mod_sockproxy_la_DEPENDENCIES) $(EXTRA_mod_sockproxy_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_sockproxy_la_LINK) -rpath $(libdir) $(mod_sockproxy_la_OBJECTS) $(mod_sockproxy_la_LIBADD) $(LIBS)
+
+mod_ssi.la: $(mod_ssi_la_OBJECTS) $(mod_ssi_la_DEPENDENCIES) $(EXTRA_mod_ssi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_ssi_la_LINK) -rpath $(libdir) $(mod_ssi_la_OBJECTS) $(mod_ssi_la_LIBADD) $(LIBS)
+
+mod_staticfile.la: $(mod_staticfile_la_OBJECTS) $(mod_staticfile_la_DEPENDENCIES) $(EXTRA_mod_staticfile_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_staticfile_la_LINK) -rpath $(libdir) $(mod_staticfile_la_OBJECTS) $(mod_staticfile_la_LIBADD) $(LIBS)
+
+mod_status.la: $(mod_status_la_OBJECTS) $(mod_status_la_DEPENDENCIES) $(EXTRA_mod_status_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_status_la_LINK) -rpath $(libdir) $(mod_status_la_OBJECTS) $(mod_status_la_LIBADD) $(LIBS)
+
+mod_trigger_b4_dl.la: $(mod_trigger_b4_dl_la_OBJECTS) $(mod_trigger_b4_dl_la_DEPENDENCIES) $(EXTRA_mod_trigger_b4_dl_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_trigger_b4_dl_la_LINK) $(am_mod_trigger_b4_dl_la_rpath) $(mod_trigger_b4_dl_la_OBJECTS) $(mod_trigger_b4_dl_la_LIBADD) $(LIBS)
+
+mod_uploadprogress.la: $(mod_uploadprogress_la_OBJECTS) $(mod_uploadprogress_la_DEPENDENCIES) $(EXTRA_mod_uploadprogress_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_uploadprogress_la_LINK) -rpath $(libdir) $(mod_uploadprogress_la_OBJECTS) $(mod_uploadprogress_la_LIBADD) $(LIBS)
+
+mod_userdir.la: $(mod_userdir_la_OBJECTS) $(mod_userdir_la_DEPENDENCIES) $(EXTRA_mod_userdir_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_userdir_la_LINK) -rpath $(libdir) $(mod_userdir_la_OBJECTS) $(mod_userdir_la_LIBADD) $(LIBS)
+
+mod_usertrack.la: $(mod_usertrack_la_OBJECTS) $(mod_usertrack_la_DEPENDENCIES) $(EXTRA_mod_usertrack_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_usertrack_la_LINK) -rpath $(libdir) $(mod_usertrack_la_OBJECTS) $(mod_usertrack_la_LIBADD) $(LIBS)
+
+mod_vhostdb.la: $(mod_vhostdb_la_OBJECTS) $(mod_vhostdb_la_DEPENDENCIES) $(EXTRA_mod_vhostdb_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_vhostdb_la_LINK) -rpath $(libdir) $(mod_vhostdb_la_OBJECTS) $(mod_vhostdb_la_LIBADD) $(LIBS)
+
+mod_vhostdb_dbi.la: $(mod_vhostdb_dbi_la_OBJECTS) $(mod_vhostdb_dbi_la_DEPENDENCIES) $(EXTRA_mod_vhostdb_dbi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_vhostdb_dbi_la_LINK) $(am_mod_vhostdb_dbi_la_rpath) $(mod_vhostdb_dbi_la_OBJECTS) $(mod_vhostdb_dbi_la_LIBADD) $(LIBS)
+
+mod_vhostdb_ldap.la: $(mod_vhostdb_ldap_la_OBJECTS) $(mod_vhostdb_ldap_la_DEPENDENCIES) $(EXTRA_mod_vhostdb_ldap_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_vhostdb_ldap_la_LINK) $(am_mod_vhostdb_ldap_la_rpath) $(mod_vhostdb_ldap_la_OBJECTS) $(mod_vhostdb_ldap_la_LIBADD) $(LIBS)
+
+mod_vhostdb_mysql.la: $(mod_vhostdb_mysql_la_OBJECTS) $(mod_vhostdb_mysql_la_DEPENDENCIES) $(EXTRA_mod_vhostdb_mysql_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_vhostdb_mysql_la_LINK) $(am_mod_vhostdb_mysql_la_rpath) $(mod_vhostdb_mysql_la_OBJECTS) $(mod_vhostdb_mysql_la_LIBADD) $(LIBS)
+
+mod_vhostdb_pgsql.la: $(mod_vhostdb_pgsql_la_OBJECTS) $(mod_vhostdb_pgsql_la_DEPENDENCIES) $(EXTRA_mod_vhostdb_pgsql_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_vhostdb_pgsql_la_LINK) $(am_mod_vhostdb_pgsql_la_rpath) $(mod_vhostdb_pgsql_la_OBJECTS) $(mod_vhostdb_pgsql_la_LIBADD) $(LIBS)
+
+mod_webdav.la: $(mod_webdav_la_OBJECTS) $(mod_webdav_la_DEPENDENCIES) $(EXTRA_mod_webdav_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_webdav_la_LINK) -rpath $(libdir) $(mod_webdav_la_OBJECTS) $(mod_webdav_la_LIBADD) $(LIBS)
+
+mod_wstunnel.la: $(mod_wstunnel_la_OBJECTS) $(mod_wstunnel_la_DEPENDENCIES) $(EXTRA_mod_wstunnel_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_wstunnel_la_LINK) -rpath $(libdir) $(mod_wstunnel_la_OBJECTS) $(mod_wstunnel_la_LIBADD) $(LIBS)
+
+lighttpd$(EXEEXT): $(lighttpd_OBJECTS) $(lighttpd_DEPENDENCIES) $(EXTRA_lighttpd_DEPENDENCIES)
+ @rm -f lighttpd$(EXEEXT)
+ $(AM_V_CCLD)$(lighttpd_LINK) $(lighttpd_OBJECTS) $(lighttpd_LDADD) $(LIBS)
+
+lighttpd-angel$(EXEEXT): $(lighttpd_angel_OBJECTS) $(lighttpd_angel_DEPENDENCIES) $(EXTRA_lighttpd_angel_DEPENDENCIES)
+ @rm -f lighttpd-angel$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lighttpd_angel_OBJECTS) $(lighttpd_angel_LDADD) $(LIBS)
+t/$(am__dirstamp):
+ @$(MKDIR_P) t
+ @: > t/$(am__dirstamp)
+t/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) t/$(DEPDIR)
+ @: > t/$(DEPDIR)/$(am__dirstamp)
+t/test_array.$(OBJEXT): t/$(am__dirstamp) t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_array$(EXEEXT): $(t_test_array_OBJECTS) $(t_test_array_DEPENDENCIES) $(EXTRA_t_test_array_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_array$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_array_OBJECTS) $(t_test_array_LDADD) $(LIBS)
+t/test_base64.$(OBJEXT): t/$(am__dirstamp) t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_base64$(EXEEXT): $(t_test_base64_OBJECTS) $(t_test_base64_DEPENDENCIES) $(EXTRA_t_test_base64_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_base64$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_base64_OBJECTS) $(t_test_base64_LDADD) $(LIBS)
+t/test_buffer.$(OBJEXT): t/$(am__dirstamp) t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_buffer$(EXEEXT): $(t_test_buffer_OBJECTS) $(t_test_buffer_DEPENDENCIES) $(EXTRA_t_test_buffer_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_buffer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_buffer_OBJECTS) $(t_test_buffer_LDADD) $(LIBS)
+t/test_burl.$(OBJEXT): t/$(am__dirstamp) t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_burl$(EXEEXT): $(t_test_burl_OBJECTS) $(t_test_burl_DEPENDENCIES) $(EXTRA_t_test_burl_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_burl$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_burl_OBJECTS) $(t_test_burl_LDADD) $(LIBS)
+t/test_configfile.$(OBJEXT): t/$(am__dirstamp) \
+ t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_configfile$(EXEEXT): $(t_test_configfile_OBJECTS) $(t_test_configfile_DEPENDENCIES) $(EXTRA_t_test_configfile_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_configfile$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_configfile_OBJECTS) $(t_test_configfile_LDADD) $(LIBS)
+t/test_keyvalue.$(OBJEXT): t/$(am__dirstamp) \
+ t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_keyvalue$(EXEEXT): $(t_test_keyvalue_OBJECTS) $(t_test_keyvalue_DEPENDENCIES) $(EXTRA_t_test_keyvalue_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_keyvalue$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_keyvalue_OBJECTS) $(t_test_keyvalue_LDADD) $(LIBS)
+t/test_mod_access.$(OBJEXT): t/$(am__dirstamp) \
+ t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_mod_access$(EXEEXT): $(t_test_mod_access_OBJECTS) $(t_test_mod_access_DEPENDENCIES) $(EXTRA_t_test_mod_access_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_mod_access$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_mod_access_OBJECTS) $(t_test_mod_access_LDADD) $(LIBS)
+t/test_mod_evhost.$(OBJEXT): t/$(am__dirstamp) \
+ t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_mod_evhost$(EXEEXT): $(t_test_mod_evhost_OBJECTS) $(t_test_mod_evhost_DEPENDENCIES) $(EXTRA_t_test_mod_evhost_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_mod_evhost$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_mod_evhost_OBJECTS) $(t_test_mod_evhost_LDADD) $(LIBS)
+t/test_mod_simple_vhost.$(OBJEXT): t/$(am__dirstamp) \
+ t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_mod_simple_vhost$(EXEEXT): $(t_test_mod_simple_vhost_OBJECTS) $(t_test_mod_simple_vhost_DEPENDENCIES) $(EXTRA_t_test_mod_simple_vhost_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_mod_simple_vhost$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_mod_simple_vhost_OBJECTS) $(t_test_mod_simple_vhost_LDADD) $(LIBS)
+t/test_request.$(OBJEXT): t/$(am__dirstamp) \
+ t/$(DEPDIR)/$(am__dirstamp)
+
+t/test_request$(EXEEXT): $(t_test_request_OBJECTS) $(t_test_request_DEPENDENCIES) $(EXTRA_t_test_request_DEPENDENCIES) t/$(am__dirstamp)
+ @rm -f t/test_request$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_test_request_OBJECTS) $(t_test_request_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f t/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/burl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configfile-glue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data_array.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data_config.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data_integer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data_string.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http_header.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http_kv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-algo_sha1.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-array.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-base64.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-buffer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-burl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-chunk.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-configfile-glue.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-connections-glue.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-crc32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-data_array.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-data_config.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-data_integer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-data_string.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-etag.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_libev.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_poll.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_select.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-gw_backend.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http-header-glue.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http_auth.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http_chunk.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http_header.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http_kv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http_vhostdb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-joblist.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-keyvalue.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-log.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-md5.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-rand.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-request.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-safe_memclear.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-sock_addr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-splaytree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-stat_cache.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-stream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-vector.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-algo_sha1.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-angel.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-array.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-base64.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-buffer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-burl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-chunk.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-configfile-glue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-configfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-configparser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-connections-glue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-connections.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-crc32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-data_array.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-data_config.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-data_integer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-data_string.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-etag.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_libev.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_poll.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_select.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-fdevent_solaris_port.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-gw_backend.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-http-header-glue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-http_auth.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-http_chunk.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-http_header.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-http_kv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-http_vhostdb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-inet_ntop_cache.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-joblist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-keyvalue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-log.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-md5.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_access.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_accesslog.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_alias.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_auth.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_authn_file.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_authn_gssapi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_authn_ldap.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_authn_mysql.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_authn_pam.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_cgi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_cml.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_cml_funcs.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_cml_lua.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_compress.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_deflate.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_dirlisting.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_evasive.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_expire.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_extforward.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_fastcgi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_flv_streaming.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_geoip.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_indexfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_magnet.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_magnet_cache.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_mysql_vhost.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_openssl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_proxy.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_redirect.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_rewrite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_rrdtool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_scgi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_secdownload.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_setenv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_simple_vhost.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_ssi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_ssi_expr.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_ssi_exprparser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_staticfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_status.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_trigger_b4_dl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_uploadprogress.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_userdir.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_usertrack.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_vhostdb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_vhostdb_dbi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_vhostdb_ldap.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_vhostdb_mysql.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-mod_webdav.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-network.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-network_write.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-plugin.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-rand.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-request.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-response.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-safe_memclear.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-server.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-sock_addr.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-splaytree.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-stat_cache.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-stream.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-vector.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_access.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_accesslog.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_alias.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_auth.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_authn_file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_authn_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_authn_ldap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_authn_pam.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cgi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_compress.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_deflate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_dirlisting.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_expire.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_extforward.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_fastcgi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_flv_streaming.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_geoip.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_indexfile.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_magnet_la-mod_magnet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_openssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_redirect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_rewrite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_rrdtool.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_scgi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_secdownload.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_setenv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_simple_vhost.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_sockproxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_ssi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_ssi_expr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_ssi_exprparser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_staticfile.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_status.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_trigger_b4_dl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_uploadprogress.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_userdir.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_usertrack.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_vhostdb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_vhostdb_ldap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_webdav_la-mod_webdav.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_wstunnel.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/request.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sock_addr.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_array.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_base64.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_buffer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_burl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_configfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_keyvalue.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_mod_access.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_mod_evhost.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_mod_simple_vhost.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@t/$(DEPDIR)/test_request.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+liblightcomp_la-base64.lo: base64.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-base64.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-base64.Tpo -c -o liblightcomp_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-base64.Tpo $(DEPDIR)/liblightcomp_la-base64.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='base64.c' object='liblightcomp_la-base64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+
+liblightcomp_la-buffer.lo: buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-buffer.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-buffer.Tpo -c -o liblightcomp_la-buffer.lo `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-buffer.Tpo $(DEPDIR)/liblightcomp_la-buffer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='buffer.c' object='liblightcomp_la-buffer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-buffer.lo `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+
+liblightcomp_la-burl.lo: burl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-burl.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-burl.Tpo -c -o liblightcomp_la-burl.lo `test -f 'burl.c' || echo '$(srcdir)/'`burl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-burl.Tpo $(DEPDIR)/liblightcomp_la-burl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='burl.c' object='liblightcomp_la-burl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-burl.lo `test -f 'burl.c' || echo '$(srcdir)/'`burl.c
+
+liblightcomp_la-log.lo: log.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-log.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-log.Tpo -c -o liblightcomp_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-log.Tpo $(DEPDIR)/liblightcomp_la-log.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='liblightcomp_la-log.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c
+
+liblightcomp_la-http_header.lo: http_header.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_header.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http_header.Tpo -c -o liblightcomp_la-http_header.lo `test -f 'http_header.c' || echo '$(srcdir)/'`http_header.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http_header.Tpo $(DEPDIR)/liblightcomp_la-http_header.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_header.c' object='liblightcomp_la-http_header.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_header.lo `test -f 'http_header.c' || echo '$(srcdir)/'`http_header.c
+
+liblightcomp_la-http_kv.lo: http_kv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_kv.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http_kv.Tpo -c -o liblightcomp_la-http_kv.lo `test -f 'http_kv.c' || echo '$(srcdir)/'`http_kv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http_kv.Tpo $(DEPDIR)/liblightcomp_la-http_kv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_kv.c' object='liblightcomp_la-http_kv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_kv.lo `test -f 'http_kv.c' || echo '$(srcdir)/'`http_kv.c
+
+liblightcomp_la-keyvalue.lo: keyvalue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-keyvalue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-keyvalue.Tpo -c -o liblightcomp_la-keyvalue.lo `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-keyvalue.Tpo $(DEPDIR)/liblightcomp_la-keyvalue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='keyvalue.c' object='liblightcomp_la-keyvalue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-keyvalue.lo `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
+
+liblightcomp_la-chunk.lo: chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-chunk.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-chunk.Tpo -c -o liblightcomp_la-chunk.lo `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-chunk.Tpo $(DEPDIR)/liblightcomp_la-chunk.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='chunk.c' object='liblightcomp_la-chunk.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-chunk.lo `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
+
+liblightcomp_la-http_chunk.lo: http_chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_chunk.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http_chunk.Tpo -c -o liblightcomp_la-http_chunk.lo `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http_chunk.Tpo $(DEPDIR)/liblightcomp_la-http_chunk.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_chunk.c' object='liblightcomp_la-http_chunk.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_chunk.lo `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
+
+liblightcomp_la-stream.lo: stream.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-stream.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-stream.Tpo -c -o liblightcomp_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-stream.Tpo $(DEPDIR)/liblightcomp_la-stream.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stream.c' object='liblightcomp_la-stream.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
+
+liblightcomp_la-fdevent.lo: fdevent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent.Tpo -c -o liblightcomp_la-fdevent.lo `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent.Tpo $(DEPDIR)/liblightcomp_la-fdevent.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent.c' object='liblightcomp_la-fdevent.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent.lo `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
+
+liblightcomp_la-gw_backend.lo: gw_backend.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-gw_backend.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-gw_backend.Tpo -c -o liblightcomp_la-gw_backend.lo `test -f 'gw_backend.c' || echo '$(srcdir)/'`gw_backend.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-gw_backend.Tpo $(DEPDIR)/liblightcomp_la-gw_backend.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gw_backend.c' object='liblightcomp_la-gw_backend.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-gw_backend.lo `test -f 'gw_backend.c' || echo '$(srcdir)/'`gw_backend.c
+
+liblightcomp_la-stat_cache.lo: stat_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-stat_cache.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-stat_cache.Tpo -c -o liblightcomp_la-stat_cache.lo `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-stat_cache.Tpo $(DEPDIR)/liblightcomp_la-stat_cache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stat_cache.c' object='liblightcomp_la-stat_cache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-stat_cache.lo `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
+
+liblightcomp_la-plugin.lo: plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-plugin.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-plugin.Tpo -c -o liblightcomp_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-plugin.Tpo $(DEPDIR)/liblightcomp_la-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugin.c' object='liblightcomp_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+
+liblightcomp_la-joblist.lo: joblist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-joblist.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-joblist.Tpo -c -o liblightcomp_la-joblist.lo `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-joblist.Tpo $(DEPDIR)/liblightcomp_la-joblist.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='joblist.c' object='liblightcomp_la-joblist.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-joblist.lo `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
+
+liblightcomp_la-etag.lo: etag.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-etag.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-etag.Tpo -c -o liblightcomp_la-etag.lo `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-etag.Tpo $(DEPDIR)/liblightcomp_la-etag.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='etag.c' object='liblightcomp_la-etag.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-etag.lo `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
+
+liblightcomp_la-array.lo: array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-array.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-array.Tpo -c -o liblightcomp_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-array.Tpo $(DEPDIR)/liblightcomp_la-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='array.c' object='liblightcomp_la-array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+
+liblightcomp_la-data_string.lo: data_string.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_string.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_string.Tpo -c -o liblightcomp_la-data_string.lo `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_string.Tpo $(DEPDIR)/liblightcomp_la-data_string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_string.c' object='liblightcomp_la-data_string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_string.lo `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
+
+liblightcomp_la-data_array.lo: data_array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_array.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_array.Tpo -c -o liblightcomp_la-data_array.lo `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_array.Tpo $(DEPDIR)/liblightcomp_la-data_array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_array.c' object='liblightcomp_la-data_array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_array.lo `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
+
+liblightcomp_la-data_integer.lo: data_integer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_integer.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_integer.Tpo -c -o liblightcomp_la-data_integer.lo `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_integer.Tpo $(DEPDIR)/liblightcomp_la-data_integer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_integer.c' object='liblightcomp_la-data_integer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_integer.lo `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
+
+liblightcomp_la-algo_sha1.lo: algo_sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-algo_sha1.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-algo_sha1.Tpo -c -o liblightcomp_la-algo_sha1.lo `test -f 'algo_sha1.c' || echo '$(srcdir)/'`algo_sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-algo_sha1.Tpo $(DEPDIR)/liblightcomp_la-algo_sha1.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='algo_sha1.c' object='liblightcomp_la-algo_sha1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-algo_sha1.lo `test -f 'algo_sha1.c' || echo '$(srcdir)/'`algo_sha1.c
+
+liblightcomp_la-md5.lo: md5.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-md5.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-md5.Tpo -c -o liblightcomp_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-md5.Tpo $(DEPDIR)/liblightcomp_la-md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md5.c' object='liblightcomp_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+
+liblightcomp_la-vector.lo: vector.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-vector.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-vector.Tpo -c -o liblightcomp_la-vector.lo `test -f 'vector.c' || echo '$(srcdir)/'`vector.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-vector.Tpo $(DEPDIR)/liblightcomp_la-vector.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vector.c' object='liblightcomp_la-vector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-vector.lo `test -f 'vector.c' || echo '$(srcdir)/'`vector.c
+
+liblightcomp_la-fdevent_select.lo: fdevent_select.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_select.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_select.Tpo -c -o liblightcomp_la-fdevent_select.lo `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_select.Tpo $(DEPDIR)/liblightcomp_la-fdevent_select.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_select.c' object='liblightcomp_la-fdevent_select.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_select.lo `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
+
+liblightcomp_la-fdevent_libev.lo: fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_libev.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_libev.Tpo -c -o liblightcomp_la-fdevent_libev.lo `test -f 'fdevent_libev.c' || echo '$(srcdir)/'`fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_libev.Tpo $(DEPDIR)/liblightcomp_la-fdevent_libev.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_libev.c' object='liblightcomp_la-fdevent_libev.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_libev.lo `test -f 'fdevent_libev.c' || echo '$(srcdir)/'`fdevent_libev.c
+
+liblightcomp_la-fdevent_poll.lo: fdevent_poll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_poll.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo -c -o liblightcomp_la-fdevent_poll.lo `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo $(DEPDIR)/liblightcomp_la-fdevent_poll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_poll.c' object='liblightcomp_la-fdevent_poll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_poll.lo `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
+
+liblightcomp_la-fdevent_linux_sysepoll.lo: fdevent_linux_sysepoll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_linux_sysepoll.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo -c -o liblightcomp_la-fdevent_linux_sysepoll.lo `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo $(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_linux_sysepoll.c' object='liblightcomp_la-fdevent_linux_sysepoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_linux_sysepoll.lo `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
+
+liblightcomp_la-fdevent_solaris_devpoll.lo: fdevent_solaris_devpoll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_solaris_devpoll.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo -c -o liblightcomp_la-fdevent_solaris_devpoll.lo `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo $(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_devpoll.c' object='liblightcomp_la-fdevent_solaris_devpoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_solaris_devpoll.lo `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+
+liblightcomp_la-fdevent_solaris_port.lo: fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_solaris_port.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Tpo -c -o liblightcomp_la-fdevent_solaris_port.lo `test -f 'fdevent_solaris_port.c' || echo '$(srcdir)/'`fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Tpo $(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_port.c' object='liblightcomp_la-fdevent_solaris_port.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_solaris_port.lo `test -f 'fdevent_solaris_port.c' || echo '$(srcdir)/'`fdevent_solaris_port.c
+
+liblightcomp_la-fdevent_freebsd_kqueue.lo: fdevent_freebsd_kqueue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_freebsd_kqueue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo -c -o liblightcomp_la-fdevent_freebsd_kqueue.lo `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo $(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_freebsd_kqueue.c' object='liblightcomp_la-fdevent_freebsd_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_freebsd_kqueue.lo `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
+
+liblightcomp_la-data_config.lo: data_config.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_config.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_config.Tpo -c -o liblightcomp_la-data_config.lo `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_config.Tpo $(DEPDIR)/liblightcomp_la-data_config.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_config.c' object='liblightcomp_la-data_config.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_config.lo `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
+
+liblightcomp_la-crc32.lo: crc32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-crc32.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-crc32.Tpo -c -o liblightcomp_la-crc32.lo `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-crc32.Tpo $(DEPDIR)/liblightcomp_la-crc32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crc32.c' object='liblightcomp_la-crc32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-crc32.lo `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
+
+liblightcomp_la-connections-glue.lo: connections-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-connections-glue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-connections-glue.Tpo -c -o liblightcomp_la-connections-glue.lo `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-connections-glue.Tpo $(DEPDIR)/liblightcomp_la-connections-glue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connections-glue.c' object='liblightcomp_la-connections-glue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-connections-glue.lo `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
+
+liblightcomp_la-configfile-glue.lo: configfile-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-configfile-glue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-configfile-glue.Tpo -c -o liblightcomp_la-configfile-glue.lo `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-configfile-glue.Tpo $(DEPDIR)/liblightcomp_la-configfile-glue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configfile-glue.c' object='liblightcomp_la-configfile-glue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-configfile-glue.lo `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
+
+liblightcomp_la-http-header-glue.lo: http-header-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http-header-glue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http-header-glue.Tpo -c -o liblightcomp_la-http-header-glue.lo `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http-header-glue.Tpo $(DEPDIR)/liblightcomp_la-http-header-glue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http-header-glue.c' object='liblightcomp_la-http-header-glue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http-header-glue.lo `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
+
+liblightcomp_la-http_auth.lo: http_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_auth.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http_auth.Tpo -c -o liblightcomp_la-http_auth.lo `test -f 'http_auth.c' || echo '$(srcdir)/'`http_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http_auth.Tpo $(DEPDIR)/liblightcomp_la-http_auth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_auth.c' object='liblightcomp_la-http_auth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_auth.lo `test -f 'http_auth.c' || echo '$(srcdir)/'`http_auth.c
+
+liblightcomp_la-http_vhostdb.lo: http_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_vhostdb.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http_vhostdb.Tpo -c -o liblightcomp_la-http_vhostdb.lo `test -f 'http_vhostdb.c' || echo '$(srcdir)/'`http_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http_vhostdb.Tpo $(DEPDIR)/liblightcomp_la-http_vhostdb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_vhostdb.c' object='liblightcomp_la-http_vhostdb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_vhostdb.lo `test -f 'http_vhostdb.c' || echo '$(srcdir)/'`http_vhostdb.c
+
+liblightcomp_la-rand.lo: rand.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-rand.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-rand.Tpo -c -o liblightcomp_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-rand.Tpo $(DEPDIR)/liblightcomp_la-rand.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rand.c' object='liblightcomp_la-rand.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+
+liblightcomp_la-request.lo: request.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-request.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-request.Tpo -c -o liblightcomp_la-request.lo `test -f 'request.c' || echo '$(srcdir)/'`request.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-request.Tpo $(DEPDIR)/liblightcomp_la-request.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='request.c' object='liblightcomp_la-request.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-request.lo `test -f 'request.c' || echo '$(srcdir)/'`request.c
+
+liblightcomp_la-sock_addr.lo: sock_addr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-sock_addr.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-sock_addr.Tpo -c -o liblightcomp_la-sock_addr.lo `test -f 'sock_addr.c' || echo '$(srcdir)/'`sock_addr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-sock_addr.Tpo $(DEPDIR)/liblightcomp_la-sock_addr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sock_addr.c' object='liblightcomp_la-sock_addr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-sock_addr.lo `test -f 'sock_addr.c' || echo '$(srcdir)/'`sock_addr.c
+
+liblightcomp_la-splaytree.lo: splaytree.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-splaytree.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-splaytree.Tpo -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-splaytree.Tpo $(DEPDIR)/liblightcomp_la-splaytree.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='splaytree.c' object='liblightcomp_la-splaytree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+
+liblightcomp_la-safe_memclear.lo: safe_memclear.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-safe_memclear.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-safe_memclear.Tpo -c -o liblightcomp_la-safe_memclear.lo `test -f 'safe_memclear.c' || echo '$(srcdir)/'`safe_memclear.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-safe_memclear.Tpo $(DEPDIR)/liblightcomp_la-safe_memclear.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='safe_memclear.c' object='liblightcomp_la-safe_memclear.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-safe_memclear.lo `test -f 'safe_memclear.c' || echo '$(srcdir)/'`safe_memclear.c
+
+mod_authn_mysql_la-mod_authn_mysql.lo: mod_authn_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_authn_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_authn_mysql_la-mod_authn_mysql.lo -MD -MP -MF $(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Tpo -c -o mod_authn_mysql_la-mod_authn_mysql.lo `test -f 'mod_authn_mysql.c' || echo '$(srcdir)/'`mod_authn_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Tpo $(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_mysql.c' object='mod_authn_mysql_la-mod_authn_mysql.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_authn_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_authn_mysql_la-mod_authn_mysql.lo `test -f 'mod_authn_mysql.c' || echo '$(srcdir)/'`mod_authn_mysql.c
+
+mod_authn_sasl_la-mod_authn_sasl.lo: mod_authn_sasl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_authn_sasl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_authn_sasl_la-mod_authn_sasl.lo -MD -MP -MF $(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Tpo -c -o mod_authn_sasl_la-mod_authn_sasl.lo `test -f 'mod_authn_sasl.c' || echo '$(srcdir)/'`mod_authn_sasl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Tpo $(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_sasl.c' object='mod_authn_sasl_la-mod_authn_sasl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_authn_sasl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_authn_sasl_la-mod_authn_sasl.lo `test -f 'mod_authn_sasl.c' || echo '$(srcdir)/'`mod_authn_sasl.c
+
+mod_cml_la-mod_cml.lo: mod_cml.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml.lo -MD -MP -MF $(DEPDIR)/mod_cml_la-mod_cml.Tpo -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_cml_la-mod_cml.Tpo $(DEPDIR)/mod_cml_la-mod_cml.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml.c' object='mod_cml_la-mod_cml.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
+
+mod_cml_la-mod_cml_lua.lo: mod_cml_lua.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml_lua.lo -MD -MP -MF $(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo -c -o mod_cml_la-mod_cml_lua.lo `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo $(DEPDIR)/mod_cml_la-mod_cml_lua.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_lua.c' object='mod_cml_la-mod_cml_lua.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_lua.lo `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
+
+mod_cml_la-mod_cml_funcs.lo: mod_cml_funcs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml_funcs.lo -MD -MP -MF $(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo $(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_funcs.c' object='mod_cml_la-mod_cml_funcs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+
+mod_magnet_la-mod_magnet.lo: mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -MT mod_magnet_la-mod_magnet.lo -MD -MP -MF $(DEPDIR)/mod_magnet_la-mod_magnet.Tpo -c -o mod_magnet_la-mod_magnet.lo `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_magnet_la-mod_magnet.Tpo $(DEPDIR)/mod_magnet_la-mod_magnet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet.c' object='mod_magnet_la-mod_magnet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -c -o mod_magnet_la-mod_magnet.lo `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+
+mod_magnet_la-mod_magnet_cache.lo: mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -MT mod_magnet_la-mod_magnet_cache.lo -MD -MP -MF $(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo -c -o mod_magnet_la-mod_magnet_cache.lo `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo $(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet_cache.c' object='mod_magnet_la-mod_magnet_cache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -c -o mod_magnet_la-mod_magnet_cache.lo `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
+
+mod_mysql_vhost_la-mod_mysql_vhost.lo: mod_mysql_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_mysql_vhost_la-mod_mysql_vhost.lo -MD -MP -MF $(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo $(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_mysql_vhost.c' object='mod_mysql_vhost_la-mod_mysql_vhost.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
+
+mod_vhostdb_dbi_la-mod_vhostdb_dbi.lo: mod_vhostdb_dbi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_vhostdb_dbi_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_vhostdb_dbi_la-mod_vhostdb_dbi.lo -MD -MP -MF $(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Tpo -c -o mod_vhostdb_dbi_la-mod_vhostdb_dbi.lo `test -f 'mod_vhostdb_dbi.c' || echo '$(srcdir)/'`mod_vhostdb_dbi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Tpo $(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_dbi.c' object='mod_vhostdb_dbi_la-mod_vhostdb_dbi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_vhostdb_dbi_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_vhostdb_dbi_la-mod_vhostdb_dbi.lo `test -f 'mod_vhostdb_dbi.c' || echo '$(srcdir)/'`mod_vhostdb_dbi.c
+
+mod_vhostdb_mysql_la-mod_vhostdb_mysql.lo: mod_vhostdb_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_vhostdb_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_vhostdb_mysql_la-mod_vhostdb_mysql.lo -MD -MP -MF $(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Tpo -c -o mod_vhostdb_mysql_la-mod_vhostdb_mysql.lo `test -f 'mod_vhostdb_mysql.c' || echo '$(srcdir)/'`mod_vhostdb_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Tpo $(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_mysql.c' object='mod_vhostdb_mysql_la-mod_vhostdb_mysql.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_vhostdb_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_vhostdb_mysql_la-mod_vhostdb_mysql.lo `test -f 'mod_vhostdb_mysql.c' || echo '$(srcdir)/'`mod_vhostdb_mysql.c
+
+mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.lo: mod_vhostdb_pgsql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_vhostdb_pgsql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.lo -MD -MP -MF $(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Tpo -c -o mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.lo `test -f 'mod_vhostdb_pgsql.c' || echo '$(srcdir)/'`mod_vhostdb_pgsql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Tpo $(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_pgsql.c' object='mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_vhostdb_pgsql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.lo `test -f 'mod_vhostdb_pgsql.c' || echo '$(srcdir)/'`mod_vhostdb_pgsql.c
+
+mod_webdav_la-mod_webdav.lo: mod_webdav.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_webdav_la_CFLAGS) $(CFLAGS) -MT mod_webdav_la-mod_webdav.lo -MD -MP -MF $(DEPDIR)/mod_webdav_la-mod_webdav.Tpo -c -o mod_webdav_la-mod_webdav.lo `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_webdav_la-mod_webdav.Tpo $(DEPDIR)/mod_webdav_la-mod_webdav.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_webdav.c' object='mod_webdav_la-mod_webdav.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_webdav_la_CFLAGS) $(CFLAGS) -c -o mod_webdav_la-mod_webdav.lo `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
+
+lighttpd-server.o: server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-server.o -MD -MP -MF $(DEPDIR)/lighttpd-server.Tpo -c -o lighttpd-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-server.Tpo $(DEPDIR)/lighttpd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='lighttpd-server.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c
+
+lighttpd-server.obj: server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-server.obj -MD -MP -MF $(DEPDIR)/lighttpd-server.Tpo -c -o lighttpd-server.obj `if test -f 'server.c'; then $(CYGPATH_W) 'server.c'; else $(CYGPATH_W) '$(srcdir)/server.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-server.Tpo $(DEPDIR)/lighttpd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='lighttpd-server.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-server.obj `if test -f 'server.c'; then $(CYGPATH_W) 'server.c'; else $(CYGPATH_W) '$(srcdir)/server.c'; fi`
+
+lighttpd-response.o: response.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-response.o -MD -MP -MF $(DEPDIR)/lighttpd-response.Tpo -c -o lighttpd-response.o `test -f 'response.c' || echo '$(srcdir)/'`response.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-response.Tpo $(DEPDIR)/lighttpd-response.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='response.c' object='lighttpd-response.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-response.o `test -f 'response.c' || echo '$(srcdir)/'`response.c
+
+lighttpd-response.obj: response.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-response.obj -MD -MP -MF $(DEPDIR)/lighttpd-response.Tpo -c -o lighttpd-response.obj `if test -f 'response.c'; then $(CYGPATH_W) 'response.c'; else $(CYGPATH_W) '$(srcdir)/response.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-response.Tpo $(DEPDIR)/lighttpd-response.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='response.c' object='lighttpd-response.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-response.obj `if test -f 'response.c'; then $(CYGPATH_W) 'response.c'; else $(CYGPATH_W) '$(srcdir)/response.c'; fi`
+
+lighttpd-connections.o: connections.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-connections.o -MD -MP -MF $(DEPDIR)/lighttpd-connections.Tpo -c -o lighttpd-connections.o `test -f 'connections.c' || echo '$(srcdir)/'`connections.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-connections.Tpo $(DEPDIR)/lighttpd-connections.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connections.c' object='lighttpd-connections.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-connections.o `test -f 'connections.c' || echo '$(srcdir)/'`connections.c
+
+lighttpd-connections.obj: connections.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-connections.obj -MD -MP -MF $(DEPDIR)/lighttpd-connections.Tpo -c -o lighttpd-connections.obj `if test -f 'connections.c'; then $(CYGPATH_W) 'connections.c'; else $(CYGPATH_W) '$(srcdir)/connections.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-connections.Tpo $(DEPDIR)/lighttpd-connections.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connections.c' object='lighttpd-connections.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-connections.obj `if test -f 'connections.c'; then $(CYGPATH_W) 'connections.c'; else $(CYGPATH_W) '$(srcdir)/connections.c'; fi`
+
+lighttpd-inet_ntop_cache.o: inet_ntop_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-inet_ntop_cache.o -MD -MP -MF $(DEPDIR)/lighttpd-inet_ntop_cache.Tpo -c -o lighttpd-inet_ntop_cache.o `test -f 'inet_ntop_cache.c' || echo '$(srcdir)/'`inet_ntop_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-inet_ntop_cache.Tpo $(DEPDIR)/lighttpd-inet_ntop_cache.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_ntop_cache.c' object='lighttpd-inet_ntop_cache.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-inet_ntop_cache.o `test -f 'inet_ntop_cache.c' || echo '$(srcdir)/'`inet_ntop_cache.c
+
+lighttpd-inet_ntop_cache.obj: inet_ntop_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-inet_ntop_cache.obj -MD -MP -MF $(DEPDIR)/lighttpd-inet_ntop_cache.Tpo -c -o lighttpd-inet_ntop_cache.obj `if test -f 'inet_ntop_cache.c'; then $(CYGPATH_W) 'inet_ntop_cache.c'; else $(CYGPATH_W) '$(srcdir)/inet_ntop_cache.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-inet_ntop_cache.Tpo $(DEPDIR)/lighttpd-inet_ntop_cache.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_ntop_cache.c' object='lighttpd-inet_ntop_cache.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-inet_ntop_cache.obj `if test -f 'inet_ntop_cache.c'; then $(CYGPATH_W) 'inet_ntop_cache.c'; else $(CYGPATH_W) '$(srcdir)/inet_ntop_cache.c'; fi`
+
+lighttpd-network.o: network.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-network.o -MD -MP -MF $(DEPDIR)/lighttpd-network.Tpo -c -o lighttpd-network.o `test -f 'network.c' || echo '$(srcdir)/'`network.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-network.Tpo $(DEPDIR)/lighttpd-network.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network.c' object='lighttpd-network.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-network.o `test -f 'network.c' || echo '$(srcdir)/'`network.c
+
+lighttpd-network.obj: network.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-network.obj -MD -MP -MF $(DEPDIR)/lighttpd-network.Tpo -c -o lighttpd-network.obj `if test -f 'network.c'; then $(CYGPATH_W) 'network.c'; else $(CYGPATH_W) '$(srcdir)/network.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-network.Tpo $(DEPDIR)/lighttpd-network.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network.c' object='lighttpd-network.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-network.obj `if test -f 'network.c'; then $(CYGPATH_W) 'network.c'; else $(CYGPATH_W) '$(srcdir)/network.c'; fi`
+
+lighttpd-network_write.o: network_write.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-network_write.o -MD -MP -MF $(DEPDIR)/lighttpd-network_write.Tpo -c -o lighttpd-network_write.o `test -f 'network_write.c' || echo '$(srcdir)/'`network_write.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-network_write.Tpo $(DEPDIR)/lighttpd-network_write.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_write.c' object='lighttpd-network_write.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-network_write.o `test -f 'network_write.c' || echo '$(srcdir)/'`network_write.c
+
+lighttpd-network_write.obj: network_write.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-network_write.obj -MD -MP -MF $(DEPDIR)/lighttpd-network_write.Tpo -c -o lighttpd-network_write.obj `if test -f 'network_write.c'; then $(CYGPATH_W) 'network_write.c'; else $(CYGPATH_W) '$(srcdir)/network_write.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-network_write.Tpo $(DEPDIR)/lighttpd-network_write.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_write.c' object='lighttpd-network_write.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-network_write.obj `if test -f 'network_write.c'; then $(CYGPATH_W) 'network_write.c'; else $(CYGPATH_W) '$(srcdir)/network_write.c'; fi`
+
+lighttpd-configfile.o: configfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-configfile.o -MD -MP -MF $(DEPDIR)/lighttpd-configfile.Tpo -c -o lighttpd-configfile.o `test -f 'configfile.c' || echo '$(srcdir)/'`configfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-configfile.Tpo $(DEPDIR)/lighttpd-configfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configfile.c' object='lighttpd-configfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-configfile.o `test -f 'configfile.c' || echo '$(srcdir)/'`configfile.c
+
+lighttpd-configfile.obj: configfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-configfile.obj -MD -MP -MF $(DEPDIR)/lighttpd-configfile.Tpo -c -o lighttpd-configfile.obj `if test -f 'configfile.c'; then $(CYGPATH_W) 'configfile.c'; else $(CYGPATH_W) '$(srcdir)/configfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-configfile.Tpo $(DEPDIR)/lighttpd-configfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configfile.c' object='lighttpd-configfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-configfile.obj `if test -f 'configfile.c'; then $(CYGPATH_W) 'configfile.c'; else $(CYGPATH_W) '$(srcdir)/configfile.c'; fi`
+
+lighttpd-configparser.o: configparser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-configparser.o -MD -MP -MF $(DEPDIR)/lighttpd-configparser.Tpo -c -o lighttpd-configparser.o `test -f 'configparser.c' || echo '$(srcdir)/'`configparser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-configparser.Tpo $(DEPDIR)/lighttpd-configparser.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configparser.c' object='lighttpd-configparser.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-configparser.o `test -f 'configparser.c' || echo '$(srcdir)/'`configparser.c
+
+lighttpd-configparser.obj: configparser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-configparser.obj -MD -MP -MF $(DEPDIR)/lighttpd-configparser.Tpo -c -o lighttpd-configparser.obj `if test -f 'configparser.c'; then $(CYGPATH_W) 'configparser.c'; else $(CYGPATH_W) '$(srcdir)/configparser.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-configparser.Tpo $(DEPDIR)/lighttpd-configparser.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configparser.c' object='lighttpd-configparser.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-configparser.obj `if test -f 'configparser.c'; then $(CYGPATH_W) 'configparser.c'; else $(CYGPATH_W) '$(srcdir)/configparser.c'; fi`
+
+lighttpd-base64.o: base64.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-base64.o -MD -MP -MF $(DEPDIR)/lighttpd-base64.Tpo -c -o lighttpd-base64.o `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-base64.Tpo $(DEPDIR)/lighttpd-base64.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='base64.c' object='lighttpd-base64.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-base64.o `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+
+lighttpd-base64.obj: base64.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-base64.obj -MD -MP -MF $(DEPDIR)/lighttpd-base64.Tpo -c -o lighttpd-base64.obj `if test -f 'base64.c'; then $(CYGPATH_W) 'base64.c'; else $(CYGPATH_W) '$(srcdir)/base64.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-base64.Tpo $(DEPDIR)/lighttpd-base64.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='base64.c' object='lighttpd-base64.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-base64.obj `if test -f 'base64.c'; then $(CYGPATH_W) 'base64.c'; else $(CYGPATH_W) '$(srcdir)/base64.c'; fi`
+
+lighttpd-buffer.o: buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-buffer.o -MD -MP -MF $(DEPDIR)/lighttpd-buffer.Tpo -c -o lighttpd-buffer.o `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-buffer.Tpo $(DEPDIR)/lighttpd-buffer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='buffer.c' object='lighttpd-buffer.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-buffer.o `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+
+lighttpd-buffer.obj: buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-buffer.obj -MD -MP -MF $(DEPDIR)/lighttpd-buffer.Tpo -c -o lighttpd-buffer.obj `if test -f 'buffer.c'; then $(CYGPATH_W) 'buffer.c'; else $(CYGPATH_W) '$(srcdir)/buffer.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-buffer.Tpo $(DEPDIR)/lighttpd-buffer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='buffer.c' object='lighttpd-buffer.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-buffer.obj `if test -f 'buffer.c'; then $(CYGPATH_W) 'buffer.c'; else $(CYGPATH_W) '$(srcdir)/buffer.c'; fi`
+
+lighttpd-burl.o: burl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-burl.o -MD -MP -MF $(DEPDIR)/lighttpd-burl.Tpo -c -o lighttpd-burl.o `test -f 'burl.c' || echo '$(srcdir)/'`burl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-burl.Tpo $(DEPDIR)/lighttpd-burl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='burl.c' object='lighttpd-burl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-burl.o `test -f 'burl.c' || echo '$(srcdir)/'`burl.c
+
+lighttpd-burl.obj: burl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-burl.obj -MD -MP -MF $(DEPDIR)/lighttpd-burl.Tpo -c -o lighttpd-burl.obj `if test -f 'burl.c'; then $(CYGPATH_W) 'burl.c'; else $(CYGPATH_W) '$(srcdir)/burl.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-burl.Tpo $(DEPDIR)/lighttpd-burl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='burl.c' object='lighttpd-burl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-burl.obj `if test -f 'burl.c'; then $(CYGPATH_W) 'burl.c'; else $(CYGPATH_W) '$(srcdir)/burl.c'; fi`
+
+lighttpd-log.o: log.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-log.o -MD -MP -MF $(DEPDIR)/lighttpd-log.Tpo -c -o lighttpd-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-log.Tpo $(DEPDIR)/lighttpd-log.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='lighttpd-log.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c
+
+lighttpd-log.obj: log.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-log.obj -MD -MP -MF $(DEPDIR)/lighttpd-log.Tpo -c -o lighttpd-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-log.Tpo $(DEPDIR)/lighttpd-log.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='lighttpd-log.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi`
+
+lighttpd-http_header.o: http_header.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_header.o -MD -MP -MF $(DEPDIR)/lighttpd-http_header.Tpo -c -o lighttpd-http_header.o `test -f 'http_header.c' || echo '$(srcdir)/'`http_header.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_header.Tpo $(DEPDIR)/lighttpd-http_header.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_header.c' object='lighttpd-http_header.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_header.o `test -f 'http_header.c' || echo '$(srcdir)/'`http_header.c
+
+lighttpd-http_header.obj: http_header.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_header.obj -MD -MP -MF $(DEPDIR)/lighttpd-http_header.Tpo -c -o lighttpd-http_header.obj `if test -f 'http_header.c'; then $(CYGPATH_W) 'http_header.c'; else $(CYGPATH_W) '$(srcdir)/http_header.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_header.Tpo $(DEPDIR)/lighttpd-http_header.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_header.c' object='lighttpd-http_header.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_header.obj `if test -f 'http_header.c'; then $(CYGPATH_W) 'http_header.c'; else $(CYGPATH_W) '$(srcdir)/http_header.c'; fi`
+
+lighttpd-http_kv.o: http_kv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_kv.o -MD -MP -MF $(DEPDIR)/lighttpd-http_kv.Tpo -c -o lighttpd-http_kv.o `test -f 'http_kv.c' || echo '$(srcdir)/'`http_kv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_kv.Tpo $(DEPDIR)/lighttpd-http_kv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_kv.c' object='lighttpd-http_kv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_kv.o `test -f 'http_kv.c' || echo '$(srcdir)/'`http_kv.c
+
+lighttpd-http_kv.obj: http_kv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_kv.obj -MD -MP -MF $(DEPDIR)/lighttpd-http_kv.Tpo -c -o lighttpd-http_kv.obj `if test -f 'http_kv.c'; then $(CYGPATH_W) 'http_kv.c'; else $(CYGPATH_W) '$(srcdir)/http_kv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_kv.Tpo $(DEPDIR)/lighttpd-http_kv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_kv.c' object='lighttpd-http_kv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_kv.obj `if test -f 'http_kv.c'; then $(CYGPATH_W) 'http_kv.c'; else $(CYGPATH_W) '$(srcdir)/http_kv.c'; fi`
+
+lighttpd-keyvalue.o: keyvalue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-keyvalue.o -MD -MP -MF $(DEPDIR)/lighttpd-keyvalue.Tpo -c -o lighttpd-keyvalue.o `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-keyvalue.Tpo $(DEPDIR)/lighttpd-keyvalue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='keyvalue.c' object='lighttpd-keyvalue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-keyvalue.o `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
+
+lighttpd-keyvalue.obj: keyvalue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-keyvalue.obj -MD -MP -MF $(DEPDIR)/lighttpd-keyvalue.Tpo -c -o lighttpd-keyvalue.obj `if test -f 'keyvalue.c'; then $(CYGPATH_W) 'keyvalue.c'; else $(CYGPATH_W) '$(srcdir)/keyvalue.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-keyvalue.Tpo $(DEPDIR)/lighttpd-keyvalue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='keyvalue.c' object='lighttpd-keyvalue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-keyvalue.obj `if test -f 'keyvalue.c'; then $(CYGPATH_W) 'keyvalue.c'; else $(CYGPATH_W) '$(srcdir)/keyvalue.c'; fi`
+
+lighttpd-chunk.o: chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-chunk.o -MD -MP -MF $(DEPDIR)/lighttpd-chunk.Tpo -c -o lighttpd-chunk.o `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-chunk.Tpo $(DEPDIR)/lighttpd-chunk.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='chunk.c' object='lighttpd-chunk.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-chunk.o `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
+
+lighttpd-chunk.obj: chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-chunk.obj -MD -MP -MF $(DEPDIR)/lighttpd-chunk.Tpo -c -o lighttpd-chunk.obj `if test -f 'chunk.c'; then $(CYGPATH_W) 'chunk.c'; else $(CYGPATH_W) '$(srcdir)/chunk.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-chunk.Tpo $(DEPDIR)/lighttpd-chunk.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='chunk.c' object='lighttpd-chunk.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-chunk.obj `if test -f 'chunk.c'; then $(CYGPATH_W) 'chunk.c'; else $(CYGPATH_W) '$(srcdir)/chunk.c'; fi`
+
+lighttpd-http_chunk.o: http_chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_chunk.o -MD -MP -MF $(DEPDIR)/lighttpd-http_chunk.Tpo -c -o lighttpd-http_chunk.o `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_chunk.Tpo $(DEPDIR)/lighttpd-http_chunk.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_chunk.c' object='lighttpd-http_chunk.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_chunk.o `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
+
+lighttpd-http_chunk.obj: http_chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_chunk.obj -MD -MP -MF $(DEPDIR)/lighttpd-http_chunk.Tpo -c -o lighttpd-http_chunk.obj `if test -f 'http_chunk.c'; then $(CYGPATH_W) 'http_chunk.c'; else $(CYGPATH_W) '$(srcdir)/http_chunk.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_chunk.Tpo $(DEPDIR)/lighttpd-http_chunk.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_chunk.c' object='lighttpd-http_chunk.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_chunk.obj `if test -f 'http_chunk.c'; then $(CYGPATH_W) 'http_chunk.c'; else $(CYGPATH_W) '$(srcdir)/http_chunk.c'; fi`
+
+lighttpd-stream.o: stream.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-stream.o -MD -MP -MF $(DEPDIR)/lighttpd-stream.Tpo -c -o lighttpd-stream.o `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-stream.Tpo $(DEPDIR)/lighttpd-stream.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stream.c' object='lighttpd-stream.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-stream.o `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
+
+lighttpd-stream.obj: stream.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-stream.obj -MD -MP -MF $(DEPDIR)/lighttpd-stream.Tpo -c -o lighttpd-stream.obj `if test -f 'stream.c'; then $(CYGPATH_W) 'stream.c'; else $(CYGPATH_W) '$(srcdir)/stream.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-stream.Tpo $(DEPDIR)/lighttpd-stream.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stream.c' object='lighttpd-stream.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-stream.obj `if test -f 'stream.c'; then $(CYGPATH_W) 'stream.c'; else $(CYGPATH_W) '$(srcdir)/stream.c'; fi`
+
+lighttpd-fdevent.o: fdevent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent.Tpo -c -o lighttpd-fdevent.o `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent.Tpo $(DEPDIR)/lighttpd-fdevent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent.c' object='lighttpd-fdevent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent.o `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
+
+lighttpd-fdevent.obj: fdevent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent.Tpo -c -o lighttpd-fdevent.obj `if test -f 'fdevent.c'; then $(CYGPATH_W) 'fdevent.c'; else $(CYGPATH_W) '$(srcdir)/fdevent.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent.Tpo $(DEPDIR)/lighttpd-fdevent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent.c' object='lighttpd-fdevent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent.obj `if test -f 'fdevent.c'; then $(CYGPATH_W) 'fdevent.c'; else $(CYGPATH_W) '$(srcdir)/fdevent.c'; fi`
+
+lighttpd-gw_backend.o: gw_backend.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-gw_backend.o -MD -MP -MF $(DEPDIR)/lighttpd-gw_backend.Tpo -c -o lighttpd-gw_backend.o `test -f 'gw_backend.c' || echo '$(srcdir)/'`gw_backend.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-gw_backend.Tpo $(DEPDIR)/lighttpd-gw_backend.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gw_backend.c' object='lighttpd-gw_backend.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-gw_backend.o `test -f 'gw_backend.c' || echo '$(srcdir)/'`gw_backend.c
+
+lighttpd-gw_backend.obj: gw_backend.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-gw_backend.obj -MD -MP -MF $(DEPDIR)/lighttpd-gw_backend.Tpo -c -o lighttpd-gw_backend.obj `if test -f 'gw_backend.c'; then $(CYGPATH_W) 'gw_backend.c'; else $(CYGPATH_W) '$(srcdir)/gw_backend.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-gw_backend.Tpo $(DEPDIR)/lighttpd-gw_backend.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gw_backend.c' object='lighttpd-gw_backend.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-gw_backend.obj `if test -f 'gw_backend.c'; then $(CYGPATH_W) 'gw_backend.c'; else $(CYGPATH_W) '$(srcdir)/gw_backend.c'; fi`
+
+lighttpd-stat_cache.o: stat_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-stat_cache.o -MD -MP -MF $(DEPDIR)/lighttpd-stat_cache.Tpo -c -o lighttpd-stat_cache.o `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-stat_cache.Tpo $(DEPDIR)/lighttpd-stat_cache.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stat_cache.c' object='lighttpd-stat_cache.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-stat_cache.o `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
+
+lighttpd-stat_cache.obj: stat_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-stat_cache.obj -MD -MP -MF $(DEPDIR)/lighttpd-stat_cache.Tpo -c -o lighttpd-stat_cache.obj `if test -f 'stat_cache.c'; then $(CYGPATH_W) 'stat_cache.c'; else $(CYGPATH_W) '$(srcdir)/stat_cache.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-stat_cache.Tpo $(DEPDIR)/lighttpd-stat_cache.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stat_cache.c' object='lighttpd-stat_cache.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-stat_cache.obj `if test -f 'stat_cache.c'; then $(CYGPATH_W) 'stat_cache.c'; else $(CYGPATH_W) '$(srcdir)/stat_cache.c'; fi`
+
+lighttpd-plugin.o: plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-plugin.o -MD -MP -MF $(DEPDIR)/lighttpd-plugin.Tpo -c -o lighttpd-plugin.o `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-plugin.Tpo $(DEPDIR)/lighttpd-plugin.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugin.c' object='lighttpd-plugin.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-plugin.o `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+
+lighttpd-plugin.obj: plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-plugin.obj -MD -MP -MF $(DEPDIR)/lighttpd-plugin.Tpo -c -o lighttpd-plugin.obj `if test -f 'plugin.c'; then $(CYGPATH_W) 'plugin.c'; else $(CYGPATH_W) '$(srcdir)/plugin.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-plugin.Tpo $(DEPDIR)/lighttpd-plugin.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugin.c' object='lighttpd-plugin.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-plugin.obj `if test -f 'plugin.c'; then $(CYGPATH_W) 'plugin.c'; else $(CYGPATH_W) '$(srcdir)/plugin.c'; fi`
+
+lighttpd-joblist.o: joblist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-joblist.o -MD -MP -MF $(DEPDIR)/lighttpd-joblist.Tpo -c -o lighttpd-joblist.o `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-joblist.Tpo $(DEPDIR)/lighttpd-joblist.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='joblist.c' object='lighttpd-joblist.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-joblist.o `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
+
+lighttpd-joblist.obj: joblist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-joblist.obj -MD -MP -MF $(DEPDIR)/lighttpd-joblist.Tpo -c -o lighttpd-joblist.obj `if test -f 'joblist.c'; then $(CYGPATH_W) 'joblist.c'; else $(CYGPATH_W) '$(srcdir)/joblist.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-joblist.Tpo $(DEPDIR)/lighttpd-joblist.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='joblist.c' object='lighttpd-joblist.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-joblist.obj `if test -f 'joblist.c'; then $(CYGPATH_W) 'joblist.c'; else $(CYGPATH_W) '$(srcdir)/joblist.c'; fi`
+
+lighttpd-etag.o: etag.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-etag.o -MD -MP -MF $(DEPDIR)/lighttpd-etag.Tpo -c -o lighttpd-etag.o `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-etag.Tpo $(DEPDIR)/lighttpd-etag.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='etag.c' object='lighttpd-etag.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-etag.o `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
+
+lighttpd-etag.obj: etag.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-etag.obj -MD -MP -MF $(DEPDIR)/lighttpd-etag.Tpo -c -o lighttpd-etag.obj `if test -f 'etag.c'; then $(CYGPATH_W) 'etag.c'; else $(CYGPATH_W) '$(srcdir)/etag.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-etag.Tpo $(DEPDIR)/lighttpd-etag.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='etag.c' object='lighttpd-etag.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-etag.obj `if test -f 'etag.c'; then $(CYGPATH_W) 'etag.c'; else $(CYGPATH_W) '$(srcdir)/etag.c'; fi`
+
+lighttpd-array.o: array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-array.o -MD -MP -MF $(DEPDIR)/lighttpd-array.Tpo -c -o lighttpd-array.o `test -f 'array.c' || echo '$(srcdir)/'`array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-array.Tpo $(DEPDIR)/lighttpd-array.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='array.c' object='lighttpd-array.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-array.o `test -f 'array.c' || echo '$(srcdir)/'`array.c
+
+lighttpd-array.obj: array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-array.obj -MD -MP -MF $(DEPDIR)/lighttpd-array.Tpo -c -o lighttpd-array.obj `if test -f 'array.c'; then $(CYGPATH_W) 'array.c'; else $(CYGPATH_W) '$(srcdir)/array.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-array.Tpo $(DEPDIR)/lighttpd-array.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='array.c' object='lighttpd-array.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-array.obj `if test -f 'array.c'; then $(CYGPATH_W) 'array.c'; else $(CYGPATH_W) '$(srcdir)/array.c'; fi`
+
+lighttpd-data_string.o: data_string.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_string.o -MD -MP -MF $(DEPDIR)/lighttpd-data_string.Tpo -c -o lighttpd-data_string.o `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_string.Tpo $(DEPDIR)/lighttpd-data_string.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_string.c' object='lighttpd-data_string.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_string.o `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
+
+lighttpd-data_string.obj: data_string.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_string.obj -MD -MP -MF $(DEPDIR)/lighttpd-data_string.Tpo -c -o lighttpd-data_string.obj `if test -f 'data_string.c'; then $(CYGPATH_W) 'data_string.c'; else $(CYGPATH_W) '$(srcdir)/data_string.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_string.Tpo $(DEPDIR)/lighttpd-data_string.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_string.c' object='lighttpd-data_string.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_string.obj `if test -f 'data_string.c'; then $(CYGPATH_W) 'data_string.c'; else $(CYGPATH_W) '$(srcdir)/data_string.c'; fi`
+
+lighttpd-data_array.o: data_array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_array.o -MD -MP -MF $(DEPDIR)/lighttpd-data_array.Tpo -c -o lighttpd-data_array.o `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_array.Tpo $(DEPDIR)/lighttpd-data_array.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_array.c' object='lighttpd-data_array.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_array.o `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
+
+lighttpd-data_array.obj: data_array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_array.obj -MD -MP -MF $(DEPDIR)/lighttpd-data_array.Tpo -c -o lighttpd-data_array.obj `if test -f 'data_array.c'; then $(CYGPATH_W) 'data_array.c'; else $(CYGPATH_W) '$(srcdir)/data_array.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_array.Tpo $(DEPDIR)/lighttpd-data_array.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_array.c' object='lighttpd-data_array.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_array.obj `if test -f 'data_array.c'; then $(CYGPATH_W) 'data_array.c'; else $(CYGPATH_W) '$(srcdir)/data_array.c'; fi`
+
+lighttpd-data_integer.o: data_integer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_integer.o -MD -MP -MF $(DEPDIR)/lighttpd-data_integer.Tpo -c -o lighttpd-data_integer.o `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_integer.Tpo $(DEPDIR)/lighttpd-data_integer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_integer.c' object='lighttpd-data_integer.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_integer.o `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
+
+lighttpd-data_integer.obj: data_integer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_integer.obj -MD -MP -MF $(DEPDIR)/lighttpd-data_integer.Tpo -c -o lighttpd-data_integer.obj `if test -f 'data_integer.c'; then $(CYGPATH_W) 'data_integer.c'; else $(CYGPATH_W) '$(srcdir)/data_integer.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_integer.Tpo $(DEPDIR)/lighttpd-data_integer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_integer.c' object='lighttpd-data_integer.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_integer.obj `if test -f 'data_integer.c'; then $(CYGPATH_W) 'data_integer.c'; else $(CYGPATH_W) '$(srcdir)/data_integer.c'; fi`
+
+lighttpd-algo_sha1.o: algo_sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-algo_sha1.o -MD -MP -MF $(DEPDIR)/lighttpd-algo_sha1.Tpo -c -o lighttpd-algo_sha1.o `test -f 'algo_sha1.c' || echo '$(srcdir)/'`algo_sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-algo_sha1.Tpo $(DEPDIR)/lighttpd-algo_sha1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='algo_sha1.c' object='lighttpd-algo_sha1.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-algo_sha1.o `test -f 'algo_sha1.c' || echo '$(srcdir)/'`algo_sha1.c
+
+lighttpd-algo_sha1.obj: algo_sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-algo_sha1.obj -MD -MP -MF $(DEPDIR)/lighttpd-algo_sha1.Tpo -c -o lighttpd-algo_sha1.obj `if test -f 'algo_sha1.c'; then $(CYGPATH_W) 'algo_sha1.c'; else $(CYGPATH_W) '$(srcdir)/algo_sha1.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-algo_sha1.Tpo $(DEPDIR)/lighttpd-algo_sha1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='algo_sha1.c' object='lighttpd-algo_sha1.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-algo_sha1.obj `if test -f 'algo_sha1.c'; then $(CYGPATH_W) 'algo_sha1.c'; else $(CYGPATH_W) '$(srcdir)/algo_sha1.c'; fi`
+
+lighttpd-md5.o: md5.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-md5.o -MD -MP -MF $(DEPDIR)/lighttpd-md5.Tpo -c -o lighttpd-md5.o `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-md5.Tpo $(DEPDIR)/lighttpd-md5.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md5.c' object='lighttpd-md5.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-md5.o `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+
+lighttpd-md5.obj: md5.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-md5.obj -MD -MP -MF $(DEPDIR)/lighttpd-md5.Tpo -c -o lighttpd-md5.obj `if test -f 'md5.c'; then $(CYGPATH_W) 'md5.c'; else $(CYGPATH_W) '$(srcdir)/md5.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-md5.Tpo $(DEPDIR)/lighttpd-md5.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md5.c' object='lighttpd-md5.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-md5.obj `if test -f 'md5.c'; then $(CYGPATH_W) 'md5.c'; else $(CYGPATH_W) '$(srcdir)/md5.c'; fi`
+
+lighttpd-vector.o: vector.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-vector.o -MD -MP -MF $(DEPDIR)/lighttpd-vector.Tpo -c -o lighttpd-vector.o `test -f 'vector.c' || echo '$(srcdir)/'`vector.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-vector.Tpo $(DEPDIR)/lighttpd-vector.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vector.c' object='lighttpd-vector.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-vector.o `test -f 'vector.c' || echo '$(srcdir)/'`vector.c
+
+lighttpd-vector.obj: vector.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-vector.obj -MD -MP -MF $(DEPDIR)/lighttpd-vector.Tpo -c -o lighttpd-vector.obj `if test -f 'vector.c'; then $(CYGPATH_W) 'vector.c'; else $(CYGPATH_W) '$(srcdir)/vector.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-vector.Tpo $(DEPDIR)/lighttpd-vector.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vector.c' object='lighttpd-vector.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-vector.obj `if test -f 'vector.c'; then $(CYGPATH_W) 'vector.c'; else $(CYGPATH_W) '$(srcdir)/vector.c'; fi`
+
+lighttpd-fdevent_select.o: fdevent_select.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_select.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_select.Tpo -c -o lighttpd-fdevent_select.o `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_select.Tpo $(DEPDIR)/lighttpd-fdevent_select.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_select.c' object='lighttpd-fdevent_select.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_select.o `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
+
+lighttpd-fdevent_select.obj: fdevent_select.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_select.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_select.Tpo -c -o lighttpd-fdevent_select.obj `if test -f 'fdevent_select.c'; then $(CYGPATH_W) 'fdevent_select.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_select.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_select.Tpo $(DEPDIR)/lighttpd-fdevent_select.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_select.c' object='lighttpd-fdevent_select.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_select.obj `if test -f 'fdevent_select.c'; then $(CYGPATH_W) 'fdevent_select.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_select.c'; fi`
+
+lighttpd-fdevent_libev.o: fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_libev.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_libev.Tpo -c -o lighttpd-fdevent_libev.o `test -f 'fdevent_libev.c' || echo '$(srcdir)/'`fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_libev.Tpo $(DEPDIR)/lighttpd-fdevent_libev.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_libev.c' object='lighttpd-fdevent_libev.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_libev.o `test -f 'fdevent_libev.c' || echo '$(srcdir)/'`fdevent_libev.c
+
+lighttpd-fdevent_libev.obj: fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_libev.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_libev.Tpo -c -o lighttpd-fdevent_libev.obj `if test -f 'fdevent_libev.c'; then $(CYGPATH_W) 'fdevent_libev.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_libev.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_libev.Tpo $(DEPDIR)/lighttpd-fdevent_libev.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_libev.c' object='lighttpd-fdevent_libev.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_libev.obj `if test -f 'fdevent_libev.c'; then $(CYGPATH_W) 'fdevent_libev.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_libev.c'; fi`
+
+lighttpd-fdevent_poll.o: fdevent_poll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_poll.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_poll.Tpo -c -o lighttpd-fdevent_poll.o `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_poll.Tpo $(DEPDIR)/lighttpd-fdevent_poll.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_poll.c' object='lighttpd-fdevent_poll.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_poll.o `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
+
+lighttpd-fdevent_poll.obj: fdevent_poll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_poll.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_poll.Tpo -c -o lighttpd-fdevent_poll.obj `if test -f 'fdevent_poll.c'; then $(CYGPATH_W) 'fdevent_poll.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_poll.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_poll.Tpo $(DEPDIR)/lighttpd-fdevent_poll.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_poll.c' object='lighttpd-fdevent_poll.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_poll.obj `if test -f 'fdevent_poll.c'; then $(CYGPATH_W) 'fdevent_poll.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_poll.c'; fi`
+
+lighttpd-fdevent_linux_sysepoll.o: fdevent_linux_sysepoll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_linux_sysepoll.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Tpo -c -o lighttpd-fdevent_linux_sysepoll.o `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Tpo $(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_linux_sysepoll.c' object='lighttpd-fdevent_linux_sysepoll.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_linux_sysepoll.o `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
+
+lighttpd-fdevent_linux_sysepoll.obj: fdevent_linux_sysepoll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_linux_sysepoll.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Tpo -c -o lighttpd-fdevent_linux_sysepoll.obj `if test -f 'fdevent_linux_sysepoll.c'; then $(CYGPATH_W) 'fdevent_linux_sysepoll.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_linux_sysepoll.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Tpo $(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_linux_sysepoll.c' object='lighttpd-fdevent_linux_sysepoll.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_linux_sysepoll.obj `if test -f 'fdevent_linux_sysepoll.c'; then $(CYGPATH_W) 'fdevent_linux_sysepoll.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_linux_sysepoll.c'; fi`
+
+lighttpd-fdevent_solaris_devpoll.o: fdevent_solaris_devpoll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_solaris_devpoll.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Tpo -c -o lighttpd-fdevent_solaris_devpoll.o `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Tpo $(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_devpoll.c' object='lighttpd-fdevent_solaris_devpoll.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_solaris_devpoll.o `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+
+lighttpd-fdevent_solaris_devpoll.obj: fdevent_solaris_devpoll.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_solaris_devpoll.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Tpo -c -o lighttpd-fdevent_solaris_devpoll.obj `if test -f 'fdevent_solaris_devpoll.c'; then $(CYGPATH_W) 'fdevent_solaris_devpoll.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_solaris_devpoll.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Tpo $(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_devpoll.c' object='lighttpd-fdevent_solaris_devpoll.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_solaris_devpoll.obj `if test -f 'fdevent_solaris_devpoll.c'; then $(CYGPATH_W) 'fdevent_solaris_devpoll.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_solaris_devpoll.c'; fi`
+
+lighttpd-fdevent_solaris_port.o: fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_solaris_port.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_solaris_port.Tpo -c -o lighttpd-fdevent_solaris_port.o `test -f 'fdevent_solaris_port.c' || echo '$(srcdir)/'`fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_solaris_port.Tpo $(DEPDIR)/lighttpd-fdevent_solaris_port.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_port.c' object='lighttpd-fdevent_solaris_port.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_solaris_port.o `test -f 'fdevent_solaris_port.c' || echo '$(srcdir)/'`fdevent_solaris_port.c
+
+lighttpd-fdevent_solaris_port.obj: fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_solaris_port.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_solaris_port.Tpo -c -o lighttpd-fdevent_solaris_port.obj `if test -f 'fdevent_solaris_port.c'; then $(CYGPATH_W) 'fdevent_solaris_port.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_solaris_port.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_solaris_port.Tpo $(DEPDIR)/lighttpd-fdevent_solaris_port.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_port.c' object='lighttpd-fdevent_solaris_port.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_solaris_port.obj `if test -f 'fdevent_solaris_port.c'; then $(CYGPATH_W) 'fdevent_solaris_port.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_solaris_port.c'; fi`
+
+lighttpd-fdevent_freebsd_kqueue.o: fdevent_freebsd_kqueue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_freebsd_kqueue.o -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Tpo -c -o lighttpd-fdevent_freebsd_kqueue.o `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Tpo $(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_freebsd_kqueue.c' object='lighttpd-fdevent_freebsd_kqueue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_freebsd_kqueue.o `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
+
+lighttpd-fdevent_freebsd_kqueue.obj: fdevent_freebsd_kqueue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-fdevent_freebsd_kqueue.obj -MD -MP -MF $(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Tpo -c -o lighttpd-fdevent_freebsd_kqueue.obj `if test -f 'fdevent_freebsd_kqueue.c'; then $(CYGPATH_W) 'fdevent_freebsd_kqueue.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_freebsd_kqueue.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Tpo $(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_freebsd_kqueue.c' object='lighttpd-fdevent_freebsd_kqueue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-fdevent_freebsd_kqueue.obj `if test -f 'fdevent_freebsd_kqueue.c'; then $(CYGPATH_W) 'fdevent_freebsd_kqueue.c'; else $(CYGPATH_W) '$(srcdir)/fdevent_freebsd_kqueue.c'; fi`
+
+lighttpd-data_config.o: data_config.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_config.o -MD -MP -MF $(DEPDIR)/lighttpd-data_config.Tpo -c -o lighttpd-data_config.o `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_config.Tpo $(DEPDIR)/lighttpd-data_config.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_config.c' object='lighttpd-data_config.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_config.o `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
+
+lighttpd-data_config.obj: data_config.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-data_config.obj -MD -MP -MF $(DEPDIR)/lighttpd-data_config.Tpo -c -o lighttpd-data_config.obj `if test -f 'data_config.c'; then $(CYGPATH_W) 'data_config.c'; else $(CYGPATH_W) '$(srcdir)/data_config.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-data_config.Tpo $(DEPDIR)/lighttpd-data_config.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_config.c' object='lighttpd-data_config.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-data_config.obj `if test -f 'data_config.c'; then $(CYGPATH_W) 'data_config.c'; else $(CYGPATH_W) '$(srcdir)/data_config.c'; fi`
+
+lighttpd-crc32.o: crc32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-crc32.o -MD -MP -MF $(DEPDIR)/lighttpd-crc32.Tpo -c -o lighttpd-crc32.o `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-crc32.Tpo $(DEPDIR)/lighttpd-crc32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crc32.c' object='lighttpd-crc32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-crc32.o `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
+
+lighttpd-crc32.obj: crc32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-crc32.obj -MD -MP -MF $(DEPDIR)/lighttpd-crc32.Tpo -c -o lighttpd-crc32.obj `if test -f 'crc32.c'; then $(CYGPATH_W) 'crc32.c'; else $(CYGPATH_W) '$(srcdir)/crc32.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-crc32.Tpo $(DEPDIR)/lighttpd-crc32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crc32.c' object='lighttpd-crc32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-crc32.obj `if test -f 'crc32.c'; then $(CYGPATH_W) 'crc32.c'; else $(CYGPATH_W) '$(srcdir)/crc32.c'; fi`
+
+lighttpd-connections-glue.o: connections-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-connections-glue.o -MD -MP -MF $(DEPDIR)/lighttpd-connections-glue.Tpo -c -o lighttpd-connections-glue.o `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-connections-glue.Tpo $(DEPDIR)/lighttpd-connections-glue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connections-glue.c' object='lighttpd-connections-glue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-connections-glue.o `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
+
+lighttpd-connections-glue.obj: connections-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-connections-glue.obj -MD -MP -MF $(DEPDIR)/lighttpd-connections-glue.Tpo -c -o lighttpd-connections-glue.obj `if test -f 'connections-glue.c'; then $(CYGPATH_W) 'connections-glue.c'; else $(CYGPATH_W) '$(srcdir)/connections-glue.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-connections-glue.Tpo $(DEPDIR)/lighttpd-connections-glue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connections-glue.c' object='lighttpd-connections-glue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-connections-glue.obj `if test -f 'connections-glue.c'; then $(CYGPATH_W) 'connections-glue.c'; else $(CYGPATH_W) '$(srcdir)/connections-glue.c'; fi`
+
+lighttpd-configfile-glue.o: configfile-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-configfile-glue.o -MD -MP -MF $(DEPDIR)/lighttpd-configfile-glue.Tpo -c -o lighttpd-configfile-glue.o `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-configfile-glue.Tpo $(DEPDIR)/lighttpd-configfile-glue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configfile-glue.c' object='lighttpd-configfile-glue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-configfile-glue.o `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
+
+lighttpd-configfile-glue.obj: configfile-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-configfile-glue.obj -MD -MP -MF $(DEPDIR)/lighttpd-configfile-glue.Tpo -c -o lighttpd-configfile-glue.obj `if test -f 'configfile-glue.c'; then $(CYGPATH_W) 'configfile-glue.c'; else $(CYGPATH_W) '$(srcdir)/configfile-glue.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-configfile-glue.Tpo $(DEPDIR)/lighttpd-configfile-glue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configfile-glue.c' object='lighttpd-configfile-glue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-configfile-glue.obj `if test -f 'configfile-glue.c'; then $(CYGPATH_W) 'configfile-glue.c'; else $(CYGPATH_W) '$(srcdir)/configfile-glue.c'; fi`
+
+lighttpd-http-header-glue.o: http-header-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http-header-glue.o -MD -MP -MF $(DEPDIR)/lighttpd-http-header-glue.Tpo -c -o lighttpd-http-header-glue.o `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http-header-glue.Tpo $(DEPDIR)/lighttpd-http-header-glue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http-header-glue.c' object='lighttpd-http-header-glue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http-header-glue.o `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
+
+lighttpd-http-header-glue.obj: http-header-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http-header-glue.obj -MD -MP -MF $(DEPDIR)/lighttpd-http-header-glue.Tpo -c -o lighttpd-http-header-glue.obj `if test -f 'http-header-glue.c'; then $(CYGPATH_W) 'http-header-glue.c'; else $(CYGPATH_W) '$(srcdir)/http-header-glue.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http-header-glue.Tpo $(DEPDIR)/lighttpd-http-header-glue.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http-header-glue.c' object='lighttpd-http-header-glue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http-header-glue.obj `if test -f 'http-header-glue.c'; then $(CYGPATH_W) 'http-header-glue.c'; else $(CYGPATH_W) '$(srcdir)/http-header-glue.c'; fi`
+
+lighttpd-http_auth.o: http_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_auth.o -MD -MP -MF $(DEPDIR)/lighttpd-http_auth.Tpo -c -o lighttpd-http_auth.o `test -f 'http_auth.c' || echo '$(srcdir)/'`http_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_auth.Tpo $(DEPDIR)/lighttpd-http_auth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_auth.c' object='lighttpd-http_auth.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_auth.o `test -f 'http_auth.c' || echo '$(srcdir)/'`http_auth.c
+
+lighttpd-http_auth.obj: http_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_auth.obj -MD -MP -MF $(DEPDIR)/lighttpd-http_auth.Tpo -c -o lighttpd-http_auth.obj `if test -f 'http_auth.c'; then $(CYGPATH_W) 'http_auth.c'; else $(CYGPATH_W) '$(srcdir)/http_auth.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_auth.Tpo $(DEPDIR)/lighttpd-http_auth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_auth.c' object='lighttpd-http_auth.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_auth.obj `if test -f 'http_auth.c'; then $(CYGPATH_W) 'http_auth.c'; else $(CYGPATH_W) '$(srcdir)/http_auth.c'; fi`
+
+lighttpd-http_vhostdb.o: http_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_vhostdb.o -MD -MP -MF $(DEPDIR)/lighttpd-http_vhostdb.Tpo -c -o lighttpd-http_vhostdb.o `test -f 'http_vhostdb.c' || echo '$(srcdir)/'`http_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_vhostdb.Tpo $(DEPDIR)/lighttpd-http_vhostdb.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_vhostdb.c' object='lighttpd-http_vhostdb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_vhostdb.o `test -f 'http_vhostdb.c' || echo '$(srcdir)/'`http_vhostdb.c
+
+lighttpd-http_vhostdb.obj: http_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-http_vhostdb.obj -MD -MP -MF $(DEPDIR)/lighttpd-http_vhostdb.Tpo -c -o lighttpd-http_vhostdb.obj `if test -f 'http_vhostdb.c'; then $(CYGPATH_W) 'http_vhostdb.c'; else $(CYGPATH_W) '$(srcdir)/http_vhostdb.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-http_vhostdb.Tpo $(DEPDIR)/lighttpd-http_vhostdb.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_vhostdb.c' object='lighttpd-http_vhostdb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-http_vhostdb.obj `if test -f 'http_vhostdb.c'; then $(CYGPATH_W) 'http_vhostdb.c'; else $(CYGPATH_W) '$(srcdir)/http_vhostdb.c'; fi`
+
+lighttpd-rand.o: rand.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-rand.o -MD -MP -MF $(DEPDIR)/lighttpd-rand.Tpo -c -o lighttpd-rand.o `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-rand.Tpo $(DEPDIR)/lighttpd-rand.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rand.c' object='lighttpd-rand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-rand.o `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+
+lighttpd-rand.obj: rand.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-rand.obj -MD -MP -MF $(DEPDIR)/lighttpd-rand.Tpo -c -o lighttpd-rand.obj `if test -f 'rand.c'; then $(CYGPATH_W) 'rand.c'; else $(CYGPATH_W) '$(srcdir)/rand.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-rand.Tpo $(DEPDIR)/lighttpd-rand.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rand.c' object='lighttpd-rand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-rand.obj `if test -f 'rand.c'; then $(CYGPATH_W) 'rand.c'; else $(CYGPATH_W) '$(srcdir)/rand.c'; fi`
+
+lighttpd-request.o: request.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-request.o -MD -MP -MF $(DEPDIR)/lighttpd-request.Tpo -c -o lighttpd-request.o `test -f 'request.c' || echo '$(srcdir)/'`request.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-request.Tpo $(DEPDIR)/lighttpd-request.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='request.c' object='lighttpd-request.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-request.o `test -f 'request.c' || echo '$(srcdir)/'`request.c
+
+lighttpd-request.obj: request.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-request.obj -MD -MP -MF $(DEPDIR)/lighttpd-request.Tpo -c -o lighttpd-request.obj `if test -f 'request.c'; then $(CYGPATH_W) 'request.c'; else $(CYGPATH_W) '$(srcdir)/request.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-request.Tpo $(DEPDIR)/lighttpd-request.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='request.c' object='lighttpd-request.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-request.obj `if test -f 'request.c'; then $(CYGPATH_W) 'request.c'; else $(CYGPATH_W) '$(srcdir)/request.c'; fi`
+
+lighttpd-sock_addr.o: sock_addr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-sock_addr.o -MD -MP -MF $(DEPDIR)/lighttpd-sock_addr.Tpo -c -o lighttpd-sock_addr.o `test -f 'sock_addr.c' || echo '$(srcdir)/'`sock_addr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-sock_addr.Tpo $(DEPDIR)/lighttpd-sock_addr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sock_addr.c' object='lighttpd-sock_addr.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-sock_addr.o `test -f 'sock_addr.c' || echo '$(srcdir)/'`sock_addr.c
+
+lighttpd-sock_addr.obj: sock_addr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-sock_addr.obj -MD -MP -MF $(DEPDIR)/lighttpd-sock_addr.Tpo -c -o lighttpd-sock_addr.obj `if test -f 'sock_addr.c'; then $(CYGPATH_W) 'sock_addr.c'; else $(CYGPATH_W) '$(srcdir)/sock_addr.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-sock_addr.Tpo $(DEPDIR)/lighttpd-sock_addr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sock_addr.c' object='lighttpd-sock_addr.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-sock_addr.obj `if test -f 'sock_addr.c'; then $(CYGPATH_W) 'sock_addr.c'; else $(CYGPATH_W) '$(srcdir)/sock_addr.c'; fi`
+
+lighttpd-splaytree.o: splaytree.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-splaytree.o -MD -MP -MF $(DEPDIR)/lighttpd-splaytree.Tpo -c -o lighttpd-splaytree.o `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-splaytree.Tpo $(DEPDIR)/lighttpd-splaytree.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='splaytree.c' object='lighttpd-splaytree.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-splaytree.o `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+
+lighttpd-splaytree.obj: splaytree.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-splaytree.obj -MD -MP -MF $(DEPDIR)/lighttpd-splaytree.Tpo -c -o lighttpd-splaytree.obj `if test -f 'splaytree.c'; then $(CYGPATH_W) 'splaytree.c'; else $(CYGPATH_W) '$(srcdir)/splaytree.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-splaytree.Tpo $(DEPDIR)/lighttpd-splaytree.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='splaytree.c' object='lighttpd-splaytree.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-splaytree.obj `if test -f 'splaytree.c'; then $(CYGPATH_W) 'splaytree.c'; else $(CYGPATH_W) '$(srcdir)/splaytree.c'; fi`
+
+lighttpd-safe_memclear.o: safe_memclear.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-safe_memclear.o -MD -MP -MF $(DEPDIR)/lighttpd-safe_memclear.Tpo -c -o lighttpd-safe_memclear.o `test -f 'safe_memclear.c' || echo '$(srcdir)/'`safe_memclear.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-safe_memclear.Tpo $(DEPDIR)/lighttpd-safe_memclear.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='safe_memclear.c' object='lighttpd-safe_memclear.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-safe_memclear.o `test -f 'safe_memclear.c' || echo '$(srcdir)/'`safe_memclear.c
+
+lighttpd-safe_memclear.obj: safe_memclear.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-safe_memclear.obj -MD -MP -MF $(DEPDIR)/lighttpd-safe_memclear.Tpo -c -o lighttpd-safe_memclear.obj `if test -f 'safe_memclear.c'; then $(CYGPATH_W) 'safe_memclear.c'; else $(CYGPATH_W) '$(srcdir)/safe_memclear.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-safe_memclear.Tpo $(DEPDIR)/lighttpd-safe_memclear.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='safe_memclear.c' object='lighttpd-safe_memclear.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-safe_memclear.obj `if test -f 'safe_memclear.c'; then $(CYGPATH_W) 'safe_memclear.c'; else $(CYGPATH_W) '$(srcdir)/safe_memclear.c'; fi`
+
+lighttpd-mod_access.o: mod_access.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_access.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_access.Tpo -c -o lighttpd-mod_access.o `test -f 'mod_access.c' || echo '$(srcdir)/'`mod_access.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_access.Tpo $(DEPDIR)/lighttpd-mod_access.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_access.c' object='lighttpd-mod_access.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_access.o `test -f 'mod_access.c' || echo '$(srcdir)/'`mod_access.c
+
+lighttpd-mod_access.obj: mod_access.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_access.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_access.Tpo -c -o lighttpd-mod_access.obj `if test -f 'mod_access.c'; then $(CYGPATH_W) 'mod_access.c'; else $(CYGPATH_W) '$(srcdir)/mod_access.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_access.Tpo $(DEPDIR)/lighttpd-mod_access.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_access.c' object='lighttpd-mod_access.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_access.obj `if test -f 'mod_access.c'; then $(CYGPATH_W) 'mod_access.c'; else $(CYGPATH_W) '$(srcdir)/mod_access.c'; fi`
+
+lighttpd-mod_accesslog.o: mod_accesslog.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_accesslog.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_accesslog.Tpo -c -o lighttpd-mod_accesslog.o `test -f 'mod_accesslog.c' || echo '$(srcdir)/'`mod_accesslog.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_accesslog.Tpo $(DEPDIR)/lighttpd-mod_accesslog.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_accesslog.c' object='lighttpd-mod_accesslog.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_accesslog.o `test -f 'mod_accesslog.c' || echo '$(srcdir)/'`mod_accesslog.c
+
+lighttpd-mod_accesslog.obj: mod_accesslog.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_accesslog.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_accesslog.Tpo -c -o lighttpd-mod_accesslog.obj `if test -f 'mod_accesslog.c'; then $(CYGPATH_W) 'mod_accesslog.c'; else $(CYGPATH_W) '$(srcdir)/mod_accesslog.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_accesslog.Tpo $(DEPDIR)/lighttpd-mod_accesslog.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_accesslog.c' object='lighttpd-mod_accesslog.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_accesslog.obj `if test -f 'mod_accesslog.c'; then $(CYGPATH_W) 'mod_accesslog.c'; else $(CYGPATH_W) '$(srcdir)/mod_accesslog.c'; fi`
+
+lighttpd-mod_alias.o: mod_alias.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_alias.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_alias.Tpo -c -o lighttpd-mod_alias.o `test -f 'mod_alias.c' || echo '$(srcdir)/'`mod_alias.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_alias.Tpo $(DEPDIR)/lighttpd-mod_alias.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_alias.c' object='lighttpd-mod_alias.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_alias.o `test -f 'mod_alias.c' || echo '$(srcdir)/'`mod_alias.c
+
+lighttpd-mod_alias.obj: mod_alias.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_alias.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_alias.Tpo -c -o lighttpd-mod_alias.obj `if test -f 'mod_alias.c'; then $(CYGPATH_W) 'mod_alias.c'; else $(CYGPATH_W) '$(srcdir)/mod_alias.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_alias.Tpo $(DEPDIR)/lighttpd-mod_alias.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_alias.c' object='lighttpd-mod_alias.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_alias.obj `if test -f 'mod_alias.c'; then $(CYGPATH_W) 'mod_alias.c'; else $(CYGPATH_W) '$(srcdir)/mod_alias.c'; fi`
+
+lighttpd-mod_auth.o: mod_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_auth.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_auth.Tpo -c -o lighttpd-mod_auth.o `test -f 'mod_auth.c' || echo '$(srcdir)/'`mod_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_auth.Tpo $(DEPDIR)/lighttpd-mod_auth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_auth.c' object='lighttpd-mod_auth.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_auth.o `test -f 'mod_auth.c' || echo '$(srcdir)/'`mod_auth.c
+
+lighttpd-mod_auth.obj: mod_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_auth.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_auth.Tpo -c -o lighttpd-mod_auth.obj `if test -f 'mod_auth.c'; then $(CYGPATH_W) 'mod_auth.c'; else $(CYGPATH_W) '$(srcdir)/mod_auth.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_auth.Tpo $(DEPDIR)/lighttpd-mod_auth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_auth.c' object='lighttpd-mod_auth.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_auth.obj `if test -f 'mod_auth.c'; then $(CYGPATH_W) 'mod_auth.c'; else $(CYGPATH_W) '$(srcdir)/mod_auth.c'; fi`
+
+lighttpd-mod_authn_file.o: mod_authn_file.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_file.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_file.Tpo -c -o lighttpd-mod_authn_file.o `test -f 'mod_authn_file.c' || echo '$(srcdir)/'`mod_authn_file.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_file.Tpo $(DEPDIR)/lighttpd-mod_authn_file.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_file.c' object='lighttpd-mod_authn_file.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_file.o `test -f 'mod_authn_file.c' || echo '$(srcdir)/'`mod_authn_file.c
+
+lighttpd-mod_authn_file.obj: mod_authn_file.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_file.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_file.Tpo -c -o lighttpd-mod_authn_file.obj `if test -f 'mod_authn_file.c'; then $(CYGPATH_W) 'mod_authn_file.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_file.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_file.Tpo $(DEPDIR)/lighttpd-mod_authn_file.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_file.c' object='lighttpd-mod_authn_file.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_file.obj `if test -f 'mod_authn_file.c'; then $(CYGPATH_W) 'mod_authn_file.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_file.c'; fi`
+
+lighttpd-mod_cgi.o: mod_cgi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cgi.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_cgi.Tpo -c -o lighttpd-mod_cgi.o `test -f 'mod_cgi.c' || echo '$(srcdir)/'`mod_cgi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cgi.Tpo $(DEPDIR)/lighttpd-mod_cgi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cgi.c' object='lighttpd-mod_cgi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cgi.o `test -f 'mod_cgi.c' || echo '$(srcdir)/'`mod_cgi.c
+
+lighttpd-mod_cgi.obj: mod_cgi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cgi.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_cgi.Tpo -c -o lighttpd-mod_cgi.obj `if test -f 'mod_cgi.c'; then $(CYGPATH_W) 'mod_cgi.c'; else $(CYGPATH_W) '$(srcdir)/mod_cgi.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cgi.Tpo $(DEPDIR)/lighttpd-mod_cgi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cgi.c' object='lighttpd-mod_cgi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cgi.obj `if test -f 'mod_cgi.c'; then $(CYGPATH_W) 'mod_cgi.c'; else $(CYGPATH_W) '$(srcdir)/mod_cgi.c'; fi`
+
+lighttpd-mod_compress.o: mod_compress.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_compress.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_compress.Tpo -c -o lighttpd-mod_compress.o `test -f 'mod_compress.c' || echo '$(srcdir)/'`mod_compress.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_compress.Tpo $(DEPDIR)/lighttpd-mod_compress.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_compress.c' object='lighttpd-mod_compress.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_compress.o `test -f 'mod_compress.c' || echo '$(srcdir)/'`mod_compress.c
+
+lighttpd-mod_compress.obj: mod_compress.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_compress.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_compress.Tpo -c -o lighttpd-mod_compress.obj `if test -f 'mod_compress.c'; then $(CYGPATH_W) 'mod_compress.c'; else $(CYGPATH_W) '$(srcdir)/mod_compress.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_compress.Tpo $(DEPDIR)/lighttpd-mod_compress.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_compress.c' object='lighttpd-mod_compress.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_compress.obj `if test -f 'mod_compress.c'; then $(CYGPATH_W) 'mod_compress.c'; else $(CYGPATH_W) '$(srcdir)/mod_compress.c'; fi`
+
+lighttpd-mod_deflate.o: mod_deflate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_deflate.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_deflate.Tpo -c -o lighttpd-mod_deflate.o `test -f 'mod_deflate.c' || echo '$(srcdir)/'`mod_deflate.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_deflate.Tpo $(DEPDIR)/lighttpd-mod_deflate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_deflate.c' object='lighttpd-mod_deflate.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_deflate.o `test -f 'mod_deflate.c' || echo '$(srcdir)/'`mod_deflate.c
+
+lighttpd-mod_deflate.obj: mod_deflate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_deflate.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_deflate.Tpo -c -o lighttpd-mod_deflate.obj `if test -f 'mod_deflate.c'; then $(CYGPATH_W) 'mod_deflate.c'; else $(CYGPATH_W) '$(srcdir)/mod_deflate.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_deflate.Tpo $(DEPDIR)/lighttpd-mod_deflate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_deflate.c' object='lighttpd-mod_deflate.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_deflate.obj `if test -f 'mod_deflate.c'; then $(CYGPATH_W) 'mod_deflate.c'; else $(CYGPATH_W) '$(srcdir)/mod_deflate.c'; fi`
+
+lighttpd-mod_dirlisting.o: mod_dirlisting.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_dirlisting.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_dirlisting.Tpo -c -o lighttpd-mod_dirlisting.o `test -f 'mod_dirlisting.c' || echo '$(srcdir)/'`mod_dirlisting.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_dirlisting.Tpo $(DEPDIR)/lighttpd-mod_dirlisting.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_dirlisting.c' object='lighttpd-mod_dirlisting.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_dirlisting.o `test -f 'mod_dirlisting.c' || echo '$(srcdir)/'`mod_dirlisting.c
+
+lighttpd-mod_dirlisting.obj: mod_dirlisting.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_dirlisting.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_dirlisting.Tpo -c -o lighttpd-mod_dirlisting.obj `if test -f 'mod_dirlisting.c'; then $(CYGPATH_W) 'mod_dirlisting.c'; else $(CYGPATH_W) '$(srcdir)/mod_dirlisting.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_dirlisting.Tpo $(DEPDIR)/lighttpd-mod_dirlisting.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_dirlisting.c' object='lighttpd-mod_dirlisting.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_dirlisting.obj `if test -f 'mod_dirlisting.c'; then $(CYGPATH_W) 'mod_dirlisting.c'; else $(CYGPATH_W) '$(srcdir)/mod_dirlisting.c'; fi`
+
+lighttpd-mod_evasive.o: mod_evasive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_evasive.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_evasive.Tpo -c -o lighttpd-mod_evasive.o `test -f 'mod_evasive.c' || echo '$(srcdir)/'`mod_evasive.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_evasive.Tpo $(DEPDIR)/lighttpd-mod_evasive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_evasive.c' object='lighttpd-mod_evasive.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_evasive.o `test -f 'mod_evasive.c' || echo '$(srcdir)/'`mod_evasive.c
+
+lighttpd-mod_evasive.obj: mod_evasive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_evasive.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_evasive.Tpo -c -o lighttpd-mod_evasive.obj `if test -f 'mod_evasive.c'; then $(CYGPATH_W) 'mod_evasive.c'; else $(CYGPATH_W) '$(srcdir)/mod_evasive.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_evasive.Tpo $(DEPDIR)/lighttpd-mod_evasive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_evasive.c' object='lighttpd-mod_evasive.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_evasive.obj `if test -f 'mod_evasive.c'; then $(CYGPATH_W) 'mod_evasive.c'; else $(CYGPATH_W) '$(srcdir)/mod_evasive.c'; fi`
+
+lighttpd-mod_expire.o: mod_expire.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_expire.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_expire.Tpo -c -o lighttpd-mod_expire.o `test -f 'mod_expire.c' || echo '$(srcdir)/'`mod_expire.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_expire.Tpo $(DEPDIR)/lighttpd-mod_expire.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_expire.c' object='lighttpd-mod_expire.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_expire.o `test -f 'mod_expire.c' || echo '$(srcdir)/'`mod_expire.c
+
+lighttpd-mod_expire.obj: mod_expire.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_expire.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_expire.Tpo -c -o lighttpd-mod_expire.obj `if test -f 'mod_expire.c'; then $(CYGPATH_W) 'mod_expire.c'; else $(CYGPATH_W) '$(srcdir)/mod_expire.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_expire.Tpo $(DEPDIR)/lighttpd-mod_expire.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_expire.c' object='lighttpd-mod_expire.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_expire.obj `if test -f 'mod_expire.c'; then $(CYGPATH_W) 'mod_expire.c'; else $(CYGPATH_W) '$(srcdir)/mod_expire.c'; fi`
+
+lighttpd-mod_extforward.o: mod_extforward.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_extforward.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_extforward.Tpo -c -o lighttpd-mod_extforward.o `test -f 'mod_extforward.c' || echo '$(srcdir)/'`mod_extforward.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_extforward.Tpo $(DEPDIR)/lighttpd-mod_extforward.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_extforward.c' object='lighttpd-mod_extforward.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_extforward.o `test -f 'mod_extforward.c' || echo '$(srcdir)/'`mod_extforward.c
+
+lighttpd-mod_extforward.obj: mod_extforward.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_extforward.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_extforward.Tpo -c -o lighttpd-mod_extforward.obj `if test -f 'mod_extforward.c'; then $(CYGPATH_W) 'mod_extforward.c'; else $(CYGPATH_W) '$(srcdir)/mod_extforward.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_extforward.Tpo $(DEPDIR)/lighttpd-mod_extforward.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_extforward.c' object='lighttpd-mod_extforward.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_extforward.obj `if test -f 'mod_extforward.c'; then $(CYGPATH_W) 'mod_extforward.c'; else $(CYGPATH_W) '$(srcdir)/mod_extforward.c'; fi`
+
+lighttpd-mod_fastcgi.o: mod_fastcgi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_fastcgi.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_fastcgi.Tpo -c -o lighttpd-mod_fastcgi.o `test -f 'mod_fastcgi.c' || echo '$(srcdir)/'`mod_fastcgi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_fastcgi.Tpo $(DEPDIR)/lighttpd-mod_fastcgi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_fastcgi.c' object='lighttpd-mod_fastcgi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_fastcgi.o `test -f 'mod_fastcgi.c' || echo '$(srcdir)/'`mod_fastcgi.c
+
+lighttpd-mod_fastcgi.obj: mod_fastcgi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_fastcgi.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_fastcgi.Tpo -c -o lighttpd-mod_fastcgi.obj `if test -f 'mod_fastcgi.c'; then $(CYGPATH_W) 'mod_fastcgi.c'; else $(CYGPATH_W) '$(srcdir)/mod_fastcgi.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_fastcgi.Tpo $(DEPDIR)/lighttpd-mod_fastcgi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_fastcgi.c' object='lighttpd-mod_fastcgi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_fastcgi.obj `if test -f 'mod_fastcgi.c'; then $(CYGPATH_W) 'mod_fastcgi.c'; else $(CYGPATH_W) '$(srcdir)/mod_fastcgi.c'; fi`
+
+lighttpd-mod_flv_streaming.o: mod_flv_streaming.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_flv_streaming.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_flv_streaming.Tpo -c -o lighttpd-mod_flv_streaming.o `test -f 'mod_flv_streaming.c' || echo '$(srcdir)/'`mod_flv_streaming.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_flv_streaming.Tpo $(DEPDIR)/lighttpd-mod_flv_streaming.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_flv_streaming.c' object='lighttpd-mod_flv_streaming.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_flv_streaming.o `test -f 'mod_flv_streaming.c' || echo '$(srcdir)/'`mod_flv_streaming.c
+
+lighttpd-mod_flv_streaming.obj: mod_flv_streaming.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_flv_streaming.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_flv_streaming.Tpo -c -o lighttpd-mod_flv_streaming.obj `if test -f 'mod_flv_streaming.c'; then $(CYGPATH_W) 'mod_flv_streaming.c'; else $(CYGPATH_W) '$(srcdir)/mod_flv_streaming.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_flv_streaming.Tpo $(DEPDIR)/lighttpd-mod_flv_streaming.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_flv_streaming.c' object='lighttpd-mod_flv_streaming.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_flv_streaming.obj `if test -f 'mod_flv_streaming.c'; then $(CYGPATH_W) 'mod_flv_streaming.c'; else $(CYGPATH_W) '$(srcdir)/mod_flv_streaming.c'; fi`
+
+lighttpd-mod_indexfile.o: mod_indexfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_indexfile.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_indexfile.Tpo -c -o lighttpd-mod_indexfile.o `test -f 'mod_indexfile.c' || echo '$(srcdir)/'`mod_indexfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_indexfile.Tpo $(DEPDIR)/lighttpd-mod_indexfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_indexfile.c' object='lighttpd-mod_indexfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_indexfile.o `test -f 'mod_indexfile.c' || echo '$(srcdir)/'`mod_indexfile.c
+
+lighttpd-mod_indexfile.obj: mod_indexfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_indexfile.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_indexfile.Tpo -c -o lighttpd-mod_indexfile.obj `if test -f 'mod_indexfile.c'; then $(CYGPATH_W) 'mod_indexfile.c'; else $(CYGPATH_W) '$(srcdir)/mod_indexfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_indexfile.Tpo $(DEPDIR)/lighttpd-mod_indexfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_indexfile.c' object='lighttpd-mod_indexfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_indexfile.obj `if test -f 'mod_indexfile.c'; then $(CYGPATH_W) 'mod_indexfile.c'; else $(CYGPATH_W) '$(srcdir)/mod_indexfile.c'; fi`
+
+lighttpd-mod_proxy.o: mod_proxy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_proxy.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_proxy.Tpo -c -o lighttpd-mod_proxy.o `test -f 'mod_proxy.c' || echo '$(srcdir)/'`mod_proxy.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_proxy.Tpo $(DEPDIR)/lighttpd-mod_proxy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_proxy.c' object='lighttpd-mod_proxy.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_proxy.o `test -f 'mod_proxy.c' || echo '$(srcdir)/'`mod_proxy.c
+
+lighttpd-mod_proxy.obj: mod_proxy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_proxy.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_proxy.Tpo -c -o lighttpd-mod_proxy.obj `if test -f 'mod_proxy.c'; then $(CYGPATH_W) 'mod_proxy.c'; else $(CYGPATH_W) '$(srcdir)/mod_proxy.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_proxy.Tpo $(DEPDIR)/lighttpd-mod_proxy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_proxy.c' object='lighttpd-mod_proxy.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_proxy.obj `if test -f 'mod_proxy.c'; then $(CYGPATH_W) 'mod_proxy.c'; else $(CYGPATH_W) '$(srcdir)/mod_proxy.c'; fi`
+
+lighttpd-mod_redirect.o: mod_redirect.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_redirect.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_redirect.Tpo -c -o lighttpd-mod_redirect.o `test -f 'mod_redirect.c' || echo '$(srcdir)/'`mod_redirect.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_redirect.Tpo $(DEPDIR)/lighttpd-mod_redirect.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_redirect.c' object='lighttpd-mod_redirect.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_redirect.o `test -f 'mod_redirect.c' || echo '$(srcdir)/'`mod_redirect.c
+
+lighttpd-mod_redirect.obj: mod_redirect.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_redirect.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_redirect.Tpo -c -o lighttpd-mod_redirect.obj `if test -f 'mod_redirect.c'; then $(CYGPATH_W) 'mod_redirect.c'; else $(CYGPATH_W) '$(srcdir)/mod_redirect.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_redirect.Tpo $(DEPDIR)/lighttpd-mod_redirect.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_redirect.c' object='lighttpd-mod_redirect.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_redirect.obj `if test -f 'mod_redirect.c'; then $(CYGPATH_W) 'mod_redirect.c'; else $(CYGPATH_W) '$(srcdir)/mod_redirect.c'; fi`
+
+lighttpd-mod_rewrite.o: mod_rewrite.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_rewrite.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_rewrite.Tpo -c -o lighttpd-mod_rewrite.o `test -f 'mod_rewrite.c' || echo '$(srcdir)/'`mod_rewrite.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_rewrite.Tpo $(DEPDIR)/lighttpd-mod_rewrite.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_rewrite.c' object='lighttpd-mod_rewrite.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_rewrite.o `test -f 'mod_rewrite.c' || echo '$(srcdir)/'`mod_rewrite.c
+
+lighttpd-mod_rewrite.obj: mod_rewrite.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_rewrite.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_rewrite.Tpo -c -o lighttpd-mod_rewrite.obj `if test -f 'mod_rewrite.c'; then $(CYGPATH_W) 'mod_rewrite.c'; else $(CYGPATH_W) '$(srcdir)/mod_rewrite.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_rewrite.Tpo $(DEPDIR)/lighttpd-mod_rewrite.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_rewrite.c' object='lighttpd-mod_rewrite.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_rewrite.obj `if test -f 'mod_rewrite.c'; then $(CYGPATH_W) 'mod_rewrite.c'; else $(CYGPATH_W) '$(srcdir)/mod_rewrite.c'; fi`
+
+lighttpd-mod_rrdtool.o: mod_rrdtool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_rrdtool.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_rrdtool.Tpo -c -o lighttpd-mod_rrdtool.o `test -f 'mod_rrdtool.c' || echo '$(srcdir)/'`mod_rrdtool.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_rrdtool.Tpo $(DEPDIR)/lighttpd-mod_rrdtool.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_rrdtool.c' object='lighttpd-mod_rrdtool.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_rrdtool.o `test -f 'mod_rrdtool.c' || echo '$(srcdir)/'`mod_rrdtool.c
+
+lighttpd-mod_rrdtool.obj: mod_rrdtool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_rrdtool.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_rrdtool.Tpo -c -o lighttpd-mod_rrdtool.obj `if test -f 'mod_rrdtool.c'; then $(CYGPATH_W) 'mod_rrdtool.c'; else $(CYGPATH_W) '$(srcdir)/mod_rrdtool.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_rrdtool.Tpo $(DEPDIR)/lighttpd-mod_rrdtool.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_rrdtool.c' object='lighttpd-mod_rrdtool.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_rrdtool.obj `if test -f 'mod_rrdtool.c'; then $(CYGPATH_W) 'mod_rrdtool.c'; else $(CYGPATH_W) '$(srcdir)/mod_rrdtool.c'; fi`
+
+lighttpd-mod_scgi.o: mod_scgi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_scgi.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_scgi.Tpo -c -o lighttpd-mod_scgi.o `test -f 'mod_scgi.c' || echo '$(srcdir)/'`mod_scgi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_scgi.Tpo $(DEPDIR)/lighttpd-mod_scgi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_scgi.c' object='lighttpd-mod_scgi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_scgi.o `test -f 'mod_scgi.c' || echo '$(srcdir)/'`mod_scgi.c
+
+lighttpd-mod_scgi.obj: mod_scgi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_scgi.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_scgi.Tpo -c -o lighttpd-mod_scgi.obj `if test -f 'mod_scgi.c'; then $(CYGPATH_W) 'mod_scgi.c'; else $(CYGPATH_W) '$(srcdir)/mod_scgi.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_scgi.Tpo $(DEPDIR)/lighttpd-mod_scgi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_scgi.c' object='lighttpd-mod_scgi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_scgi.obj `if test -f 'mod_scgi.c'; then $(CYGPATH_W) 'mod_scgi.c'; else $(CYGPATH_W) '$(srcdir)/mod_scgi.c'; fi`
+
+lighttpd-mod_secdownload.o: mod_secdownload.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_secdownload.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_secdownload.Tpo -c -o lighttpd-mod_secdownload.o `test -f 'mod_secdownload.c' || echo '$(srcdir)/'`mod_secdownload.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_secdownload.Tpo $(DEPDIR)/lighttpd-mod_secdownload.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_secdownload.c' object='lighttpd-mod_secdownload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_secdownload.o `test -f 'mod_secdownload.c' || echo '$(srcdir)/'`mod_secdownload.c
+
+lighttpd-mod_secdownload.obj: mod_secdownload.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_secdownload.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_secdownload.Tpo -c -o lighttpd-mod_secdownload.obj `if test -f 'mod_secdownload.c'; then $(CYGPATH_W) 'mod_secdownload.c'; else $(CYGPATH_W) '$(srcdir)/mod_secdownload.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_secdownload.Tpo $(DEPDIR)/lighttpd-mod_secdownload.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_secdownload.c' object='lighttpd-mod_secdownload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_secdownload.obj `if test -f 'mod_secdownload.c'; then $(CYGPATH_W) 'mod_secdownload.c'; else $(CYGPATH_W) '$(srcdir)/mod_secdownload.c'; fi`
+
+lighttpd-mod_setenv.o: mod_setenv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_setenv.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_setenv.Tpo -c -o lighttpd-mod_setenv.o `test -f 'mod_setenv.c' || echo '$(srcdir)/'`mod_setenv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_setenv.Tpo $(DEPDIR)/lighttpd-mod_setenv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_setenv.c' object='lighttpd-mod_setenv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_setenv.o `test -f 'mod_setenv.c' || echo '$(srcdir)/'`mod_setenv.c
+
+lighttpd-mod_setenv.obj: mod_setenv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_setenv.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_setenv.Tpo -c -o lighttpd-mod_setenv.obj `if test -f 'mod_setenv.c'; then $(CYGPATH_W) 'mod_setenv.c'; else $(CYGPATH_W) '$(srcdir)/mod_setenv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_setenv.Tpo $(DEPDIR)/lighttpd-mod_setenv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_setenv.c' object='lighttpd-mod_setenv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_setenv.obj `if test -f 'mod_setenv.c'; then $(CYGPATH_W) 'mod_setenv.c'; else $(CYGPATH_W) '$(srcdir)/mod_setenv.c'; fi`
+
+lighttpd-mod_simple_vhost.o: mod_simple_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_simple_vhost.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_simple_vhost.Tpo -c -o lighttpd-mod_simple_vhost.o `test -f 'mod_simple_vhost.c' || echo '$(srcdir)/'`mod_simple_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_simple_vhost.Tpo $(DEPDIR)/lighttpd-mod_simple_vhost.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_simple_vhost.c' object='lighttpd-mod_simple_vhost.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_simple_vhost.o `test -f 'mod_simple_vhost.c' || echo '$(srcdir)/'`mod_simple_vhost.c
+
+lighttpd-mod_simple_vhost.obj: mod_simple_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_simple_vhost.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_simple_vhost.Tpo -c -o lighttpd-mod_simple_vhost.obj `if test -f 'mod_simple_vhost.c'; then $(CYGPATH_W) 'mod_simple_vhost.c'; else $(CYGPATH_W) '$(srcdir)/mod_simple_vhost.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_simple_vhost.Tpo $(DEPDIR)/lighttpd-mod_simple_vhost.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_simple_vhost.c' object='lighttpd-mod_simple_vhost.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_simple_vhost.obj `if test -f 'mod_simple_vhost.c'; then $(CYGPATH_W) 'mod_simple_vhost.c'; else $(CYGPATH_W) '$(srcdir)/mod_simple_vhost.c'; fi`
+
+lighttpd-mod_ssi_exprparser.o: mod_ssi_exprparser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_ssi_exprparser.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_ssi_exprparser.Tpo -c -o lighttpd-mod_ssi_exprparser.o `test -f 'mod_ssi_exprparser.c' || echo '$(srcdir)/'`mod_ssi_exprparser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_ssi_exprparser.Tpo $(DEPDIR)/lighttpd-mod_ssi_exprparser.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_ssi_exprparser.c' object='lighttpd-mod_ssi_exprparser.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_ssi_exprparser.o `test -f 'mod_ssi_exprparser.c' || echo '$(srcdir)/'`mod_ssi_exprparser.c
+
+lighttpd-mod_ssi_exprparser.obj: mod_ssi_exprparser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_ssi_exprparser.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_ssi_exprparser.Tpo -c -o lighttpd-mod_ssi_exprparser.obj `if test -f 'mod_ssi_exprparser.c'; then $(CYGPATH_W) 'mod_ssi_exprparser.c'; else $(CYGPATH_W) '$(srcdir)/mod_ssi_exprparser.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_ssi_exprparser.Tpo $(DEPDIR)/lighttpd-mod_ssi_exprparser.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_ssi_exprparser.c' object='lighttpd-mod_ssi_exprparser.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_ssi_exprparser.obj `if test -f 'mod_ssi_exprparser.c'; then $(CYGPATH_W) 'mod_ssi_exprparser.c'; else $(CYGPATH_W) '$(srcdir)/mod_ssi_exprparser.c'; fi`
+
+lighttpd-mod_ssi_expr.o: mod_ssi_expr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_ssi_expr.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_ssi_expr.Tpo -c -o lighttpd-mod_ssi_expr.o `test -f 'mod_ssi_expr.c' || echo '$(srcdir)/'`mod_ssi_expr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_ssi_expr.Tpo $(DEPDIR)/lighttpd-mod_ssi_expr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_ssi_expr.c' object='lighttpd-mod_ssi_expr.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_ssi_expr.o `test -f 'mod_ssi_expr.c' || echo '$(srcdir)/'`mod_ssi_expr.c
+
+lighttpd-mod_ssi_expr.obj: mod_ssi_expr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_ssi_expr.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_ssi_expr.Tpo -c -o lighttpd-mod_ssi_expr.obj `if test -f 'mod_ssi_expr.c'; then $(CYGPATH_W) 'mod_ssi_expr.c'; else $(CYGPATH_W) '$(srcdir)/mod_ssi_expr.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_ssi_expr.Tpo $(DEPDIR)/lighttpd-mod_ssi_expr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_ssi_expr.c' object='lighttpd-mod_ssi_expr.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_ssi_expr.obj `if test -f 'mod_ssi_expr.c'; then $(CYGPATH_W) 'mod_ssi_expr.c'; else $(CYGPATH_W) '$(srcdir)/mod_ssi_expr.c'; fi`
+
+lighttpd-mod_ssi.o: mod_ssi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_ssi.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_ssi.Tpo -c -o lighttpd-mod_ssi.o `test -f 'mod_ssi.c' || echo '$(srcdir)/'`mod_ssi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_ssi.Tpo $(DEPDIR)/lighttpd-mod_ssi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_ssi.c' object='lighttpd-mod_ssi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_ssi.o `test -f 'mod_ssi.c' || echo '$(srcdir)/'`mod_ssi.c
+
+lighttpd-mod_ssi.obj: mod_ssi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_ssi.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_ssi.Tpo -c -o lighttpd-mod_ssi.obj `if test -f 'mod_ssi.c'; then $(CYGPATH_W) 'mod_ssi.c'; else $(CYGPATH_W) '$(srcdir)/mod_ssi.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_ssi.Tpo $(DEPDIR)/lighttpd-mod_ssi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_ssi.c' object='lighttpd-mod_ssi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_ssi.obj `if test -f 'mod_ssi.c'; then $(CYGPATH_W) 'mod_ssi.c'; else $(CYGPATH_W) '$(srcdir)/mod_ssi.c'; fi`
+
+lighttpd-mod_staticfile.o: mod_staticfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_staticfile.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_staticfile.Tpo -c -o lighttpd-mod_staticfile.o `test -f 'mod_staticfile.c' || echo '$(srcdir)/'`mod_staticfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_staticfile.Tpo $(DEPDIR)/lighttpd-mod_staticfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_staticfile.c' object='lighttpd-mod_staticfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_staticfile.o `test -f 'mod_staticfile.c' || echo '$(srcdir)/'`mod_staticfile.c
+
+lighttpd-mod_staticfile.obj: mod_staticfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_staticfile.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_staticfile.Tpo -c -o lighttpd-mod_staticfile.obj `if test -f 'mod_staticfile.c'; then $(CYGPATH_W) 'mod_staticfile.c'; else $(CYGPATH_W) '$(srcdir)/mod_staticfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_staticfile.Tpo $(DEPDIR)/lighttpd-mod_staticfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_staticfile.c' object='lighttpd-mod_staticfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_staticfile.obj `if test -f 'mod_staticfile.c'; then $(CYGPATH_W) 'mod_staticfile.c'; else $(CYGPATH_W) '$(srcdir)/mod_staticfile.c'; fi`
+
+lighttpd-mod_status.o: mod_status.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_status.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_status.Tpo -c -o lighttpd-mod_status.o `test -f 'mod_status.c' || echo '$(srcdir)/'`mod_status.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_status.Tpo $(DEPDIR)/lighttpd-mod_status.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_status.c' object='lighttpd-mod_status.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_status.o `test -f 'mod_status.c' || echo '$(srcdir)/'`mod_status.c
+
+lighttpd-mod_status.obj: mod_status.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_status.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_status.Tpo -c -o lighttpd-mod_status.obj `if test -f 'mod_status.c'; then $(CYGPATH_W) 'mod_status.c'; else $(CYGPATH_W) '$(srcdir)/mod_status.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_status.Tpo $(DEPDIR)/lighttpd-mod_status.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_status.c' object='lighttpd-mod_status.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_status.obj `if test -f 'mod_status.c'; then $(CYGPATH_W) 'mod_status.c'; else $(CYGPATH_W) '$(srcdir)/mod_status.c'; fi`
+
+lighttpd-mod_uploadprogress.o: mod_uploadprogress.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_uploadprogress.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_uploadprogress.Tpo -c -o lighttpd-mod_uploadprogress.o `test -f 'mod_uploadprogress.c' || echo '$(srcdir)/'`mod_uploadprogress.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_uploadprogress.Tpo $(DEPDIR)/lighttpd-mod_uploadprogress.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_uploadprogress.c' object='lighttpd-mod_uploadprogress.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_uploadprogress.o `test -f 'mod_uploadprogress.c' || echo '$(srcdir)/'`mod_uploadprogress.c
+
+lighttpd-mod_uploadprogress.obj: mod_uploadprogress.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_uploadprogress.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_uploadprogress.Tpo -c -o lighttpd-mod_uploadprogress.obj `if test -f 'mod_uploadprogress.c'; then $(CYGPATH_W) 'mod_uploadprogress.c'; else $(CYGPATH_W) '$(srcdir)/mod_uploadprogress.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_uploadprogress.Tpo $(DEPDIR)/lighttpd-mod_uploadprogress.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_uploadprogress.c' object='lighttpd-mod_uploadprogress.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_uploadprogress.obj `if test -f 'mod_uploadprogress.c'; then $(CYGPATH_W) 'mod_uploadprogress.c'; else $(CYGPATH_W) '$(srcdir)/mod_uploadprogress.c'; fi`
+
+lighttpd-mod_userdir.o: mod_userdir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_userdir.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_userdir.Tpo -c -o lighttpd-mod_userdir.o `test -f 'mod_userdir.c' || echo '$(srcdir)/'`mod_userdir.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_userdir.Tpo $(DEPDIR)/lighttpd-mod_userdir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_userdir.c' object='lighttpd-mod_userdir.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_userdir.o `test -f 'mod_userdir.c' || echo '$(srcdir)/'`mod_userdir.c
+
+lighttpd-mod_userdir.obj: mod_userdir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_userdir.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_userdir.Tpo -c -o lighttpd-mod_userdir.obj `if test -f 'mod_userdir.c'; then $(CYGPATH_W) 'mod_userdir.c'; else $(CYGPATH_W) '$(srcdir)/mod_userdir.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_userdir.Tpo $(DEPDIR)/lighttpd-mod_userdir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_userdir.c' object='lighttpd-mod_userdir.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_userdir.obj `if test -f 'mod_userdir.c'; then $(CYGPATH_W) 'mod_userdir.c'; else $(CYGPATH_W) '$(srcdir)/mod_userdir.c'; fi`
+
+lighttpd-mod_usertrack.o: mod_usertrack.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_usertrack.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_usertrack.Tpo -c -o lighttpd-mod_usertrack.o `test -f 'mod_usertrack.c' || echo '$(srcdir)/'`mod_usertrack.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_usertrack.Tpo $(DEPDIR)/lighttpd-mod_usertrack.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_usertrack.c' object='lighttpd-mod_usertrack.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_usertrack.o `test -f 'mod_usertrack.c' || echo '$(srcdir)/'`mod_usertrack.c
+
+lighttpd-mod_usertrack.obj: mod_usertrack.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_usertrack.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_usertrack.Tpo -c -o lighttpd-mod_usertrack.obj `if test -f 'mod_usertrack.c'; then $(CYGPATH_W) 'mod_usertrack.c'; else $(CYGPATH_W) '$(srcdir)/mod_usertrack.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_usertrack.Tpo $(DEPDIR)/lighttpd-mod_usertrack.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_usertrack.c' object='lighttpd-mod_usertrack.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_usertrack.obj `if test -f 'mod_usertrack.c'; then $(CYGPATH_W) 'mod_usertrack.c'; else $(CYGPATH_W) '$(srcdir)/mod_usertrack.c'; fi`
+
+lighttpd-mod_vhostdb.o: mod_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb.Tpo -c -o lighttpd-mod_vhostdb.o `test -f 'mod_vhostdb.c' || echo '$(srcdir)/'`mod_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb.Tpo $(DEPDIR)/lighttpd-mod_vhostdb.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb.c' object='lighttpd-mod_vhostdb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb.o `test -f 'mod_vhostdb.c' || echo '$(srcdir)/'`mod_vhostdb.c
+
+lighttpd-mod_vhostdb.obj: mod_vhostdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb.Tpo -c -o lighttpd-mod_vhostdb.obj `if test -f 'mod_vhostdb.c'; then $(CYGPATH_W) 'mod_vhostdb.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb.Tpo $(DEPDIR)/lighttpd-mod_vhostdb.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb.c' object='lighttpd-mod_vhostdb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb.obj `if test -f 'mod_vhostdb.c'; then $(CYGPATH_W) 'mod_vhostdb.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb.c'; fi`
+
+lighttpd-mod_webdav.o: mod_webdav.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_webdav.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_webdav.Tpo -c -o lighttpd-mod_webdav.o `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_webdav.Tpo $(DEPDIR)/lighttpd-mod_webdav.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_webdav.c' object='lighttpd-mod_webdav.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_webdav.o `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
+
+lighttpd-mod_webdav.obj: mod_webdav.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_webdav.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_webdav.Tpo -c -o lighttpd-mod_webdav.obj `if test -f 'mod_webdav.c'; then $(CYGPATH_W) 'mod_webdav.c'; else $(CYGPATH_W) '$(srcdir)/mod_webdav.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_webdav.Tpo $(DEPDIR)/lighttpd-mod_webdav.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_webdav.c' object='lighttpd-mod_webdav.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_webdav.obj `if test -f 'mod_webdav.c'; then $(CYGPATH_W) 'mod_webdav.c'; else $(CYGPATH_W) '$(srcdir)/mod_webdav.c'; fi`
+
+lighttpd-mod_geoip.o: mod_geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_geoip.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_geoip.Tpo -c -o lighttpd-mod_geoip.o `test -f 'mod_geoip.c' || echo '$(srcdir)/'`mod_geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_geoip.Tpo $(DEPDIR)/lighttpd-mod_geoip.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_geoip.c' object='lighttpd-mod_geoip.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_geoip.o `test -f 'mod_geoip.c' || echo '$(srcdir)/'`mod_geoip.c
+
+lighttpd-mod_geoip.obj: mod_geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_geoip.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_geoip.Tpo -c -o lighttpd-mod_geoip.obj `if test -f 'mod_geoip.c'; then $(CYGPATH_W) 'mod_geoip.c'; else $(CYGPATH_W) '$(srcdir)/mod_geoip.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_geoip.Tpo $(DEPDIR)/lighttpd-mod_geoip.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_geoip.c' object='lighttpd-mod_geoip.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_geoip.obj `if test -f 'mod_geoip.c'; then $(CYGPATH_W) 'mod_geoip.c'; else $(CYGPATH_W) '$(srcdir)/mod_geoip.c'; fi`
+
+lighttpd-mod_cml.o: mod_cml.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cml.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_cml.Tpo -c -o lighttpd-mod_cml.o `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cml.Tpo $(DEPDIR)/lighttpd-mod_cml.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml.c' object='lighttpd-mod_cml.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cml.o `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
+
+lighttpd-mod_cml.obj: mod_cml.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cml.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_cml.Tpo -c -o lighttpd-mod_cml.obj `if test -f 'mod_cml.c'; then $(CYGPATH_W) 'mod_cml.c'; else $(CYGPATH_W) '$(srcdir)/mod_cml.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cml.Tpo $(DEPDIR)/lighttpd-mod_cml.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml.c' object='lighttpd-mod_cml.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cml.obj `if test -f 'mod_cml.c'; then $(CYGPATH_W) 'mod_cml.c'; else $(CYGPATH_W) '$(srcdir)/mod_cml.c'; fi`
+
+lighttpd-mod_cml_lua.o: mod_cml_lua.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cml_lua.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_cml_lua.Tpo -c -o lighttpd-mod_cml_lua.o `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cml_lua.Tpo $(DEPDIR)/lighttpd-mod_cml_lua.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_lua.c' object='lighttpd-mod_cml_lua.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cml_lua.o `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
+
+lighttpd-mod_cml_lua.obj: mod_cml_lua.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cml_lua.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_cml_lua.Tpo -c -o lighttpd-mod_cml_lua.obj `if test -f 'mod_cml_lua.c'; then $(CYGPATH_W) 'mod_cml_lua.c'; else $(CYGPATH_W) '$(srcdir)/mod_cml_lua.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cml_lua.Tpo $(DEPDIR)/lighttpd-mod_cml_lua.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_lua.c' object='lighttpd-mod_cml_lua.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cml_lua.obj `if test -f 'mod_cml_lua.c'; then $(CYGPATH_W) 'mod_cml_lua.c'; else $(CYGPATH_W) '$(srcdir)/mod_cml_lua.c'; fi`
+
+lighttpd-mod_cml_funcs.o: mod_cml_funcs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cml_funcs.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_cml_funcs.Tpo -c -o lighttpd-mod_cml_funcs.o `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cml_funcs.Tpo $(DEPDIR)/lighttpd-mod_cml_funcs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_funcs.c' object='lighttpd-mod_cml_funcs.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cml_funcs.o `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+
+lighttpd-mod_cml_funcs.obj: mod_cml_funcs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_cml_funcs.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_cml_funcs.Tpo -c -o lighttpd-mod_cml_funcs.obj `if test -f 'mod_cml_funcs.c'; then $(CYGPATH_W) 'mod_cml_funcs.c'; else $(CYGPATH_W) '$(srcdir)/mod_cml_funcs.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_cml_funcs.Tpo $(DEPDIR)/lighttpd-mod_cml_funcs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_funcs.c' object='lighttpd-mod_cml_funcs.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_cml_funcs.obj `if test -f 'mod_cml_funcs.c'; then $(CYGPATH_W) 'mod_cml_funcs.c'; else $(CYGPATH_W) '$(srcdir)/mod_cml_funcs.c'; fi`
+
+lighttpd-mod_magnet.o: mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_magnet.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_magnet.Tpo -c -o lighttpd-mod_magnet.o `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_magnet.Tpo $(DEPDIR)/lighttpd-mod_magnet.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet.c' object='lighttpd-mod_magnet.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_magnet.o `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+
+lighttpd-mod_magnet.obj: mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_magnet.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_magnet.Tpo -c -o lighttpd-mod_magnet.obj `if test -f 'mod_magnet.c'; then $(CYGPATH_W) 'mod_magnet.c'; else $(CYGPATH_W) '$(srcdir)/mod_magnet.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_magnet.Tpo $(DEPDIR)/lighttpd-mod_magnet.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet.c' object='lighttpd-mod_magnet.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_magnet.obj `if test -f 'mod_magnet.c'; then $(CYGPATH_W) 'mod_magnet.c'; else $(CYGPATH_W) '$(srcdir)/mod_magnet.c'; fi`
+
+lighttpd-mod_magnet_cache.o: mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_magnet_cache.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_magnet_cache.Tpo -c -o lighttpd-mod_magnet_cache.o `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_magnet_cache.Tpo $(DEPDIR)/lighttpd-mod_magnet_cache.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet_cache.c' object='lighttpd-mod_magnet_cache.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_magnet_cache.o `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
+
+lighttpd-mod_magnet_cache.obj: mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_magnet_cache.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_magnet_cache.Tpo -c -o lighttpd-mod_magnet_cache.obj `if test -f 'mod_magnet_cache.c'; then $(CYGPATH_W) 'mod_magnet_cache.c'; else $(CYGPATH_W) '$(srcdir)/mod_magnet_cache.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_magnet_cache.Tpo $(DEPDIR)/lighttpd-mod_magnet_cache.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet_cache.c' object='lighttpd-mod_magnet_cache.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_magnet_cache.obj `if test -f 'mod_magnet_cache.c'; then $(CYGPATH_W) 'mod_magnet_cache.c'; else $(CYGPATH_W) '$(srcdir)/mod_magnet_cache.c'; fi`
+
+lighttpd-mod_authn_gssapi.o: mod_authn_gssapi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_gssapi.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_gssapi.Tpo -c -o lighttpd-mod_authn_gssapi.o `test -f 'mod_authn_gssapi.c' || echo '$(srcdir)/'`mod_authn_gssapi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_gssapi.Tpo $(DEPDIR)/lighttpd-mod_authn_gssapi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_gssapi.c' object='lighttpd-mod_authn_gssapi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_gssapi.o `test -f 'mod_authn_gssapi.c' || echo '$(srcdir)/'`mod_authn_gssapi.c
+
+lighttpd-mod_authn_gssapi.obj: mod_authn_gssapi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_gssapi.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_gssapi.Tpo -c -o lighttpd-mod_authn_gssapi.obj `if test -f 'mod_authn_gssapi.c'; then $(CYGPATH_W) 'mod_authn_gssapi.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_gssapi.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_gssapi.Tpo $(DEPDIR)/lighttpd-mod_authn_gssapi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_gssapi.c' object='lighttpd-mod_authn_gssapi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_gssapi.obj `if test -f 'mod_authn_gssapi.c'; then $(CYGPATH_W) 'mod_authn_gssapi.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_gssapi.c'; fi`
+
+lighttpd-mod_authn_ldap.o: mod_authn_ldap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_ldap.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_ldap.Tpo -c -o lighttpd-mod_authn_ldap.o `test -f 'mod_authn_ldap.c' || echo '$(srcdir)/'`mod_authn_ldap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_ldap.Tpo $(DEPDIR)/lighttpd-mod_authn_ldap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_ldap.c' object='lighttpd-mod_authn_ldap.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_ldap.o `test -f 'mod_authn_ldap.c' || echo '$(srcdir)/'`mod_authn_ldap.c
+
+lighttpd-mod_authn_ldap.obj: mod_authn_ldap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_ldap.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_ldap.Tpo -c -o lighttpd-mod_authn_ldap.obj `if test -f 'mod_authn_ldap.c'; then $(CYGPATH_W) 'mod_authn_ldap.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_ldap.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_ldap.Tpo $(DEPDIR)/lighttpd-mod_authn_ldap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_ldap.c' object='lighttpd-mod_authn_ldap.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_ldap.obj `if test -f 'mod_authn_ldap.c'; then $(CYGPATH_W) 'mod_authn_ldap.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_ldap.c'; fi`
+
+lighttpd-mod_vhostdb_ldap.o: mod_vhostdb_ldap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_ldap.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_ldap.Tpo -c -o lighttpd-mod_vhostdb_ldap.o `test -f 'mod_vhostdb_ldap.c' || echo '$(srcdir)/'`mod_vhostdb_ldap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_ldap.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_ldap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_ldap.c' object='lighttpd-mod_vhostdb_ldap.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_ldap.o `test -f 'mod_vhostdb_ldap.c' || echo '$(srcdir)/'`mod_vhostdb_ldap.c
+
+lighttpd-mod_vhostdb_ldap.obj: mod_vhostdb_ldap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_ldap.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_ldap.Tpo -c -o lighttpd-mod_vhostdb_ldap.obj `if test -f 'mod_vhostdb_ldap.c'; then $(CYGPATH_W) 'mod_vhostdb_ldap.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_ldap.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_ldap.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_ldap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_ldap.c' object='lighttpd-mod_vhostdb_ldap.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_ldap.obj `if test -f 'mod_vhostdb_ldap.c'; then $(CYGPATH_W) 'mod_vhostdb_ldap.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_ldap.c'; fi`
+
+lighttpd-mod_authn_pam.o: mod_authn_pam.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_pam.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_pam.Tpo -c -o lighttpd-mod_authn_pam.o `test -f 'mod_authn_pam.c' || echo '$(srcdir)/'`mod_authn_pam.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_pam.Tpo $(DEPDIR)/lighttpd-mod_authn_pam.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_pam.c' object='lighttpd-mod_authn_pam.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_pam.o `test -f 'mod_authn_pam.c' || echo '$(srcdir)/'`mod_authn_pam.c
+
+lighttpd-mod_authn_pam.obj: mod_authn_pam.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_pam.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_pam.Tpo -c -o lighttpd-mod_authn_pam.obj `if test -f 'mod_authn_pam.c'; then $(CYGPATH_W) 'mod_authn_pam.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_pam.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_pam.Tpo $(DEPDIR)/lighttpd-mod_authn_pam.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_pam.c' object='lighttpd-mod_authn_pam.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_pam.obj `if test -f 'mod_authn_pam.c'; then $(CYGPATH_W) 'mod_authn_pam.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_pam.c'; fi`
+
+lighttpd-mod_authn_mysql.o: mod_authn_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_mysql.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_mysql.Tpo -c -o lighttpd-mod_authn_mysql.o `test -f 'mod_authn_mysql.c' || echo '$(srcdir)/'`mod_authn_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_mysql.Tpo $(DEPDIR)/lighttpd-mod_authn_mysql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_mysql.c' object='lighttpd-mod_authn_mysql.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_mysql.o `test -f 'mod_authn_mysql.c' || echo '$(srcdir)/'`mod_authn_mysql.c
+
+lighttpd-mod_authn_mysql.obj: mod_authn_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_authn_mysql.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_authn_mysql.Tpo -c -o lighttpd-mod_authn_mysql.obj `if test -f 'mod_authn_mysql.c'; then $(CYGPATH_W) 'mod_authn_mysql.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_mysql.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_authn_mysql.Tpo $(DEPDIR)/lighttpd-mod_authn_mysql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_authn_mysql.c' object='lighttpd-mod_authn_mysql.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_authn_mysql.obj `if test -f 'mod_authn_mysql.c'; then $(CYGPATH_W) 'mod_authn_mysql.c'; else $(CYGPATH_W) '$(srcdir)/mod_authn_mysql.c'; fi`
+
+lighttpd-mod_mysql_vhost.o: mod_mysql_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_mysql_vhost.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_mysql_vhost.Tpo -c -o lighttpd-mod_mysql_vhost.o `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_mysql_vhost.Tpo $(DEPDIR)/lighttpd-mod_mysql_vhost.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_mysql_vhost.c' object='lighttpd-mod_mysql_vhost.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_mysql_vhost.o `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
+
+lighttpd-mod_mysql_vhost.obj: mod_mysql_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_mysql_vhost.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_mysql_vhost.Tpo -c -o lighttpd-mod_mysql_vhost.obj `if test -f 'mod_mysql_vhost.c'; then $(CYGPATH_W) 'mod_mysql_vhost.c'; else $(CYGPATH_W) '$(srcdir)/mod_mysql_vhost.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_mysql_vhost.Tpo $(DEPDIR)/lighttpd-mod_mysql_vhost.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_mysql_vhost.c' object='lighttpd-mod_mysql_vhost.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_mysql_vhost.obj `if test -f 'mod_mysql_vhost.c'; then $(CYGPATH_W) 'mod_mysql_vhost.c'; else $(CYGPATH_W) '$(srcdir)/mod_mysql_vhost.c'; fi`
+
+lighttpd-mod_vhostdb_mysql.o: mod_vhostdb_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_mysql.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_mysql.Tpo -c -o lighttpd-mod_vhostdb_mysql.o `test -f 'mod_vhostdb_mysql.c' || echo '$(srcdir)/'`mod_vhostdb_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_mysql.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_mysql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_mysql.c' object='lighttpd-mod_vhostdb_mysql.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_mysql.o `test -f 'mod_vhostdb_mysql.c' || echo '$(srcdir)/'`mod_vhostdb_mysql.c
+
+lighttpd-mod_vhostdb_mysql.obj: mod_vhostdb_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_mysql.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_mysql.Tpo -c -o lighttpd-mod_vhostdb_mysql.obj `if test -f 'mod_vhostdb_mysql.c'; then $(CYGPATH_W) 'mod_vhostdb_mysql.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_mysql.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_mysql.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_mysql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_mysql.c' object='lighttpd-mod_vhostdb_mysql.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_mysql.obj `if test -f 'mod_vhostdb_mysql.c'; then $(CYGPATH_W) 'mod_vhostdb_mysql.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_mysql.c'; fi`
+
+lighttpd-mod_vhostdb_pgsql.o: mod_vhostdb_pgsql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_pgsql.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Tpo -c -o lighttpd-mod_vhostdb_pgsql.o `test -f 'mod_vhostdb_pgsql.c' || echo '$(srcdir)/'`mod_vhostdb_pgsql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_pgsql.c' object='lighttpd-mod_vhostdb_pgsql.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_pgsql.o `test -f 'mod_vhostdb_pgsql.c' || echo '$(srcdir)/'`mod_vhostdb_pgsql.c
+
+lighttpd-mod_vhostdb_pgsql.obj: mod_vhostdb_pgsql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_pgsql.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Tpo -c -o lighttpd-mod_vhostdb_pgsql.obj `if test -f 'mod_vhostdb_pgsql.c'; then $(CYGPATH_W) 'mod_vhostdb_pgsql.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_pgsql.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_pgsql.c' object='lighttpd-mod_vhostdb_pgsql.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_pgsql.obj `if test -f 'mod_vhostdb_pgsql.c'; then $(CYGPATH_W) 'mod_vhostdb_pgsql.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_pgsql.c'; fi`
+
+lighttpd-mod_vhostdb_dbi.o: mod_vhostdb_dbi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_dbi.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_dbi.Tpo -c -o lighttpd-mod_vhostdb_dbi.o `test -f 'mod_vhostdb_dbi.c' || echo '$(srcdir)/'`mod_vhostdb_dbi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_dbi.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_dbi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_dbi.c' object='lighttpd-mod_vhostdb_dbi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_dbi.o `test -f 'mod_vhostdb_dbi.c' || echo '$(srcdir)/'`mod_vhostdb_dbi.c
+
+lighttpd-mod_vhostdb_dbi.obj: mod_vhostdb_dbi.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_vhostdb_dbi.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_vhostdb_dbi.Tpo -c -o lighttpd-mod_vhostdb_dbi.obj `if test -f 'mod_vhostdb_dbi.c'; then $(CYGPATH_W) 'mod_vhostdb_dbi.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_dbi.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_vhostdb_dbi.Tpo $(DEPDIR)/lighttpd-mod_vhostdb_dbi.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_vhostdb_dbi.c' object='lighttpd-mod_vhostdb_dbi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_vhostdb_dbi.obj `if test -f 'mod_vhostdb_dbi.c'; then $(CYGPATH_W) 'mod_vhostdb_dbi.c'; else $(CYGPATH_W) '$(srcdir)/mod_vhostdb_dbi.c'; fi`
+
+lighttpd-mod_openssl.o: mod_openssl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_openssl.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_openssl.Tpo -c -o lighttpd-mod_openssl.o `test -f 'mod_openssl.c' || echo '$(srcdir)/'`mod_openssl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_openssl.Tpo $(DEPDIR)/lighttpd-mod_openssl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_openssl.c' object='lighttpd-mod_openssl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_openssl.o `test -f 'mod_openssl.c' || echo '$(srcdir)/'`mod_openssl.c
+
+lighttpd-mod_openssl.obj: mod_openssl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_openssl.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_openssl.Tpo -c -o lighttpd-mod_openssl.obj `if test -f 'mod_openssl.c'; then $(CYGPATH_W) 'mod_openssl.c'; else $(CYGPATH_W) '$(srcdir)/mod_openssl.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_openssl.Tpo $(DEPDIR)/lighttpd-mod_openssl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_openssl.c' object='lighttpd-mod_openssl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_openssl.obj `if test -f 'mod_openssl.c'; then $(CYGPATH_W) 'mod_openssl.c'; else $(CYGPATH_W) '$(srcdir)/mod_openssl.c'; fi`
+
+lighttpd-mod_trigger_b4_dl.o: mod_trigger_b4_dl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_trigger_b4_dl.o -MD -MP -MF $(DEPDIR)/lighttpd-mod_trigger_b4_dl.Tpo -c -o lighttpd-mod_trigger_b4_dl.o `test -f 'mod_trigger_b4_dl.c' || echo '$(srcdir)/'`mod_trigger_b4_dl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_trigger_b4_dl.Tpo $(DEPDIR)/lighttpd-mod_trigger_b4_dl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_trigger_b4_dl.c' object='lighttpd-mod_trigger_b4_dl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_trigger_b4_dl.o `test -f 'mod_trigger_b4_dl.c' || echo '$(srcdir)/'`mod_trigger_b4_dl.c
+
+lighttpd-mod_trigger_b4_dl.obj: mod_trigger_b4_dl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lighttpd-mod_trigger_b4_dl.obj -MD -MP -MF $(DEPDIR)/lighttpd-mod_trigger_b4_dl.Tpo -c -o lighttpd-mod_trigger_b4_dl.obj `if test -f 'mod_trigger_b4_dl.c'; then $(CYGPATH_W) 'mod_trigger_b4_dl.c'; else $(CYGPATH_W) '$(srcdir)/mod_trigger_b4_dl.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lighttpd-mod_trigger_b4_dl.Tpo $(DEPDIR)/lighttpd-mod_trigger_b4_dl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_trigger_b4_dl.c' object='lighttpd-mod_trigger_b4_dl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lighttpd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lighttpd-mod_trigger_b4_dl.obj `if test -f 'mod_trigger_b4_dl.c'; then $(CYGPATH_W) 'mod_trigger_b4_dl.c'; else $(CYGPATH_W) '$(srcdir)/mod_trigger_b4_dl.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf t/.libs t/_libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f t/$(DEPDIR)/$(am__dirstamp)
+ -rm -f t/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstPROGRAMS clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/array.Po
+ -rm -f ./$(DEPDIR)/base64.Po
+ -rm -f ./$(DEPDIR)/buffer.Po
+ -rm -f ./$(DEPDIR)/burl.Po
+ -rm -f ./$(DEPDIR)/configfile-glue.Po
+ -rm -f ./$(DEPDIR)/data_array.Po
+ -rm -f ./$(DEPDIR)/data_config.Po
+ -rm -f ./$(DEPDIR)/data_integer.Po
+ -rm -f ./$(DEPDIR)/data_string.Po
+ -rm -f ./$(DEPDIR)/http_header.Po
+ -rm -f ./$(DEPDIR)/http_kv.Po
+ -rm -f ./$(DEPDIR)/liblightcomp_la-algo_sha1.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-array.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-base64.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-buffer.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-burl.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-chunk.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-configfile-glue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-connections-glue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-crc32.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_array.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_config.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_integer.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_string.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-etag.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_libev.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_poll.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_select.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-gw_backend.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http-header-glue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_auth.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_chunk.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_header.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_kv.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_vhostdb.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-joblist.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-keyvalue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-log.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-md5.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-plugin.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-rand.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-request.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-safe_memclear.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-sock_addr.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-splaytree.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-stat_cache.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-stream.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-vector.Plo
+ -rm -f ./$(DEPDIR)/lighttpd-algo_sha1.Po
+ -rm -f ./$(DEPDIR)/lighttpd-angel.Po
+ -rm -f ./$(DEPDIR)/lighttpd-array.Po
+ -rm -f ./$(DEPDIR)/lighttpd-base64.Po
+ -rm -f ./$(DEPDIR)/lighttpd-buffer.Po
+ -rm -f ./$(DEPDIR)/lighttpd-burl.Po
+ -rm -f ./$(DEPDIR)/lighttpd-chunk.Po
+ -rm -f ./$(DEPDIR)/lighttpd-configfile-glue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-configfile.Po
+ -rm -f ./$(DEPDIR)/lighttpd-configparser.Po
+ -rm -f ./$(DEPDIR)/lighttpd-connections-glue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-connections.Po
+ -rm -f ./$(DEPDIR)/lighttpd-crc32.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_array.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_config.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_integer.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_string.Po
+ -rm -f ./$(DEPDIR)/lighttpd-etag.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_libev.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_poll.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_select.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_solaris_port.Po
+ -rm -f ./$(DEPDIR)/lighttpd-gw_backend.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http-header-glue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_auth.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_chunk.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_header.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_kv.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_vhostdb.Po
+ -rm -f ./$(DEPDIR)/lighttpd-inet_ntop_cache.Po
+ -rm -f ./$(DEPDIR)/lighttpd-joblist.Po
+ -rm -f ./$(DEPDIR)/lighttpd-keyvalue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-log.Po
+ -rm -f ./$(DEPDIR)/lighttpd-md5.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_access.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_accesslog.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_alias.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_auth.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_file.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_gssapi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_ldap.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_mysql.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_pam.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cgi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cml.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cml_funcs.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cml_lua.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_compress.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_deflate.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_dirlisting.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_evasive.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_expire.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_extforward.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_fastcgi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_flv_streaming.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_geoip.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_indexfile.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_magnet.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_magnet_cache.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_mysql_vhost.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_openssl.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_proxy.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_redirect.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_rewrite.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_rrdtool.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_scgi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_secdownload.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_setenv.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_simple_vhost.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_ssi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_ssi_expr.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_ssi_exprparser.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_staticfile.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_status.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_trigger_b4_dl.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_uploadprogress.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_userdir.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_usertrack.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_dbi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_ldap.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_mysql.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_webdav.Po
+ -rm -f ./$(DEPDIR)/lighttpd-network.Po
+ -rm -f ./$(DEPDIR)/lighttpd-network_write.Po
+ -rm -f ./$(DEPDIR)/lighttpd-plugin.Po
+ -rm -f ./$(DEPDIR)/lighttpd-rand.Po
+ -rm -f ./$(DEPDIR)/lighttpd-request.Po
+ -rm -f ./$(DEPDIR)/lighttpd-response.Po
+ -rm -f ./$(DEPDIR)/lighttpd-safe_memclear.Po
+ -rm -f ./$(DEPDIR)/lighttpd-server.Po
+ -rm -f ./$(DEPDIR)/lighttpd-sock_addr.Po
+ -rm -f ./$(DEPDIR)/lighttpd-splaytree.Po
+ -rm -f ./$(DEPDIR)/lighttpd-stat_cache.Po
+ -rm -f ./$(DEPDIR)/lighttpd-stream.Po
+ -rm -f ./$(DEPDIR)/lighttpd-vector.Po
+ -rm -f ./$(DEPDIR)/log.Po
+ -rm -f ./$(DEPDIR)/mod_access.Plo
+ -rm -f ./$(DEPDIR)/mod_accesslog.Plo
+ -rm -f ./$(DEPDIR)/mod_alias.Plo
+ -rm -f ./$(DEPDIR)/mod_auth.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_file.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_gssapi.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_ldap.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_pam.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Plo
+ -rm -f ./$(DEPDIR)/mod_cgi.Plo
+ -rm -f ./$(DEPDIR)/mod_cml_la-mod_cml.Plo
+ -rm -f ./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo
+ -rm -f ./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo
+ -rm -f ./$(DEPDIR)/mod_compress.Plo
+ -rm -f ./$(DEPDIR)/mod_deflate.Plo
+ -rm -f ./$(DEPDIR)/mod_dirlisting.Plo
+ -rm -f ./$(DEPDIR)/mod_evasive.Plo
+ -rm -f ./$(DEPDIR)/mod_evhost.Plo
+ -rm -f ./$(DEPDIR)/mod_expire.Plo
+ -rm -f ./$(DEPDIR)/mod_extforward.Plo
+ -rm -f ./$(DEPDIR)/mod_fastcgi.Plo
+ -rm -f ./$(DEPDIR)/mod_flv_streaming.Plo
+ -rm -f ./$(DEPDIR)/mod_geoip.Plo
+ -rm -f ./$(DEPDIR)/mod_indexfile.Plo
+ -rm -f ./$(DEPDIR)/mod_magnet_la-mod_magnet.Plo
+ -rm -f ./$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo
+ -rm -f ./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo
+ -rm -f ./$(DEPDIR)/mod_openssl.Plo
+ -rm -f ./$(DEPDIR)/mod_proxy.Plo
+ -rm -f ./$(DEPDIR)/mod_redirect.Plo
+ -rm -f ./$(DEPDIR)/mod_rewrite.Plo
+ -rm -f ./$(DEPDIR)/mod_rrdtool.Plo
+ -rm -f ./$(DEPDIR)/mod_scgi.Plo
+ -rm -f ./$(DEPDIR)/mod_secdownload.Plo
+ -rm -f ./$(DEPDIR)/mod_setenv.Plo
+ -rm -f ./$(DEPDIR)/mod_simple_vhost.Plo
+ -rm -f ./$(DEPDIR)/mod_sockproxy.Plo
+ -rm -f ./$(DEPDIR)/mod_ssi.Plo
+ -rm -f ./$(DEPDIR)/mod_ssi_expr.Plo
+ -rm -f ./$(DEPDIR)/mod_ssi_exprparser.Plo
+ -rm -f ./$(DEPDIR)/mod_staticfile.Plo
+ -rm -f ./$(DEPDIR)/mod_status.Plo
+ -rm -f ./$(DEPDIR)/mod_trigger_b4_dl.Plo
+ -rm -f ./$(DEPDIR)/mod_uploadprogress.Plo
+ -rm -f ./$(DEPDIR)/mod_userdir.Plo
+ -rm -f ./$(DEPDIR)/mod_usertrack.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_ldap.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Plo
+ -rm -f ./$(DEPDIR)/mod_webdav_la-mod_webdav.Plo
+ -rm -f ./$(DEPDIR)/mod_wstunnel.Plo
+ -rm -f ./$(DEPDIR)/request.Po
+ -rm -f ./$(DEPDIR)/sock_addr.Po
+ -rm -f ./$(DEPDIR)/vector.Po
+ -rm -f t/$(DEPDIR)/test_array.Po
+ -rm -f t/$(DEPDIR)/test_base64.Po
+ -rm -f t/$(DEPDIR)/test_buffer.Po
+ -rm -f t/$(DEPDIR)/test_burl.Po
+ -rm -f t/$(DEPDIR)/test_configfile.Po
+ -rm -f t/$(DEPDIR)/test_keyvalue.Po
+ -rm -f t/$(DEPDIR)/test_mod_access.Po
+ -rm -f t/$(DEPDIR)/test_mod_evhost.Po
+ -rm -f t/$(DEPDIR)/test_mod_simple_vhost.Po
+ -rm -f t/$(DEPDIR)/test_request.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/array.Po
+ -rm -f ./$(DEPDIR)/base64.Po
+ -rm -f ./$(DEPDIR)/buffer.Po
+ -rm -f ./$(DEPDIR)/burl.Po
+ -rm -f ./$(DEPDIR)/configfile-glue.Po
+ -rm -f ./$(DEPDIR)/data_array.Po
+ -rm -f ./$(DEPDIR)/data_config.Po
+ -rm -f ./$(DEPDIR)/data_integer.Po
+ -rm -f ./$(DEPDIR)/data_string.Po
+ -rm -f ./$(DEPDIR)/http_header.Po
+ -rm -f ./$(DEPDIR)/http_kv.Po
+ -rm -f ./$(DEPDIR)/liblightcomp_la-algo_sha1.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-array.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-base64.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-buffer.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-burl.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-chunk.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-configfile-glue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-connections-glue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-crc32.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_array.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_config.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_integer.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-data_string.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-etag.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_libev.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_poll.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_select.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-gw_backend.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http-header-glue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_auth.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_chunk.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_header.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_kv.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-http_vhostdb.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-joblist.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-keyvalue.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-log.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-md5.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-plugin.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-rand.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-request.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-safe_memclear.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-sock_addr.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-splaytree.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-stat_cache.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-stream.Plo
+ -rm -f ./$(DEPDIR)/liblightcomp_la-vector.Plo
+ -rm -f ./$(DEPDIR)/lighttpd-algo_sha1.Po
+ -rm -f ./$(DEPDIR)/lighttpd-angel.Po
+ -rm -f ./$(DEPDIR)/lighttpd-array.Po
+ -rm -f ./$(DEPDIR)/lighttpd-base64.Po
+ -rm -f ./$(DEPDIR)/lighttpd-buffer.Po
+ -rm -f ./$(DEPDIR)/lighttpd-burl.Po
+ -rm -f ./$(DEPDIR)/lighttpd-chunk.Po
+ -rm -f ./$(DEPDIR)/lighttpd-configfile-glue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-configfile.Po
+ -rm -f ./$(DEPDIR)/lighttpd-configparser.Po
+ -rm -f ./$(DEPDIR)/lighttpd-connections-glue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-connections.Po
+ -rm -f ./$(DEPDIR)/lighttpd-crc32.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_array.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_config.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_integer.Po
+ -rm -f ./$(DEPDIR)/lighttpd-data_string.Po
+ -rm -f ./$(DEPDIR)/lighttpd-etag.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_freebsd_kqueue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_libev.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_linux_sysepoll.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_poll.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_select.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_solaris_devpoll.Po
+ -rm -f ./$(DEPDIR)/lighttpd-fdevent_solaris_port.Po
+ -rm -f ./$(DEPDIR)/lighttpd-gw_backend.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http-header-glue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_auth.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_chunk.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_header.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_kv.Po
+ -rm -f ./$(DEPDIR)/lighttpd-http_vhostdb.Po
+ -rm -f ./$(DEPDIR)/lighttpd-inet_ntop_cache.Po
+ -rm -f ./$(DEPDIR)/lighttpd-joblist.Po
+ -rm -f ./$(DEPDIR)/lighttpd-keyvalue.Po
+ -rm -f ./$(DEPDIR)/lighttpd-log.Po
+ -rm -f ./$(DEPDIR)/lighttpd-md5.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_access.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_accesslog.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_alias.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_auth.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_file.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_gssapi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_ldap.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_mysql.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_authn_pam.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cgi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cml.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cml_funcs.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_cml_lua.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_compress.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_deflate.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_dirlisting.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_evasive.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_expire.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_extforward.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_fastcgi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_flv_streaming.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_geoip.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_indexfile.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_magnet.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_magnet_cache.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_mysql_vhost.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_openssl.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_proxy.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_redirect.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_rewrite.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_rrdtool.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_scgi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_secdownload.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_setenv.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_simple_vhost.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_ssi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_ssi_expr.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_ssi_exprparser.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_staticfile.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_status.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_trigger_b4_dl.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_uploadprogress.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_userdir.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_usertrack.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_dbi.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_ldap.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_mysql.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_vhostdb_pgsql.Po
+ -rm -f ./$(DEPDIR)/lighttpd-mod_webdav.Po
+ -rm -f ./$(DEPDIR)/lighttpd-network.Po
+ -rm -f ./$(DEPDIR)/lighttpd-network_write.Po
+ -rm -f ./$(DEPDIR)/lighttpd-plugin.Po
+ -rm -f ./$(DEPDIR)/lighttpd-rand.Po
+ -rm -f ./$(DEPDIR)/lighttpd-request.Po
+ -rm -f ./$(DEPDIR)/lighttpd-response.Po
+ -rm -f ./$(DEPDIR)/lighttpd-safe_memclear.Po
+ -rm -f ./$(DEPDIR)/lighttpd-server.Po
+ -rm -f ./$(DEPDIR)/lighttpd-sock_addr.Po
+ -rm -f ./$(DEPDIR)/lighttpd-splaytree.Po
+ -rm -f ./$(DEPDIR)/lighttpd-stat_cache.Po
+ -rm -f ./$(DEPDIR)/lighttpd-stream.Po
+ -rm -f ./$(DEPDIR)/lighttpd-vector.Po
+ -rm -f ./$(DEPDIR)/log.Po
+ -rm -f ./$(DEPDIR)/mod_access.Plo
+ -rm -f ./$(DEPDIR)/mod_accesslog.Plo
+ -rm -f ./$(DEPDIR)/mod_alias.Plo
+ -rm -f ./$(DEPDIR)/mod_auth.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_file.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_gssapi.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_ldap.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_mysql_la-mod_authn_mysql.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_pam.Plo
+ -rm -f ./$(DEPDIR)/mod_authn_sasl_la-mod_authn_sasl.Plo
+ -rm -f ./$(DEPDIR)/mod_cgi.Plo
+ -rm -f ./$(DEPDIR)/mod_cml_la-mod_cml.Plo
+ -rm -f ./$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo
+ -rm -f ./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo
+ -rm -f ./$(DEPDIR)/mod_compress.Plo
+ -rm -f ./$(DEPDIR)/mod_deflate.Plo
+ -rm -f ./$(DEPDIR)/mod_dirlisting.Plo
+ -rm -f ./$(DEPDIR)/mod_evasive.Plo
+ -rm -f ./$(DEPDIR)/mod_evhost.Plo
+ -rm -f ./$(DEPDIR)/mod_expire.Plo
+ -rm -f ./$(DEPDIR)/mod_extforward.Plo
+ -rm -f ./$(DEPDIR)/mod_fastcgi.Plo
+ -rm -f ./$(DEPDIR)/mod_flv_streaming.Plo
+ -rm -f ./$(DEPDIR)/mod_geoip.Plo
+ -rm -f ./$(DEPDIR)/mod_indexfile.Plo
+ -rm -f ./$(DEPDIR)/mod_magnet_la-mod_magnet.Plo
+ -rm -f ./$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo
+ -rm -f ./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo
+ -rm -f ./$(DEPDIR)/mod_openssl.Plo
+ -rm -f ./$(DEPDIR)/mod_proxy.Plo
+ -rm -f ./$(DEPDIR)/mod_redirect.Plo
+ -rm -f ./$(DEPDIR)/mod_rewrite.Plo
+ -rm -f ./$(DEPDIR)/mod_rrdtool.Plo
+ -rm -f ./$(DEPDIR)/mod_scgi.Plo
+ -rm -f ./$(DEPDIR)/mod_secdownload.Plo
+ -rm -f ./$(DEPDIR)/mod_setenv.Plo
+ -rm -f ./$(DEPDIR)/mod_simple_vhost.Plo
+ -rm -f ./$(DEPDIR)/mod_sockproxy.Plo
+ -rm -f ./$(DEPDIR)/mod_ssi.Plo
+ -rm -f ./$(DEPDIR)/mod_ssi_expr.Plo
+ -rm -f ./$(DEPDIR)/mod_ssi_exprparser.Plo
+ -rm -f ./$(DEPDIR)/mod_staticfile.Plo
+ -rm -f ./$(DEPDIR)/mod_status.Plo
+ -rm -f ./$(DEPDIR)/mod_trigger_b4_dl.Plo
+ -rm -f ./$(DEPDIR)/mod_uploadprogress.Plo
+ -rm -f ./$(DEPDIR)/mod_userdir.Plo
+ -rm -f ./$(DEPDIR)/mod_usertrack.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_dbi_la-mod_vhostdb_dbi.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_ldap.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_mysql_la-mod_vhostdb_mysql.Plo
+ -rm -f ./$(DEPDIR)/mod_vhostdb_pgsql_la-mod_vhostdb_pgsql.Plo
+ -rm -f ./$(DEPDIR)/mod_webdav_la-mod_webdav.Plo
+ -rm -f ./$(DEPDIR)/mod_wstunnel.Plo
+ -rm -f ./$(DEPDIR)/request.Po
+ -rm -f ./$(DEPDIR)/sock_addr.Po
+ -rm -f ./$(DEPDIR)/vector.Po
+ -rm -f t/$(DEPDIR)/test_array.Po
+ -rm -f t/$(DEPDIR)/test_base64.Po
+ -rm -f t/$(DEPDIR)/test_buffer.Po
+ -rm -f t/$(DEPDIR)/test_burl.Po
+ -rm -f t/$(DEPDIR)/test_configfile.Po
+ -rm -f t/$(DEPDIR)/test_keyvalue.Po
+ -rm -f t/$(DEPDIR)/test_mod_access.Po
+ -rm -f t/$(DEPDIR)/test_mod_evhost.Po
+ -rm -f t/$(DEPDIR)/test_mod_simple_vhost.Po
+ -rm -f t/$(DEPDIR)/test_request.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-noinstPROGRAMS clean-sbinPROGRAMS \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-sbinPROGRAMS install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \
+ uninstall-sbinPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+lemon$(BUILD_EXEEXT): lemon.c
+ $(AM_V_CC)$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $(srcdir)/lemon.c
+
+.PHONY: versionstamp parsers
+
+versionstamp:
+ @test -f versionstamp.h || touch versionstamp.h; \
+ REVISION=""; \
+ if test -d "$(top_srcdir)/.svn" -a -x "`which svnversion`"; then \
+ REVISION="$$(LANG= LC_ALL=C svnversion "$(top_srcdir)" 2>/dev/null || echo exported)"; \
+ if test "$$REVISION" = "exported"; then \
+ REVISION=""; \
+ fi; \
+ fi; \
+ if test -z "$$REVISION" -a -d "$(top_srcdir)/.git" -a -x "`which git`"; then \
+ REVISION="$$(cd "$(top_srcdir)"; LANG= LC_ALL=C git describe --always 2>/dev/null || echo)"; \
+ fi; \
+ if test -n "$$REVISION"; then \
+ echo "#define REPO_VERSION \"-devel-$$REVISION\"" > versionstamp.h.tmp; \
+ else \
+ echo "#define REPO_VERSION \"\"" > versionstamp.h.tmp; \
+ fi; \
+ if ! diff versionstamp.h.tmp versionstamp.h >/dev/null 2>/dev/null; then \
+ mv versionstamp.h.tmp versionstamp.h; \
+ else \
+ rm versionstamp.h.tmp; \
+ fi
+
+configparser.h: configparser.c
+configparser.c: $(srcdir)/configparser.y $(srcdir)/lempar.c lemon$(BUILD_EXEEXT)
+ rm -f configparser.h
+ $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
+
+mod_ssi_exprparser.h: mod_ssi_exprparser.c
+mod_ssi_exprparser.c: $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c lemon$(BUILD_EXEEXT)
+ rm -f mod_ssi_exprparser.h
+ $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
+
+parsers: configparser.c mod_ssi_exprparser.c
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/data/lighttpd/lighttpd-1.4.53/src/SConscript b/data/lighttpd/lighttpd-1.4.53/src/SConscript
new file mode 100644
index 000000000..b785ca879
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/SConscript
@@ -0,0 +1,337 @@
+import itertools
+import os
+import re
+from collections import OrderedDict
+from copy import copy
+
+try:
+ string_types = basestring
+except NameError:
+ string_types = str
+
+
+# search any file, not just executables
+def WhereIsFile(file, paths):
+ for d in paths:
+ f = os.path.join(d, file)
+ if os.path.isfile(f):
+ try:
+ st = os.stat(f)
+ except OSError:
+ # os.stat() raises OSError, not IOError if the file
+ # doesn't exist, so in this case we let IOError get
+ # raised so as to not mask possibly serious disk or
+ # network issues.
+ continue
+ return os.path.normpath(f)
+ return None
+
+def FlattenLibs(libs):
+ if isinstance(libs, string_types):
+ return [libs]
+ else:
+ return [item for sublibs in libs for item in FlattenLibs(sublibs)]
+
+# removes all but the *LAST* occurance of a lib in the list
+def RemoveDuplicateLibs(libs):
+ libs = FlattenLibs(libs)
+ # remove empty strings from list
+ libs = list(filter(lambda x: x != '', libs))
+ return list(reversed(OrderedDict.fromkeys(reversed(libs))))
+
+Import('env')
+
+def WorkaroundFreeBSDLibOrder(libs):
+ # lib(re)ssl includes (weak) arc4random functions
+ # which "on purpose" might conflict with those in libc
+ # => link libc first solves this
+ # (required for FreeBSD11 fullstatic build)
+ import platform
+ if ('c' in libs) and (platform.system() == 'FreeBSD'):
+ return ['c'] + libs
+ return libs
+
+def GatherLibs(env, *libs):
+ libs = RemoveDuplicateLibs(env['LIBS'] + list(libs) + [env['APPEND_LIBS']])
+ return WorkaroundFreeBSDLibOrder(libs)
+
+common_src = Split("base64.c buffer.c burl.c log.c \
+ http_header.c http_kv.c keyvalue.c chunk.c \
+ http_chunk.c stream.c fdevent.c gw_backend.c \
+ stat_cache.c plugin.c joblist.c etag.c array.c \
+ data_string.c data_array.c \
+ data_integer.c algo_sha1.c md5.c \
+ vector.c \
+ fdevent_select.c fdevent_libev.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
+ data_config.c \
+ crc32.c \
+ connections-glue.c \
+ configfile-glue.c \
+ http-header-glue.c \
+ http_auth.c \
+ http_vhostdb.c \
+ request.c \
+ sock_addr.c \
+ splaytree.c \
+ rand.c \
+ safe_memclear.c \
+")
+
+src = Split("server.c response.c connections.c \
+ inet_ntop_cache.c \
+ network.c \
+ network_write.c \
+ configfile.c configparser.c")
+
+lemon = env.Program('lemon', 'lemon.c', LIBS = GatherLibs(env))
+
+def Lemon(env, input):
+ parser = env.Command([input.replace('.y', '.c'),input.replace('.y', '.h')], input, '(cd sconsbuild/build; ../../' + lemon[0].path + ' -q ../../$SOURCE ../../src/lempar.c)')
+ env.Depends(parser, lemon)
+
+configparser = Lemon(env, 'configparser.y')
+mod_ssi_exprparser = Lemon(env, 'mod_ssi_exprparser.y')
+
+## the modules and how they are built
+modules = {
+ 'mod_access' : { 'src' : [ 'mod_access.c' ] },
+ 'mod_accesslog' : { 'src' : [ 'mod_accesslog.c' ] },
+ 'mod_alias' : { 'src' : [ 'mod_alias.c' ] },
+ 'mod_auth' : { 'src' : [ 'mod_auth.c' ] },
+ 'mod_authn_file' : { 'src' : [ 'mod_authn_file.c' ], 'lib' : [ env['LIBCRYPT'], env['LIBCRYPTO'] ] },
+ 'mod_cgi' : { 'src' : [ 'mod_cgi.c' ] },
+ 'mod_compress' : { 'src' : [ 'mod_compress.c' ], 'lib' : [ env['LIBZ'], env['LIBBZ2'] ] },
+ 'mod_deflate' : { 'src' : [ 'mod_deflate.c' ], 'lib' : [ env['LIBZ'], env['LIBBZ2'] ] },
+ 'mod_dirlisting' : { 'src' : [ 'mod_dirlisting.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_evasive' : { 'src' : [ 'mod_evasive.c' ] },
+ 'mod_evhost' : { 'src' : [ 'mod_evhost.c' ] },
+ 'mod_expire' : { 'src' : [ 'mod_expire.c' ] },
+ 'mod_extforward' : { 'src' : [ 'mod_extforward.c' ] },
+ 'mod_fastcgi' : { 'src' : [ 'mod_fastcgi.c' ] },
+ 'mod_flv_streaming' : { 'src' : [ 'mod_flv_streaming.c' ] },
+ 'mod_indexfile' : { 'src' : [ 'mod_indexfile.c' ] },
+ 'mod_proxy' : { 'src' : [ 'mod_proxy.c' ] },
+ 'mod_redirect' : { 'src' : [ 'mod_redirect.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_rewrite' : { 'src' : [ 'mod_rewrite.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_rrdtool' : { 'src' : [ 'mod_rrdtool.c' ] },
+ 'mod_scgi' : { 'src' : [ 'mod_scgi.c' ] },
+ 'mod_secdownload' : { 'src' : [ 'mod_secdownload.c' ], 'lib' : [ env['LIBCRYPTO'] ] },
+ 'mod_setenv' : { 'src' : [ 'mod_setenv.c' ] },
+ 'mod_simple_vhost' : { 'src' : [ 'mod_simple_vhost.c' ] },
+ 'mod_sockproxy' : { 'src' : [ 'mod_sockproxy.c' ] },
+ 'mod_ssi' : { 'src' : [ 'mod_ssi_exprparser.c', 'mod_ssi_expr.c', 'mod_ssi.c' ] },
+ 'mod_staticfile' : { 'src' : [ 'mod_staticfile.c' ] },
+ 'mod_status' : { 'src' : [ 'mod_status.c' ] },
+ 'mod_uploadprogress' : { 'src' : [ 'mod_uploadprogress.c' ] },
+ 'mod_userdir' : { 'src' : [ 'mod_userdir.c' ] },
+ 'mod_usertrack' : { 'src' : [ 'mod_usertrack.c' ] },
+ 'mod_vhostdb' : { 'src' : [ 'mod_vhostdb.c' ] },
+ 'mod_webdav' : { 'src' : [ 'mod_webdav.c' ], 'lib' : [ env['LIBXML2'], env['LIBSQLITE3'], env['LIBUUID'] ] },
+ 'mod_wstunnel' : { 'src' : [ 'mod_wstunnel.c' ], 'lib' : [ env['LIBCRYPTO'] ] },
+}
+
+if env['with_geoip']:
+ modules['mod_geoip'] = { 'src' : [ 'mod_geoip.c' ], 'lib' : [ env['LIBGEOIP'] ] }
+
+if env['with_krb5']:
+ modules['mod_authn_gssapi'] = { 'src' : [ 'mod_authn_gssapi.c' ], 'lib' : [ env['LIBKRB5'], env['LIBGSSAPI_KRB5'] ] }
+
+if env['with_ldap']:
+ modules['mod_authn_ldap'] = { 'src' : [ 'mod_authn_ldap.c' ], 'lib' : [ env['LIBLDAP'], env['LIBLBER'] ] }
+ modules['mod_vhostdb_ldap'] = { 'src' : [ 'mod_vhostdb_ldap.c' ], 'lib' : [ env['LIBLDAP'], env['LIBLBER'] ] }
+
+if env['with_lua']:
+ modules['mod_magnet'] = { 'src' : [ 'mod_magnet.c', 'mod_magnet_cache.c' ], 'lib' : [ env['LIBLUA'] ] }
+ modules['mod_cml'] = {
+ 'src' : [ 'mod_cml_lua.c', 'mod_cml.c', 'mod_cml_funcs.c' ],
+ 'lib' : [ env['LIBMEMCACHED'], env['LIBLUA'] ]
+ }
+
+if env['with_pam']:
+ modules['mod_authn_pam'] = { 'src' : [ 'mod_authn_pam.c' ], 'lib' : [ env['LIBPAM'] ] }
+
+if env['with_pcre'] and (env['with_memcached'] or env['with_gdbm']):
+ modules['mod_trigger_b4_dl'] = { 'src' : [ 'mod_trigger_b4_dl.c' ], 'lib' : [ env['LIBPCRE'], env['LIBMEMCACHED'], env['LIBGDBM'] ] }
+
+if env['with_mysql']:
+ modules['mod_authn_mysql'] = { 'src' : [ 'mod_authn_mysql.c' ], 'lib' : [ env['LIBCRYPT'], env['LIBMYSQL'] ] }
+ modules['mod_mysql_vhost'] = { 'src' : [ 'mod_mysql_vhost.c' ], 'lib' : [ env['LIBMYSQL'] ] }
+ modules['mod_vhostdb_mysql'] = { 'src' : [ 'mod_vhostdb_mysql.c' ], 'lib' : [ env['LIBMYSQL'] ] }
+
+if env['with_pgsql']:
+ modules['mod_vhostdb_pgsql'] = { 'src' : [ 'mod_vhostdb_pgsql.c' ], 'lib' : [ env['LIBPGSQL'] ] }
+
+if env['with_dbi']:
+ modules['mod_vhostdb_dbi'] = { 'src' : [ 'mod_vhostdb_dbi.c' ], 'lib' : [ env['LIBDBI'] ] }
+
+if env['with_sasl']:
+ modules['mod_authn_sasl'] = { 'src' : [ 'mod_authn_sasl.c' ], 'lib' : [ env['LIBSASL'] ] }
+
+if env['with_openssl']:
+ modules['mod_openssl'] = { 'src' : [ 'mod_openssl.c' ], 'lib' : [ env['LIBSSL'], env['LIBCRYPTO'] ] }
+
+if env['with_wolfssl']:
+ modules['mod_openssl'] = { 'src' : [ 'mod_openssl.c' ], 'lib' : [ env['LIBCRYPTO'], 'm' ] }
+
+staticenv = env.Clone(CPPFLAGS=[ env['CPPFLAGS'], '-DLIGHTTPD_STATIC' ])
+
+## all the core-sources + the modules
+staticsrc = src + common_src
+
+staticlib = copy(env['LIBS'])
+staticinit = ''
+for module in modules.keys():
+ staticsrc += modules[module]['src']
+ staticinit += "PLUGIN_INIT(%s)\n"%module
+ if 'lib' in modules[module]:
+ staticlib += modules[module]['lib']
+
+def WriteStaticPluginHeader(target, source, env):
+ do_write = True
+ data = env['STATICINIT']
+ # only touch the file if content actually changes
+ try:
+ with open(target[0].abspath, 'r') as f:
+ do_write = (data != f.read())
+ except IOError:
+ pass
+ if do_write:
+ with open(target[0].abspath, 'w+') as f:
+ f.write(env['STATICINIT'])
+
+env['STATICINIT'] = staticinit
+staticheader = env.AlwaysBuild(env.Command('plugin-static.h', [], WriteStaticPluginHeader))
+
+## turn all src-files into objects
+staticobj = []
+static_plugin_obj = None
+for cfile in staticsrc:
+ if cfile == 'plugin.c':
+ static_plugin_obj = [ staticenv.Object('static-' + cfile.replace('.c', ''), cfile) ]
+ staticobj += static_plugin_obj
+ else:
+ staticobj += [ staticenv.Object('static-' + cfile.replace('.c', ''), cfile) ]
+env.Depends(static_plugin_obj, 'plugin-static.h')
+
+## includes all modules, but links dynamically against other libs
+staticbin = staticenv.Program('../static/build/lighttpd',
+ staticobj,
+ LIBS = GatherLibs(env, staticlib)
+ )
+
+## you might have to adjust the list of libs and the order for your setup
+## this is tricky, be warned
+fullstaticlib = []
+
+## try to calculate the libs for fullstatic with ldd
+## 1. find the lib
+## 2. check the deps
+## 3. add them to the libs
+#searchlibs = os.pathsep.join([ '/lib/', '/usr/lib/', '/usr/local/lib/' ])
+searchlibs = []
+searchpathre = re.compile(r'\bSEARCH_DIR\("=([^"]+)"\)')
+f = os.popen('ld --verbose | grep SEARCH_DIR', 'r')
+for aword in searchpathre.findall(f.read()):
+ searchlibs += [ aword]
+f.close
+
+lddre = re.compile(r'^\s+lib([^=-]+)(?:-[\.0-9]+)?\.so\.[0-9]+ =>', re.MULTILINE)
+for libs in staticlib:
+ if isinstance(libs, string_types): libs = [ libs ]
+ for lib in libs:
+ fullstaticlib += [ lib ]
+ solibpath = WhereIsFile('lib' + lib + '.so', paths = searchlibs)
+ if solibpath is None:
+ continue
+
+ f = os.popen('ldd ' + solibpath, 'r')
+ for aword in lddre.findall(f.read()):
+ fullstaticlib += [ aword ]
+ f.close
+
+## glibc pthread needs to be linked completely (especially nptl-init.o)
+## or not at all, or else pthread structures may not be initialized correctly
+import platform
+fullstatic_libs = GatherLibs(env, fullstaticlib)
+fullstatic_linkflags = [staticenv['LINKFLAGS'], '-static']
+if (('pthread' in fullstatic_libs) or ('pcre' in fullstatic_libs)) and (platform.system() == 'Linux'):
+ fullstatic_linkflags += ['-Wl,--whole-archive','-lpthread','-Wl,--no-whole-archive']
+ fullstatic_libs.remove('pthread')
+if 'gcc_s' in fullstatic_libs:
+ fullstatic_linkflags += ['-static-libgcc']
+ fullstatic_libs.remove('gcc_s')
+
+## includes all modules, linked statically
+fullstaticbin = staticenv.Program('../fullstatic/build/lighttpd',
+ staticobj,
+ LIBS = fullstatic_libs,
+ LINKFLAGS= fullstatic_linkflags
+ )
+
+Alias('static', staticbin)
+Alias('fullstatic', fullstaticbin)
+
+implib = 'lighttpd.exe.a'
+bin_targets = ['lighttpd']
+bin_linkflags = [ env['LINKFLAGS'] ]
+if env['COMMON_LIB'] == 'lib':
+ common_lib = env.SharedLibrary('liblighttpd', common_src, LINKFLAGS = [ env['LINKFLAGS'], '-Wl,--export-dynamic' ])
+else:
+ src += common_src
+ common_lib = []
+ if env['COMMON_LIB'] == 'bin':
+ bin_linkflags += [ '-Wl,--export-all-symbols', '-Wl,--out-implib=build/' + implib ]
+ bin_targets += [ implib ]
+ else:
+ bin_linkflags += [ '-Wl,--export-dynamic' ]
+
+instbin = env.Program(bin_targets, src, LINKFLAGS = bin_linkflags,
+ LIBS = GatherLibs(
+ env,
+ common_lib,
+ env['LIBCRYPTO'],
+ env['LIBDL'],
+ env['LIBPCRE'],
+ )
+)
+env.Depends(instbin, configparser)
+
+if env['COMMON_LIB'] == 'bin':
+ common_lib = instbin[1]
+
+env['SHLIBPREFIX'] = ''
+instlib = []
+for module in modules.keys():
+ libs = [ common_lib ]
+ if 'lib' in modules[module]:
+ libs += modules[module]['lib']
+ instlib += env.SharedLibrary(module, modules[module]['src'], LIBS = GatherLibs(env, libs))
+env.Alias('modules', instlib)
+
+inst = []
+
+if env['build_dynamic']:
+ Default(instbin[0], instlib)
+ inst += env.Install('${sbindir}', instbin[0])
+ inst += env.Install('${libdir}', instlib)
+ if env['COMMON_LIB'] == 'lib':
+ Default(common_lib)
+ inst += env.Install('${bindir}', common_lib)
+
+if env['build_static']:
+ Default(staticbin)
+ inst += env.Install('${sbindir}', staticbin)
+
+if env['build_fullstatic']:
+ Default(fullstaticbin)
+ inst += env.Install('${sbindir}', fullstaticbin)
+
+env.Alias('dynamic', instbin)
+# default all to be installed
+env.Alias('install', inst)
+
+pkgdir = '.'
+tarname = env['package'] + '-' + env['version']
diff --git a/data/lighttpd/lighttpd-1.4.53/src/algo_sha1.c b/data/lighttpd/lighttpd-1.4.53/src/algo_sha1.c
new file mode 100644
index 000000000..fd251cd8f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/algo_sha1.c
@@ -0,0 +1,173 @@
+#include "first.h"
+typedef int innocuous_typedef_to_quiet_empty_translation_unit_compiler_warning;
+
+#include "sys-crypto.h"
+#ifndef USE_OPENSSL_CRYPTO
+
+#include "sys-endian.h"
+#include "algo_sha1.h"
+
+/*
+ * obtained from https://github.com/nori0428/mod_websocket
+ */
+
+/*
+ * sha1.c
+ *
+ * Originally written by Steve Reid <steve@edmweb.com>
+ *
+ * Modified by Aaron D. Gifford <agifford@infowest.com>
+ *
+ * NO COPYRIGHT - THIS IS 100% IN THE PUBLIC DOMAIN
+ *
+ * The original unmodified version is available at:
+ * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+
+#ifdef __LITTLE_ENDIAN__
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&(sha1_quadbyte)0xFF00FF00) \
+ |(rol(block->l[i],8)&(sha1_quadbyte)0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+typedef union _BYTE64QUAD16 {
+ sha1_byte c[64];
+ sha1_quadbyte l[16];
+} BYTE64QUAD16;
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+void SHA1_Transform(sha1_quadbyte state[5], const sha1_byte buffer[64]) {
+ sha1_quadbyte a, b, c, d, e;
+ BYTE64QUAD16 src;
+ BYTE64QUAD16 *block;
+
+ /* slow but cast-align */
+ memcpy(src.c, buffer, sizeof(sha1_byte) * 64);
+ block = &src;
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1_Init - Initialize new context */
+void SHA1_Init(SHA_CTX* context) {
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+/* Run your data through this. */
+void SHA1_Update(SHA_CTX *context, const sha1_byte *data, unsigned int len) {
+ unsigned int i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1_Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1_Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+void SHA1_Final(sha1_byte digest[SHA1_DIGEST_LENGTH], SHA_CTX *context) {
+ sha1_quadbyte i, j;
+ sha1_byte finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (sha1_byte)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1_Update(context, (sha1_byte *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1_Update(context, (sha1_byte *)"\0", 1);
+ }
+ /* Should cause a SHA1_Transform() */
+ SHA1_Update(context, finalcount, 8);
+ for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+ digest[i] = (sha1_byte)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, SHA1_BLOCK_LENGTH);
+ memset(context->state, 0, SHA1_DIGEST_LENGTH);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+}
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/algo_sha1.h b/data/lighttpd/lighttpd-1.4.53/src/algo_sha1.h
new file mode 100644
index 000000000..346d1c989
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/algo_sha1.h
@@ -0,0 +1,82 @@
+#ifndef INCLUDED_ALGO_SHA1_H
+#define INCLUDED_ALGO_SHA1_H
+#include "first.h"
+
+#include "sys-crypto.h"
+#ifdef USE_OPENSSL_CRYPTO
+
+#include <openssl/sha.h>
+
+#else
+
+/*
+ * sha.h
+ *
+ * Originally taken from the public domain SHA1 implementation
+ * written by by Steve Reid <steve@edmweb.com>
+ *
+ * Modified by Aaron D. Gifford <agifford@infowest.com>
+ *
+ * NO COPYRIGHT - THIS IS 100% IN THE PUBLIC DOMAIN
+ *
+ * The original unmodified version is available at:
+ * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#include <sys/types.h>
+
+/* Make sure you define these types for your architecture: */
+typedef uint32_t sha1_quadbyte; /* 4 byte type */
+typedef unsigned char sha1_byte; /* single byte type */
+
+#define SHA1_BLOCK_LENGTH 64
+#define SHA1_DIGEST_LENGTH 20
+/*(added for lighttpd)*/
+#define SHA_DIGEST_LENGTH SHA1_DIGEST_LENGTH
+
+/* The SHA1 structure: */
+typedef struct _SHA_CTX {
+ sha1_quadbyte state[5];
+ sha1_quadbyte count[2];
+ sha1_byte buffer[SHA1_BLOCK_LENGTH];
+} SHA_CTX;
+
+#ifndef NOPROTO
+void SHA1_Init(SHA_CTX *context);
+void SHA1_Update(SHA_CTX *context, const sha1_byte *data, unsigned int len);
+void SHA1_Final(sha1_byte digest[SHA1_DIGEST_LENGTH], SHA_CTX *context);
+#else
+void SHA1_Init();
+void SHA1_Update();
+void SHA1_Final();
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/array.c b/data/lighttpd/lighttpd-1.4.53/src/array.c
new file mode 100644
index 000000000..9abaeada6
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/array.c
@@ -0,0 +1,606 @@
+#include "first.h"
+
+#include "array.h"
+#include "buffer.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <errno.h>
+#include <assert.h>
+
+#define ARRAY_NOT_FOUND ((size_t)(-1))
+
+array *array_init(void) {
+ array *a;
+
+ a = calloc(1, sizeof(*a));
+ force_assert(a);
+
+ return a;
+}
+
+array *array_init_array(array *src) {
+ size_t i;
+ array *a = array_init();
+
+ if (0 == src->size) return a;
+
+ a->used = src->used;
+ a->size = src->size;
+ a->unique_ndx = src->unique_ndx;
+
+ a->data = malloc(sizeof(*src->data) * src->size);
+ force_assert(NULL != a->data);
+ for (i = 0; i < src->size; i++) {
+ if (src->data[i]) a->data[i] = src->data[i]->fn->copy(src->data[i]);
+ else a->data[i] = NULL;
+ }
+
+ a->sorted = malloc(sizeof(*src->sorted) * src->size);
+ force_assert(NULL != a->sorted);
+ memcpy(a->sorted, src->sorted, sizeof(*src->sorted) * src->size);
+ return a;
+}
+
+void array_free(array *a) {
+ size_t i;
+ if (!a) return;
+
+ for (i = 0; i < a->size; i++) {
+ if (a->data[i]) a->data[i]->fn->free(a->data[i]);
+ }
+
+ if (a->data) free(a->data);
+ if (a->sorted) free(a->sorted);
+
+ free(a);
+}
+
+void array_reset(array *a) {
+ size_t i;
+ if (!a) return;
+
+ for (i = 0; i < a->used; i++) {
+ a->data[i]->fn->reset(a->data[i]);
+ }
+
+ a->used = 0;
+ a->unique_ndx = 0;
+}
+
+void array_reset_data_strings(array *a) {
+ if (!a) return;
+
+ for (size_t i = 0; i < a->used; ++i) {
+ data_string * const ds = (data_string *)a->data[i];
+ /*force_assert(ds->type == TYPE_STRING);*/
+ buffer_reset(ds->key);
+ buffer_reset(ds->value);
+ }
+
+ a->used = 0;
+ a->unique_ndx = 0;
+}
+
+data_unset *array_pop(array *a) {
+ data_unset *du;
+
+ force_assert(a->used != 0);
+
+ a->used --;
+ du = a->data[a->used];
+ force_assert(a->sorted[a->used] == a->used); /* only works on "simple" lists */
+ a->data[a->used] = NULL;
+
+ return du;
+}
+
+static int array_keycmp(const char *a, size_t alen, const char *b, size_t blen) {
+ return alen < blen ? -1 : alen > blen ? 1 : buffer_caseless_compare(a, alen, b, blen);
+}
+
+/* returns index of element or ARRAY_NOT_FOUND
+ * if rndx != NULL it stores the position in a->sorted[] where the key needs
+ * to be inserted
+ */
+static size_t array_get_index(const array *a, const char *key, size_t keylen, size_t *rndx) {
+ /* invariant: [lower-1] < key < [upper]
+ * "virtual elements": [-1] = -INFTY, [a->used] = +INFTY
+ * also an invariant: 0 <= lower <= upper <= a->used
+ */
+ size_t lower = 0, upper = a->used;
+ force_assert(upper <= SSIZE_MAX); /* (lower + upper) can't overflow */
+
+ while (lower != upper) {
+ size_t probe = (lower + upper) / 2;
+ const buffer *b = a->data[a->sorted[probe]]->key;
+ int cmp = array_keycmp(key, keylen, CONST_BUF_LEN(b));
+
+ if (cmp == 0) {
+ /* found */
+ if (rndx) *rndx = probe;
+ return a->sorted[probe];
+ } else if (cmp < 0) {
+ /* key < [probe] */
+ upper = probe; /* still: lower <= upper */
+ } else {
+ /* key > [probe] */
+ lower = probe + 1; /* still: lower <= upper */
+ }
+ }
+
+ /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */
+ if (rndx) *rndx = lower;
+ return ARRAY_NOT_FOUND;
+}
+
+data_unset *array_get_element_klen(const array *a, const char *key, size_t klen) {
+ size_t ndx;
+ force_assert(NULL != key);
+
+ if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, NULL))) {
+ /* found, return it */
+ return a->data[ndx];
+ }
+
+ return NULL;
+}
+
+data_unset *array_extract_element_klen(array *a, const char *key, size_t klen) {
+ size_t ndx, pos;
+ force_assert(NULL != key);
+
+ if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, &pos))) {
+ /* found */
+ const size_t last_ndx = a->used - 1;
+ data_unset *entry = a->data[ndx];
+
+ /* now we need to swap it with the last element (if it isn't already the last element) */
+ if (ndx != last_ndx) {
+ /* to swap we also need to modify the index in a->sorted - find pos of last_elem there */
+ size_t last_elem_pos;
+ /* last element must be present at the expected position */
+ force_assert(last_ndx == array_get_index(a, CONST_BUF_LEN(a->data[last_ndx]->key), &last_elem_pos));
+
+ /* move entry from last_ndx to ndx */
+ a->data[ndx] = a->data[last_ndx];
+ a->data[last_ndx] = NULL;
+
+ /* fix index entry for moved entry */
+ a->sorted[last_elem_pos] = ndx;
+ } else {
+ a->data[ndx] = NULL;
+ }
+
+ /* remove entry in a->sorted: move everything after pos one step to the left */
+ if (pos != last_ndx) {
+ memmove(a->sorted + pos, a->sorted + pos + 1, (last_ndx - pos) * sizeof(*a->sorted));
+ }
+ a->sorted[last_ndx] = ARRAY_NOT_FOUND;
+ --a->used;
+
+ return entry;
+ }
+
+ return NULL;
+}
+
+static data_unset *array_get_unused_element(array *a, data_type_t t) {
+ data_unset *ds = NULL;
+ unsigned int i;
+
+ for (i = a->used; i < a->size; i++) {
+ if (a->data[i] && a->data[i]->type == t) {
+ ds = a->data[i];
+
+ /* make empty slot at a->used for next insert */
+ a->data[i] = a->data[a->used];
+ a->data[a->used] = NULL;
+
+ return ds;
+ }
+ }
+
+ return NULL;
+}
+
+void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
+ data_string *ds;
+
+ if (NULL != (ds = (data_string *)array_get_element_klen(hdrs, key, key_len))) {
+ buffer_copy_string_len(ds->value, value, val_len);
+ return;
+ }
+
+ array_insert_key_value(hdrs, key, key_len, value, val_len);
+}
+
+void array_insert_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
+ data_string *ds;
+
+ if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
+ ds = data_string_init();
+ }
+
+ buffer_copy_string_len(ds->key, key, key_len);
+ buffer_copy_string_len(ds->value, value, val_len);
+ array_insert_unique(hdrs, (data_unset *)ds);
+}
+
+void array_insert_value(array *hdrs, const char *value, size_t val_len) {
+ data_string *ds;
+
+ if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
+ ds = data_string_init();
+ }
+
+ buffer_copy_string_len(ds->value, value, val_len);
+ array_insert_unique(hdrs, (data_unset *)ds);
+}
+
+int * array_get_int_ptr(array *a, const char *k, size_t klen) {
+ data_integer *di = (data_integer *)array_get_element_klen(a, k, klen);
+
+ if (NULL == di) {
+ di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER);
+ if (NULL == di) di = data_integer_init();
+ buffer_copy_string_len(di->key, k, klen);
+ array_insert_unique(a, (data_unset *)di);
+ }
+
+ return &di->value;
+}
+
+/* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */
+static data_unset **array_find_or_insert(array *a, data_unset *entry) {
+ size_t ndx, pos, j;
+
+ /* generate unique index if neccesary */
+ if (buffer_is_empty(entry->key) || entry->is_index_key) {
+ buffer_copy_int(entry->key, a->unique_ndx++);
+ entry->is_index_key = 1;
+ force_assert(0 != a->unique_ndx); /* must not wrap or we'll get problems */
+ }
+
+ /* try to find the entry */
+ if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, CONST_BUF_LEN(entry->key), &pos))) {
+ /* found collision, return it */
+ return &a->data[ndx];
+ }
+
+ /* insert */
+
+ /* there couldn't possibly be enough memory to store so many entries */
+ force_assert(a->used + 1 <= SSIZE_MAX);
+
+ if (a->size == 0) {
+ a->size = 16;
+ a->data = malloc(sizeof(*a->data) * a->size);
+ a->sorted = malloc(sizeof(*a->sorted) * a->size);
+ force_assert(a->data);
+ force_assert(a->sorted);
+ for (j = a->used; j < a->size; j++) a->data[j] = NULL;
+ } else if (a->size == a->used) {
+ a->size += 16;
+ a->data = realloc(a->data, sizeof(*a->data) * a->size);
+ a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size);
+ force_assert(a->data);
+ force_assert(a->sorted);
+ for (j = a->used; j < a->size; j++) a->data[j] = NULL;
+ }
+
+ ndx = a->used;
+
+ /* make sure there is nothing here */
+ if (a->data[ndx]) a->data[ndx]->fn->free(a->data[ndx]);
+
+ a->data[a->used++] = entry;
+
+ /* move everything one step to the right */
+ if (pos != ndx) {
+ memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
+ }
+
+ /* insert */
+ a->sorted[pos] = ndx;
+
+ return NULL;
+}
+
+/* replace or insert data (free existing entry) */
+void array_replace(array *a, data_unset *entry) {
+ data_unset **old;
+
+ force_assert(NULL != entry);
+ if (NULL != (old = array_find_or_insert(a, entry))) {
+ force_assert(*old != entry);
+ (*old)->fn->free(*old);
+ *old = entry;
+ }
+}
+
+void array_insert_unique(array *a, data_unset *entry) {
+ data_unset **old;
+
+ force_assert(NULL != entry);
+ if (NULL != (old = array_find_or_insert(a, entry))) {
+ force_assert((*old)->type == entry->type);
+ entry->fn->insert_dup(*old, entry);
+ }
+}
+
+int array_is_vlist(array *a) {
+ for (size_t i = 0; i < a->used; ++i) {
+ data_unset *du = a->data[i];
+ if (!du->is_index_key || du->type != TYPE_STRING) return 0;
+ }
+ return 1;
+}
+
+int array_is_kvany(array *a) {
+ for (size_t i = 0; i < a->used; ++i) {
+ data_unset *du = a->data[i];
+ if (du->is_index_key) return 0;
+ }
+ return 1;
+}
+
+int array_is_kvarray(array *a) {
+ for (size_t i = 0; i < a->used; ++i) {
+ data_unset *du = a->data[i];
+ if (du->is_index_key || du->type != TYPE_ARRAY) return 0;
+ }
+ return 1;
+}
+
+int array_is_kvstring(array *a) {
+ for (size_t i = 0; i < a->used; ++i) {
+ data_unset *du = a->data[i];
+ if (du->is_index_key || du->type != TYPE_STRING) return 0;
+ }
+ return 1;
+}
+
+/* array_match_*() routines follow very similar pattern, but operate on slightly
+ * different data: array key/value, prefix/suffix match, case-insensitive or not
+ * While these could be combined into fewer routines with flags to modify the
+ * behavior, the interface distinctions are useful to add clarity to the code,
+ * and the specialized routines run slightly faster */
+
+data_unset *
+array_match_key_prefix_klen (const array * const a, const char * const s, const size_t slen)
+{
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const key = a->data[i]->key;
+ const size_t klen = buffer_string_length(key);
+ if (klen <= slen && 0 == memcmp(s, key->ptr, klen))
+ return a->data[i];
+ }
+ return NULL;
+}
+
+data_unset *
+array_match_key_prefix_nc_klen (const array * const a, const char * const s, const size_t slen)
+{
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const key = a->data[i]->key;
+ const size_t klen = buffer_string_length(key);
+ if (klen <= slen && 0 == strncasecmp(s, key->ptr, klen))
+ return a->data[i];
+ }
+ return NULL;
+}
+
+data_unset *
+array_match_key_prefix (const array * const a, const buffer * const b)
+{
+ return array_match_key_prefix_klen(a, CONST_BUF_LEN(b));
+}
+
+data_unset *
+array_match_key_prefix_nc (const array * const a, const buffer * const b)
+{
+ return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b));
+}
+
+const buffer *
+array_match_value_prefix (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const value = ((data_string *)a->data[i])->value;
+ const size_t vlen = buffer_string_length(value);
+ if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen))
+ return value;
+ }
+ return NULL;
+}
+
+const buffer *
+array_match_value_prefix_nc (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const value = ((data_string *)a->data[i])->value;
+ const size_t vlen = buffer_string_length(value);
+ if (vlen <= blen && 0 == strncasecmp(b->ptr, value->ptr, vlen))
+ return value;
+ }
+ return NULL;
+}
+
+data_unset *
+array_match_key_suffix (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+ const char * const end = b->ptr + blen;
+
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const key = a->data[i]->key;
+ const size_t klen = buffer_string_length(key);
+ if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen))
+ return a->data[i];
+ }
+ return NULL;
+}
+
+data_unset *
+array_match_key_suffix_nc (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+ const char * const end = b->ptr + blen;
+
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const key = a->data[i]->key;
+ const size_t klen = buffer_string_length(key);
+ if (klen <= blen && 0 == strncasecmp(end - klen, key->ptr, klen))
+ return a->data[i];
+ }
+ return NULL;
+}
+
+const buffer *
+array_match_value_suffix (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+ const char * const end = b->ptr + blen;
+
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const value = ((data_string *)a->data[i])->value;
+ const size_t vlen = buffer_string_length(value);
+ if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen))
+ return value;
+ }
+ return NULL;
+}
+
+const buffer *
+array_match_value_suffix_nc (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+ const char * const end = b->ptr + blen;
+
+ for (size_t i = 0; i < a->used; ++i) {
+ const buffer * const value = ((data_string *)a->data[i])->value;
+ const size_t vlen = buffer_string_length(value);
+ if (vlen <= blen && 0 == strncasecmp(end - vlen, value->ptr, vlen))
+ return value;
+ }
+ return NULL;
+}
+
+data_unset *
+array_match_path_or_ext (const array * const a, const buffer * const b)
+{
+ const size_t blen = buffer_string_length(b);
+
+ for (size_t i = 0; i < a->used; ++i) {
+ /* check extension in the form "^/path" or ".ext$" */
+ const buffer * const key = a->data[i]->key;
+ const size_t klen = buffer_string_length(key);
+ if (klen <= blen
+ && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen),
+ key->ptr, klen))
+ return a->data[i];
+ }
+ return NULL;
+}
+
+
+
+
+
+#include <stdio.h>
+
+void array_print_indent(int depth) {
+ int i;
+ for (i = 0; i < depth; i ++) {
+ fprintf(stdout, " ");
+ }
+}
+
+size_t array_get_max_key_length(array *a) {
+ size_t maxlen, i;
+
+ maxlen = 0;
+ for (i = 0; i < a->used; i ++) {
+ data_unset *du = a->data[i];
+ size_t len = buffer_string_length(du->key);
+
+ if (len > maxlen) {
+ maxlen = len;
+ }
+ }
+ return maxlen;
+}
+
+int array_print(array *a, int depth) {
+ size_t i;
+ size_t maxlen;
+ int oneline = 1;
+
+ if (a->used > 5) {
+ oneline = 0;
+ }
+ for (i = 0; i < a->used && oneline; i++) {
+ data_unset *du = a->data[i];
+ if (!du->is_index_key) {
+ oneline = 0;
+ break;
+ }
+ switch (du->type) {
+ case TYPE_INTEGER:
+ case TYPE_STRING:
+ break;
+ default:
+ oneline = 0;
+ break;
+ }
+ }
+ if (oneline) {
+ fprintf(stdout, "(");
+ for (i = 0; i < a->used; i++) {
+ data_unset *du = a->data[i];
+ if (i != 0) {
+ fprintf(stdout, ", ");
+ }
+ du->fn->print(du, depth + 1);
+ }
+ fprintf(stdout, ")");
+ return 0;
+ }
+
+ maxlen = array_get_max_key_length(a);
+ fprintf(stdout, "(\n");
+ for (i = 0; i < a->used; i++) {
+ data_unset *du = a->data[i];
+ array_print_indent(depth + 1);
+ if (!du->is_index_key) {
+ int j;
+
+ if (i && (i % 5) == 0) {
+ fprintf(stdout, "# %zu\n", i);
+ array_print_indent(depth + 1);
+ }
+ fprintf(stdout, "\"%s\"", du->key->ptr);
+ for (j = maxlen - buffer_string_length(du->key); j > 0; j--) {
+ fprintf(stdout, " ");
+ }
+ fprintf(stdout, " => ");
+ }
+ du->fn->print(du, depth + 1);
+ fprintf(stdout, ",\n");
+ }
+ if (!(i && (i - 1 % 5) == 0)) {
+ array_print_indent(depth + 1);
+ fprintf(stdout, "# %zu\n", i);
+ }
+ array_print_indent(depth);
+ fprintf(stdout, ")");
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/array.h b/data/lighttpd/lighttpd-1.4.53/src/array.h
new file mode 100644
index 000000000..8dbcbf688
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/array.h
@@ -0,0 +1,98 @@
+#ifndef ARRAY_H
+#define ARRAY_H
+#include "first.h"
+
+#include "buffer.h"
+
+struct data_unset; /* declaration */
+
+struct data_methods {
+ void (*reset)(struct data_unset *p); \
+ struct data_unset *(*copy)(const struct data_unset *src); \
+ void (*free)(struct data_unset *p); \
+ int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \
+ void (*print)(const struct data_unset *p, int depth);
+};
+
+typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_OTHER, TYPE_ARRAY, TYPE_INTEGER, TYPE_DONOTUSE, TYPE_CONFIG } data_type_t;
+#define DATA_UNSET \
+ buffer *key; \
+ data_type_t type; \
+ int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
+ const struct data_methods *fn /* function table */
+
+typedef struct data_unset {
+ DATA_UNSET;
+} data_unset;
+
+typedef struct {
+ data_unset **data;
+
+ size_t *sorted;
+
+ size_t used; /* <= SSIZE_MAX */
+ size_t size;
+
+ size_t unique_ndx;
+} array;
+
+typedef struct {
+ DATA_UNSET;
+
+ buffer *value;
+} data_string;
+
+data_string *data_string_init(void);
+
+typedef struct {
+ DATA_UNSET;
+
+ array *value;
+} data_array;
+
+data_array *data_array_init(void);
+
+typedef struct {
+ DATA_UNSET;
+
+ int value;
+} data_integer;
+
+data_integer *data_integer_init(void);
+
+array *array_init(void);
+array *array_init_array(array *a);
+void array_free(array *a);
+void array_reset(array *a);
+void array_reset_data_strings(array *a);
+void array_insert_unique(array *a, data_unset *entry);
+data_unset *array_pop(array *a); /* only works on "simple" lists with autogenerated keys */
+int array_is_vlist(array *a);
+int array_is_kvany(array *a);
+int array_is_kvarray(array *a);
+int array_is_kvstring(array *a);
+int array_print(array *a, int depth);
+#define array_get_element(a, key) array_get_element_klen((a), (key), sizeof(key)-1)
+data_unset *array_get_element_klen(const array *a, const char *key, size_t klen);
+data_unset *array_extract_element_klen(array *a, const char *key, size_t klen); /* removes found entry from array */
+void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
+void array_insert_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
+void array_insert_value(array *hdrs, const char *value, size_t val_len);
+int * array_get_int_ptr(array *a, const char *k, size_t klen);
+void array_replace(array *a, data_unset *entry);
+void array_print_indent(int depth);
+size_t array_get_max_key_length(array *a);
+
+data_unset * array_match_key_prefix_klen (const array * const a, const char * const s, const size_t slen);
+data_unset * array_match_key_prefix_nc_klen (const array * const a, const char * const s, const size_t slen);
+data_unset * array_match_key_prefix (const array * const a, const buffer * const b);
+data_unset * array_match_key_prefix_nc (const array * const a, const buffer * const b);
+const buffer * array_match_value_prefix (const array * const a, const buffer * const b);
+const buffer * array_match_value_prefix_nc (const array * const a, const buffer * const b);
+data_unset * array_match_key_suffix (const array * const a, const buffer * const b);
+data_unset * array_match_key_suffix_nc (const array * const a, const buffer * const b);
+const buffer * array_match_value_suffix (const array * const a, const buffer * const b);
+const buffer * array_match_value_suffix_nc (const array * const a, const buffer * const b);
+data_unset * array_match_path_or_ext (const array * const a, const buffer * const b);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/base.h b/data/lighttpd/lighttpd-1.4.53/src/base.h
new file mode 100644
index 000000000..b3c508c83
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/base.h
@@ -0,0 +1,468 @@
+#ifndef _BASE_H_
+#define _BASE_H_
+#include "first.h"
+
+#include "settings.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "base_decls.h"
+#include "buffer.h"
+#include "array.h"
+#include "chunk.h"
+#include "http_kv.h"
+#include "sock_addr.h"
+#include "etag.h"
+
+struct fdevents; /* declaration */
+struct stat_cache; /* declaration */
+
+#define DIRECT 0 /* con->mode */
+
+
+typedef struct {
+ /** HEADER */
+ /* the request-line */
+ buffer *request;
+ buffer *uri;
+
+ buffer *orig_uri;
+
+ http_method_t http_method;
+ http_version_t http_version;
+
+ buffer *request_line;
+
+ /* strings to the header */
+ buffer *http_host; /* not alloced */
+
+ unsigned int htags; /* bitfield of flagged headers present in request */
+ array *headers;
+
+ /* CONTENT */
+ off_t content_length; /* returned by strtoll() */
+ off_t te_chunked;
+
+ /* internal */
+ buffer *pathinfo;
+} request;
+
+typedef struct {
+ off_t content_length;
+ int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
+
+ unsigned int htags; /* bitfield of flagged headers present in response */
+ array *headers;
+ int send_chunked;
+} response;
+
+typedef struct {
+ buffer *scheme; /* scheme without colon or slashes ( "http" or "https" ) */
+
+ /* authority with optional portnumber ("site.name" or "site.name:8080" ) NOTE: without "username:password@" */
+ buffer *authority;
+
+ /* path including leading slash ("/" or "/index.html") - urldecoded, and sanitized ( buffer_path_simplify() && buffer_urldecode_path() ) */
+ buffer *path;
+ buffer *path_raw; /* raw path, as sent from client. no urldecoding or path simplifying */
+ buffer *query; /* querystring ( everything after "?", ie: in "/index.php?foo=1", query is "foo=1" ) */
+} request_uri;
+
+typedef struct {
+ buffer *path;
+ buffer *basedir; /* path = "(basedir)(.*)" */
+
+ buffer *doc_root; /* path = doc_root + rel_path */
+ buffer *rel_path;
+
+ buffer *etag;
+} physical;
+
+typedef struct {
+ array *mimetypes;
+
+ /* virtual-servers */
+ buffer *document_root;
+ buffer *server_name;
+ buffer *error_handler;
+ buffer *error_handler_404;
+ buffer *server_tag;
+ buffer *dirlist_encoding;
+ buffer *errorfile_prefix;
+ buffer *socket_perms;
+
+ unsigned short high_precision_timestamps;
+ unsigned short max_keep_alive_requests;
+ unsigned short max_keep_alive_idle;
+ unsigned short max_read_idle;
+ unsigned short max_write_idle;
+ unsigned short use_xattr;
+ unsigned short follow_symlink;
+ unsigned short range_requests;
+ unsigned short stream_request_body;
+ unsigned short stream_response_body;
+ unsigned short error_intercept;
+
+ /* debug */
+
+ unsigned short log_file_not_found;
+ unsigned short log_request_header;
+ unsigned short log_request_handling;
+ unsigned short log_response_header;
+ unsigned short log_condition_handling;
+ unsigned short log_timeouts;
+
+
+ /* server wide */
+ unsigned short use_ipv6, set_v6only; /* set_v6only is only a temporary option */
+ unsigned short defer_accept;
+ unsigned short ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */
+ unsigned short allow_http11;
+ unsigned short etag_use_inode;
+ unsigned short etag_use_mtime;
+ unsigned short etag_use_size;
+ unsigned short force_lowercase_filenames; /* if the FS is case-insensitive, force all files to lower-case */
+ unsigned int http_parseopts;
+ unsigned int max_request_size;
+ int listen_backlog;
+
+ unsigned short kbytes_per_second; /* connection kb/s limit */
+
+ /* configside */
+ unsigned short global_kbytes_per_second; /* */
+
+ off_t global_bytes_per_second_cnt;
+ /* server-wide traffic-shaper
+ *
+ * each context has the counter which is inited once
+ * a second by the global_kbytes_per_second config-var
+ *
+ * as soon as global_kbytes_per_second gets below 0
+ * the connected conns are "offline" a little bit
+ *
+ * the problem:
+ * we somehow have to loose our "we are writable" signal
+ * on the way.
+ *
+ */
+ off_t *global_bytes_per_second_cnt_ptr; /* */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__DragonFly__)
+ buffer *bsd_accept_filter;
+#endif
+
+} specific_config;
+
+/* the order of the items should be the same as they are processed
+ * read before write as we use this later */
+typedef enum {
+ CON_STATE_CONNECT,
+ CON_STATE_REQUEST_START,
+ CON_STATE_READ,
+ CON_STATE_REQUEST_END,
+ CON_STATE_READ_POST,
+ CON_STATE_HANDLE_REQUEST,
+ CON_STATE_RESPONSE_START,
+ CON_STATE_WRITE,
+ CON_STATE_RESPONSE_END,
+ CON_STATE_ERROR,
+ CON_STATE_CLOSE
+} connection_state_t;
+
+typedef enum {
+ /* condition not active at the moment because itself or some
+ * pre-condition depends on data not available yet
+ */
+ COND_RESULT_UNSET,
+
+ /* special "unset" for branches not selected due to pre-conditions
+ * not met (but pre-conditions are not "unset" anymore)
+ */
+ COND_RESULT_SKIP,
+
+ /* actually evaluated the condition itself */
+ COND_RESULT_FALSE, /* not active */
+ COND_RESULT_TRUE /* active */
+} cond_result_t;
+
+typedef struct cond_cache_t {
+ /* current result (with preconditions) */
+ cond_result_t result;
+ /* result without preconditions (must never be "skip") */
+ cond_result_t local_result;
+ int patterncount;
+ int matches[3 * 10];
+ buffer *comp_value; /* just a pointer */
+} cond_cache_t;
+
+struct connection {
+ connection_state_t state;
+
+ /* timestamps */
+ time_t read_idle_ts;
+ time_t close_timeout_ts;
+ time_t write_request_ts;
+
+ time_t connection_start;
+ time_t request_start;
+ struct timespec request_start_hp;
+
+ size_t request_count; /* number of requests handled in this connection */
+ size_t loops_per_request; /* to catch endless loops in a single request
+ *
+ * used by mod_rewrite, mod_fastcgi, ... and others
+ * this is self-protection
+ */
+
+ int fd; /* the FD for this connection */
+ int fde_ndx; /* index for the fdevent-handler */
+ int ndx; /* reverse mapping to server->connection[ndx] */
+
+ /* fd states */
+ int is_readable;
+ int is_writable;
+
+ int keep_alive; /* only request.c can enable it, all other just disable */
+ int keep_alive_idle; /* remember max_keep_alive_idle from config */
+
+ int file_started;
+ int file_finished;
+
+ chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
+ chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
+ chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
+
+ int traffic_limit_reached;
+
+ off_t bytes_written; /* used by mod_accesslog, mod_rrd */
+ off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
+ off_t bytes_read; /* used by mod_accesslog, mod_rrd */
+ off_t bytes_header;
+
+ int http_status;
+
+ sock_addr dst_addr;
+ buffer *dst_addr_buf;
+
+ /* request */
+ buffer *parse_request;
+
+ request request;
+ request_uri uri;
+ physical physical;
+ response response;
+
+ size_t header_len;
+
+ array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
+
+ unsigned int mode; /* DIRECT (0) or plugin id */
+ int async_callback;
+
+ void **plugin_ctx; /* plugin connection specific config */
+
+ specific_config conf; /* global connection specific config */
+ cond_cache_t *cond_cache;
+
+ buffer *server_name;
+ buffer *proto;
+
+ /* error-handler */
+ int error_handler_saved_status;
+ http_method_t error_handler_saved_method;
+
+ struct server_socket *srv_socket; /* reference to the server-socket */
+ int (* network_write)(struct server *srv, struct connection *con, chunkqueue *cq, off_t max_bytes);
+ int (* network_read)(struct server *srv, struct connection *con, chunkqueue *cq, off_t max_bytes);
+
+ /* etag handling */
+ etag_flags_t etag_flags;
+
+ int8_t conditional_is_valid[16]; /* MUST be >= COMP_LAST_ELEMENT] */
+};
+
+typedef struct {
+ connection **ptr;
+ size_t size;
+ size_t used;
+} connections;
+
+typedef struct {
+ time_t mtime; /* the key */
+ buffer *str; /* a buffer for the string represenation */
+} mtime_cache_type;
+
+typedef struct {
+ void *ptr;
+ size_t used;
+ size_t size;
+} buffer_plugin;
+
+typedef struct {
+ unsigned short port;
+ buffer *bindhost;
+
+ buffer *errorlog_file;
+ unsigned short errorlog_use_syslog;
+ buffer *breakagelog_file;
+
+ unsigned short dont_daemonize;
+ unsigned short preflight_check;
+ buffer *changeroot;
+ buffer *username;
+ buffer *groupname;
+
+ buffer *pid_file;
+
+ buffer *event_handler;
+
+ buffer *modules_dir;
+ buffer *network_backend;
+ array *modules;
+ array *upload_tempdirs;
+ unsigned int upload_temp_file_size;
+ unsigned int max_request_field_size;
+
+ unsigned short max_worker;
+ unsigned short max_fds;
+ unsigned short max_conns;
+
+ unsigned short log_request_header_on_error;
+ unsigned short log_state_handling;
+
+ int stat_cache_engine;
+ unsigned short enable_cores;
+ unsigned short reject_expect_100_with_417;
+ buffer *xattr_name;
+
+ unsigned short http_header_strict;
+ unsigned short http_host_strict;
+ unsigned short http_host_normalize;
+ unsigned short http_url_normalize;
+ unsigned short high_precision_timestamps;
+ time_t loadts;
+ double loadavg[3];
+ buffer *syslog_facility;
+
+ unsigned short compat_module_load;
+ unsigned short systemd_socket_activation;
+} server_config;
+
+typedef struct server_socket {
+ sock_addr addr;
+ int fd;
+ int fde_ndx;
+
+ unsigned short is_ssl;
+ unsigned short sidx;
+
+ buffer *srv_token;
+} server_socket;
+
+typedef struct {
+ server_socket **ptr;
+
+ size_t size;
+ size_t used;
+} server_socket_array;
+
+struct server {
+ server_socket_array srv_sockets;
+
+ /* the errorlog */
+ int errorlog_fd;
+ enum { ERRORLOG_FILE, ERRORLOG_FD, ERRORLOG_SYSLOG, ERRORLOG_PIPE } errorlog_mode;
+ buffer *errorlog_buf;
+
+ struct fdevents *ev;
+
+ buffer_plugin plugins;
+ void *plugin_slots;
+
+ /* counters */
+ int con_opened;
+ int con_read;
+ int con_written;
+ int con_closed;
+
+ int max_fds; /* max possible fds */
+ int cur_fds; /* currently used fds */
+ int want_fds; /* waiting fds */
+ int sockets_disabled;
+
+ size_t max_conns;
+
+ /* buffers */
+ buffer *parse_full_path;
+ buffer *response_header;
+ buffer *response_range;
+ buffer *tmp_buf;
+
+ buffer *tmp_chunk_len;
+
+ buffer *empty_string; /* is necessary for cond_match */
+
+ buffer *cond_check_buf;
+
+ /* caches */
+ mtime_cache_type mtime_cache[FILE_CACHE_MAX];
+
+ array *split_vals;
+
+ /* Timestamps */
+ time_t cur_ts;
+ time_t last_generated_date_ts;
+ time_t last_generated_debug_ts;
+ time_t startup_ts;
+
+ buffer *ts_debug_str;
+ buffer *ts_date_str;
+
+ /* config-file */
+ array *config_touched;
+
+ array *config_context;
+ specific_config **config_storage;
+
+ server_config srvconf;
+
+ short int config_deprecated;
+ short int config_unsupported;
+
+ connections *conns;
+ connections *joblist;
+ connections *fdwaitqueue;
+
+ struct stat_cache *stat_cache;
+
+ /**
+ * 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 = ...
+ */
+ array *status;
+
+ int event_handler;
+
+ int (* network_backend_write)(struct server *srv, int fd, chunkqueue *cq, off_t max_bytes);
+ handler_t (* request_env)(struct server *srv, connection *con);
+
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+
+ server_socket_array srv_sockets_inherited;
+};
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/base64.c b/data/lighttpd/lighttpd-1.4.53/src/base64.c
new file mode 100644
index 000000000..3034181a5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/base64.c
@@ -0,0 +1,235 @@
+#include "first.h"
+
+#include "base64.h"
+
+/* reverse mapping:
+ * >= 0: base64 value
+ * -1: invalid character
+ * -2: skip character (whitespace/control)
+ * -3: padding
+ */
+
+/* BASE64_STANDARD: "A-Z a-z 0-9 + /" maps to 0-63, pad with "=" */
+static const char base64_standard_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+static const signed char base64_standard_reverse_table[] = {
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* 0x00 - 0x0F */
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* 0x10 - 0x1F */
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 - 0x2F */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30 - 0x3F */
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4F */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 - 0x5F */
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6F */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 - 0x7F */
+};
+
+/* BASE64_URL: "A-Z a-z 0-9 - _" maps to 0-63, pad with "." */
+static const char base64_url_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
+static const signed char base64_url_reverse_table[] = {
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* 0x00 - 0x0F */
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* 0x10 - 0x1F */
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -3, -1, /* 0x20 - 0x2F */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 - 0x3F */
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4F */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, /* 0x50 - 0x5F */
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6F */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 - 0x7F */
+};
+
+unsigned char* buffer_append_base64_decode(buffer *out, const char* in, size_t in_length, base64_charset charset) {
+ unsigned char *result;
+ size_t out_pos = 0; /* current output character (position) that is decoded. can contain partial result */
+ unsigned int group = 0; /* how many base64 digits in the current group were decoded already. each group has up to 4 digits */
+ size_t i;
+ const signed char *base64_reverse_table;
+
+ switch (charset) {
+ case BASE64_STANDARD:
+ base64_reverse_table = base64_standard_reverse_table;
+ break;
+ case BASE64_URL:
+ base64_reverse_table = base64_url_reverse_table;
+ break;
+ default:
+ return NULL;
+ }
+
+ result = (unsigned char *) buffer_string_prepare_append(out, 3*(in_length / 4) + 3);
+
+ /* run through the whole string, converting as we go */
+ for (i = 0; i < in_length; i++) {
+ unsigned char c = (unsigned char) in[i];
+ int ch;
+
+ if (c == '\0') break;
+ if (c >= 128) return NULL; /* only 7-bit characters allowed */
+
+ ch = base64_reverse_table[c];
+ if (-3 == ch) {
+ /* pad character; can only come after 2 base64 digits in a group */
+ if (group < 2) return NULL;
+ break;
+ } else if (-2 == ch) {
+ continue; /* skip character */
+ } else if (ch < 0) {
+ return NULL; /* invalid character, abort */
+ }
+
+ switch(group) {
+ case 0:
+ result[out_pos] = ch << 2;
+ group = 1;
+ break;
+ case 1:
+ result[out_pos++] |= ch >> 4;
+ result[out_pos] = (ch & 0x0f) << 4;
+ group = 2;
+ break;
+ case 2:
+ result[out_pos++] |= ch >>2;
+ result[out_pos] = (ch & 0x03) << 6;
+ group = 3;
+ break;
+ case 3:
+ result[out_pos++] |= ch;
+ group = 0;
+ break;
+ }
+ }
+
+ switch(group) {
+ case 0:
+ /* ended on boundary */
+ break;
+ case 1:
+ /* need at least 2 base64 digits per group */
+ return NULL;
+ case 2:
+ /* have 2 base64 digits in last group => one real octect, two zeroes padded */
+ case 3:
+ /* have 3 base64 digits in last group => two real octects, one zero padded */
+
+ /* for both cases the current index already is on the first zero padded octet
+ * - check it really is zero (overlapping bits) */
+ if (0 != result[out_pos]) return NULL;
+ break;
+ }
+
+ buffer_commit(out, out_pos);
+
+ return result;
+}
+
+size_t li_to_base64_no_padding(char* out, size_t out_length, const unsigned char* in, size_t in_length, base64_charset charset) {
+ const size_t full_tuples = in_length / 3;
+ const size_t in_tuple_remainder = in_length % 3;
+ const size_t out_tuple_remainder = in_tuple_remainder ? 1 + in_tuple_remainder : 0;
+ const size_t require_space = 4 * full_tuples + out_tuple_remainder;
+ const char* base64_table;
+ size_t i;
+ size_t out_pos = 0;
+
+ switch (charset) {
+ case BASE64_STANDARD:
+ base64_table = base64_standard_table;
+ break;
+ case BASE64_URL:
+ base64_table = base64_url_table;
+ break;
+ default:
+ force_assert(0 && "invalid charset");
+ }
+
+ /* check overflows */
+ force_assert(full_tuples <= 2*full_tuples);
+ force_assert(full_tuples <= 4*full_tuples);
+ force_assert(4*full_tuples <= 4*full_tuples + out_tuple_remainder);
+ force_assert(require_space <= out_length);
+
+ for (i = 2; i < in_length; i += 3) {
+ unsigned int v = (in[i-2] << 16) | (in[i-1] << 8) | in[i];
+ out[out_pos+3] = base64_table[v & 0x3f]; v >>= 6;
+ out[out_pos+2] = base64_table[v & 0x3f]; v >>= 6;
+ out[out_pos+1] = base64_table[v & 0x3f]; v >>= 6;
+ out[out_pos+0] = base64_table[v & 0x3f];
+ out_pos += 4;
+ }
+ switch (in_tuple_remainder) {
+ case 0:
+ break;
+ case 1:
+ {
+ /* pretend in[i-1] = in[i] = 0, don't write last two (out_pos+3, out_pos+2) characters */
+ unsigned int v = (in[i-2] << 4);
+ out[out_pos+1] = base64_table[v & 0x3f]; v >>= 6;
+ out[out_pos+0] = base64_table[v & 0x3f];
+ out_pos += 2;
+ }
+ break;
+ case 2:
+ {
+ /* pretend in[i] = 0, don't write last (out_pos+3) character */
+ unsigned int v = (in[i-2] << 10) | (in[i-1] << 2);
+ out[out_pos+2] = base64_table[v & 0x3f]; v >>= 6;
+ out[out_pos+1] = base64_table[v & 0x3f]; v >>= 6;
+ out[out_pos+0] = base64_table[v & 0x3f];
+ out_pos += 3;
+ }
+ break;
+ }
+ force_assert(out_pos <= out_length);
+ return out_pos;
+}
+
+size_t li_to_base64(char* out, size_t out_length, const unsigned char* in, size_t in_length, base64_charset charset) {
+ const size_t in_tuple_remainder = in_length % 3;
+ size_t padding_length = in_tuple_remainder ? 3 - in_tuple_remainder : 0;
+
+ char padding;
+ size_t out_pos;
+
+ switch (charset) {
+ case BASE64_STANDARD:
+ padding = base64_standard_table[64];
+ break;
+ case BASE64_URL:
+ padding = base64_url_table[64];
+ break;
+ default:
+ force_assert(0 && "invalid charset");
+ }
+
+ force_assert(out_length >= padding_length);
+ out_pos = li_to_base64_no_padding(out, out_length - padding_length, in, in_length, charset);
+
+ while (padding_length > 0) {
+ out[out_pos++] = padding;
+ padding_length--;
+ }
+
+ force_assert(out_pos <= out_length);
+
+ return out_pos;
+}
+
+
+char* buffer_append_base64_encode_no_padding(buffer *out, const unsigned char* in, size_t in_length, base64_charset charset) {
+ size_t reserve = 4*(in_length/3) + 4;
+ char* result = buffer_string_prepare_append(out, reserve);
+ size_t out_pos = li_to_base64_no_padding(result, reserve, in, in_length, charset);
+
+ buffer_commit(out, out_pos);
+
+ return result;
+}
+
+char* buffer_append_base64_encode(buffer *out, const unsigned char* in, size_t in_length, base64_charset charset) {
+ size_t reserve = 4*(in_length/3) + 4;
+ char* result = buffer_string_prepare_append(out, reserve);
+ size_t out_pos = li_to_base64(result, reserve, in, in_length, charset);
+
+ buffer_commit(out, out_pos);
+
+ return result;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/base64.h b/data/lighttpd/lighttpd-1.4.53/src/base64.h
new file mode 100644
index 000000000..615f32f2a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/base64.h
@@ -0,0 +1,20 @@
+#ifndef _BASE64_H_
+#define _BASE64_H_
+#include "first.h"
+
+#include "buffer.h"
+
+typedef enum {
+ BASE64_STANDARD,
+ BASE64_URL,
+} base64_charset;
+
+unsigned char* buffer_append_base64_decode(buffer *out, const char* in, size_t in_length, base64_charset charset);
+
+size_t li_to_base64_no_padding(char* out, size_t out_length, const unsigned char* in, size_t in_length, base64_charset charset);
+size_t li_to_base64(char* out, size_t out_length, const unsigned char* in, size_t in_length, base64_charset charset);
+
+char* buffer_append_base64_encode_no_padding(buffer *out, const unsigned char* in, size_t in_length, base64_charset charset);
+char* buffer_append_base64_encode(buffer *out, const unsigned char* in, size_t in_length, base64_charset charset);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/base_decls.h b/data/lighttpd/lighttpd-1.4.53/src/base_decls.h
new file mode 100644
index 000000000..33c559bf5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/base_decls.h
@@ -0,0 +1,30 @@
+#ifndef INCLUDED_BASE_DECLS_H
+#define INCLUDED_BASE_DECLS_H
+
+#include "first.h"
+
+struct server;
+typedef struct server server;
+
+struct connection;
+typedef struct connection connection;
+
+union sock_addr;
+typedef union sock_addr sock_addr;
+
+
+enum handler_t {
+ HANDLER_UNSET,
+ HANDLER_GO_ON,
+ HANDLER_FINISHED,
+ HANDLER_COMEBACK,
+ HANDLER_WAIT_FOR_EVENT,
+ HANDLER_ERROR,
+ HANDLER_WAIT_FOR_FD
+};
+typedef enum handler_t handler_t;
+
+#define BV(x) (1 << x)
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/buffer.c b/data/lighttpd/lighttpd-1.4.53/src/buffer.c
new file mode 100644
index 000000000..261adf55c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/buffer.c
@@ -0,0 +1,1028 @@
+#include "first.h"
+
+#include "buffer.h"
+#include "settings.h" /* BUFFER_MAX_REUSE_SIZE */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h> /* strftime() */
+
+static const char hex_chars_lc[] = "0123456789abcdef";
+static const char hex_chars_uc[] = "0123456789ABCDEF";
+
+/**
+ * init the buffer
+ *
+ */
+
+buffer* buffer_init(void) {
+ buffer *b;
+
+ b = malloc(sizeof(*b));
+ force_assert(b);
+
+ b->ptr = NULL;
+ b->size = 0;
+ b->used = 0;
+
+ return b;
+}
+
+buffer *buffer_init_buffer(const buffer *src) {
+ buffer *b = buffer_init();
+ buffer_copy_buffer(b, src);
+ return b;
+}
+
+buffer *buffer_init_string(const char *str) {
+ buffer *b = buffer_init();
+ buffer_copy_string(b, str);
+ return b;
+}
+
+void buffer_free(buffer *b) {
+ if (NULL == b) return;
+
+ free(b->ptr);
+ free(b);
+}
+
+__attribute_cold__
+static void buffer_free_ptr(buffer *b) {
+ if (NULL == b) return;
+ free(b->ptr);
+ b->ptr = NULL;
+ b->used = 0;
+ b->size = 0;
+}
+
+void buffer_reset(buffer *b) {
+ if (NULL != b && b->size > 0) {
+ b->used = 0;
+ /* release buffer larger than ... bytes */
+ if (b->size > BUFFER_MAX_REUSE_SIZE) buffer_free_ptr(b);
+ }
+}
+
+void buffer_move(buffer *b, buffer *src) {
+ buffer tmp;
+ force_assert(NULL != b);
+ force_assert(NULL != src);
+
+ buffer_clear(b);
+ tmp = *src; *src = *b; *b = tmp;
+}
+
+/* make sure buffer is at least "size" big + 1 for '\0'. keep old data */
+__attribute_cold__
+static void buffer_realloc(buffer *b, size_t len) {
+ #define BUFFER_PIECE_SIZE 64uL /*(must be power-of-2)*/
+ const size_t sz = (len + 1 + BUFFER_PIECE_SIZE-1) & ~(BUFFER_PIECE_SIZE-1);
+ force_assert(sz > len);
+
+ b->size = sz;
+ b->ptr = realloc(b->ptr, sz);
+
+ force_assert(NULL != b->ptr);
+}
+
+__attribute_cold__
+static void buffer_alloc_replace(buffer *b, size_t size) {
+ /*(discard old data so realloc() does not copy)*/
+ if (NULL != b->ptr) {
+ free(b->ptr);
+ b->ptr = NULL;
+ }
+ buffer_realloc(b, size);
+}
+
+char* buffer_string_prepare_copy(buffer *b, size_t size) {
+ force_assert(NULL != b);
+
+ if (size >= b->size) buffer_alloc_replace(b, size);
+
+ b->used = 0;
+ return b->ptr;
+}
+
+char* buffer_string_prepare_append(buffer *b, size_t size) {
+ force_assert(NULL != b);
+
+ if (b->used && size < b->size - b->used)
+ return b->ptr + b->used - 1;
+
+ if (buffer_string_is_empty(b)) {
+ return buffer_string_prepare_copy(b, size);
+ } else {
+ /* not empty, b->used already includes a terminating 0 */
+ size_t req_size = b->used + size;
+
+ /* check for overflow: unsigned overflow is defined to wrap around */
+ force_assert(req_size >= b->used);
+
+ buffer_realloc(b, req_size);
+
+ return b->ptr + b->used - 1;
+ }
+}
+
+void buffer_string_set_length(buffer *b, size_t len) {
+ force_assert(NULL != b);
+
+ if (len >= b->size) buffer_realloc(b, len);
+
+ b->used = len + 1;
+ b->ptr[len] = '\0';
+}
+
+void buffer_commit(buffer *b, size_t size)
+{
+ force_assert(NULL != b);
+ force_assert(b->size > 0);
+
+ if (0 == b->used) b->used = 1;
+
+ if (size > 0) {
+ /* check for overflow: unsigned overflow is defined to wrap around */
+ size_t sz = b->used + size;
+ force_assert(sz > b->used);
+ force_assert(sz <= b->size);
+ b->used = sz;
+ }
+
+ b->ptr[b->used - 1] = '\0';
+}
+
+void buffer_copy_string(buffer *b, const char *s) {
+ buffer_copy_string_len(b, s, NULL != s ? strlen(s) : 0);
+}
+
+void buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
+ force_assert(NULL != b);
+ force_assert(NULL != s || s_len == 0);
+
+ if (s_len >= b->size) buffer_string_prepare_copy(b, s_len);
+
+ if (0 != s_len) memcpy(b->ptr, s, s_len); /*(s might be NULL)*/
+ b->ptr[s_len] = '\0';
+ b->used = s_len + 1;
+}
+
+void buffer_append_string(buffer *b, const char *s) {
+ buffer_append_string_len(b, s, NULL != s ? strlen(s) : 0);
+}
+
+/**
+ * append a string to the end of the buffer
+ *
+ * the resulting buffer is terminated with a '\0'
+ * s is treated as a un-terminated string (a \0 is handled a normal character)
+ *
+ * @param b a buffer
+ * @param s the string
+ * @param s_len size of the string (without the terminating \0)
+ */
+
+void buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
+ char *target_buf;
+
+ force_assert(NULL != b);
+ force_assert(NULL != s || s_len == 0);
+
+ target_buf = buffer_string_prepare_append(b, s_len);
+ if (0 == b->used) ++b->used; /*(must include '\0' for append below)*/
+
+ /*(s might be NULL if 0 == s_len)*/
+ if (s_len) memcpy(target_buf, s, s_len);
+ target_buf[s_len] = '\0';
+ b->used += s_len;
+}
+
+void buffer_append_path_len(buffer *b, const char *a, size_t alen) {
+ size_t blen = buffer_string_length(b);
+ int aslash = (alen && a[0] == '/');
+ buffer_string_prepare_append(b, alen+2); /*(+ '/' and + '\0' if 0 == blen)*/
+ if (blen && b->ptr[blen-1] == '/') {
+ if (aslash) --b->used;
+ }
+ else {
+ if (!b->used) ++b->used;
+ if (!aslash) b->ptr[++b->used - 2] = '/';
+ }
+ memcpy(b->ptr+b->used-1, a, alen);
+ b->ptr[(b->used += alen)-1] = '\0';
+}
+
+void buffer_append_uint_hex_lc(buffer *b, uintmax_t value) {
+ char *buf;
+ unsigned int shift = 0;
+
+ {
+ uintmax_t copy = value;
+ do {
+ copy >>= 8;
+ shift += 8; /* counting bits */
+ } while (0 != copy);
+ }
+
+ buf = buffer_string_prepare_append(b, shift >> 2); /*nibbles (4 bits)*/
+ buffer_commit(b, shift >> 2); /* will fill below */
+
+ while (shift > 0) {
+ shift -= 4;
+ *(buf++) = hex_chars_lc[(value >> shift) & 0x0F];
+ }
+}
+
+static char* utostr(char * const buf_end, uintmax_t val) {
+ char *cur = buf_end;
+ do {
+ int mod = val % 10;
+ val /= 10;
+ /* prepend digit mod */
+ *(--cur) = (char) ('0' + mod);
+ } while (0 != val);
+ return cur;
+}
+
+static char* itostr(char * const buf_end, intmax_t val) {
+ /* absolute value not defined for INTMAX_MIN, but can take absolute
+ * value of any negative number via twos complement cast to unsigned.
+ * negative sign is prepended after (now unsigned) value is converted
+ * to string */
+ uintmax_t uval = val >= 0 ? (uintmax_t)val : ((uintmax_t)~val) + 1;
+ char *cur = utostr(buf_end, uval);
+ if (val < 0) *(--cur) = '-';
+
+ return cur;
+}
+
+void buffer_append_int(buffer *b, intmax_t val) {
+ char buf[LI_ITOSTRING_LENGTH];
+ char* const buf_end = buf + sizeof(buf);
+ char *str;
+
+ force_assert(NULL != b);
+
+ str = itostr(buf_end, val);
+ force_assert(buf_end > str && str >= buf);
+
+ buffer_append_string_len(b, str, buf_end - str);
+}
+
+void buffer_copy_int(buffer *b, intmax_t val) {
+ force_assert(NULL != b);
+
+ b->used = 0;
+ buffer_append_int(b, val);
+}
+
+void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm) {
+ size_t r;
+ char* buf;
+ force_assert(NULL != b);
+ force_assert(NULL != format);
+ force_assert(NULL != tm);
+
+ buf = buffer_string_prepare_append(b, 255);
+ r = strftime(buf, buffer_string_space(b), format, tm);
+
+ /* 0 (in some apis buffer_string_space(b)) signals the string may have
+ * been too small; but the format could also just have lead to an empty
+ * string
+ */
+ if (0 == r || r >= buffer_string_space(b)) {
+ /* give it a second try with a larger string */
+ buf = buffer_string_prepare_append(b, 4095);
+ r = strftime(buf, buffer_string_space(b), format, tm);
+ }
+
+ if (r >= buffer_string_space(b)) r = 0;
+
+ buffer_commit(b, r);
+}
+
+
+void li_itostrn(char *buf, size_t buf_len, intmax_t val) {
+ char p_buf[LI_ITOSTRING_LENGTH];
+ char* const p_buf_end = p_buf + sizeof(p_buf);
+ char* str = p_buf_end - 1;
+ *str = '\0';
+
+ str = itostr(str, val);
+ force_assert(p_buf_end > str && str >= p_buf);
+
+ force_assert(buf_len >= (size_t) (p_buf_end - str));
+ memcpy(buf, str, p_buf_end - str);
+}
+
+void li_utostrn(char *buf, size_t buf_len, uintmax_t val) {
+ char p_buf[LI_ITOSTRING_LENGTH];
+ char* const p_buf_end = p_buf + sizeof(p_buf);
+ char* str = p_buf_end - 1;
+ *str = '\0';
+
+ str = utostr(str, val);
+ force_assert(p_buf_end > str && str >= p_buf);
+
+ force_assert(buf_len >= (size_t) (p_buf_end - str));
+ memcpy(buf, str, p_buf_end - str);
+}
+
+#define li_ntox_lc(n) ((n) <= 9 ? (n) + '0' : (n) + 'a' - 10)
+
+char int2hex(char c) {
+ /*return li_ntox_lc(c & 0xF);*/
+ return hex_chars_lc[(c & 0x0F)];
+}
+
+/* c (char) and n (nibble) MUST be unsigned integer types */
+#define li_cton(c,n) \
+ (((n) = (c) - '0') <= 9 || (((n) = ((c)&0xdf) - 'A') <= 5 ? ((n) += 10) : 0))
+
+/* converts hex char (0-9, A-Z, a-z) to decimal.
+ * returns 0xFF on invalid input.
+ */
+char hex2int(unsigned char hex) {
+ unsigned char n;
+ return li_cton(hex,n) ? (char)n : 0xFF;
+}
+
+/**
+ * check if two buffer contain the same data
+ */
+
+int buffer_is_equal(const buffer *a, const buffer *b) {
+ force_assert(NULL != a && NULL != b);
+
+ /* 1 = equal; 0 = not equal */
+ return (a->used == b->used && 0 == memcmp(a->ptr, b->ptr, a->used));
+}
+
+int buffer_is_equal_string(const buffer *a, const char *s, size_t b_len) {
+ force_assert(NULL != a && NULL != s);
+ force_assert(b_len + 1 > b_len);
+
+ /* 1 = equal; 0 = not equal */
+ return (a->used == b_len + 1 && 0 == memcmp(a->ptr, s, b_len));
+}
+
+/* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */
+int buffer_is_equal_caseless_string(const buffer *a, const char *s, size_t b_len) {
+ force_assert(NULL != a && NULL != s);
+ force_assert(b_len + 1 > b_len);
+
+ /* 1 = equal; 0 = not equal */
+ return (a->used == b_len + 1 && 0 == strncasecmp(a->ptr, s, b_len));
+}
+
+int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
+ size_t const len = (a_len < b_len) ? a_len : b_len;
+ size_t i;
+
+ for (i = 0; i < len; ++i) {
+ unsigned char ca = a[i], cb = b[i];
+ if (ca == cb) continue;
+
+ /* always lowercase for transitive results */
+ if (ca >= 'A' && ca <= 'Z') ca |= 32;
+ if (cb >= 'A' && cb <= 'Z') cb |= 32;
+
+ if (ca == cb) continue;
+ return ((int)ca) - ((int)cb);
+ }
+ if (a_len == b_len) return 0;
+ return a_len < b_len ? -1 : 1;
+}
+
+int buffer_is_equal_right_len(const buffer *b1, const buffer *b2, size_t len) {
+ /* no len -> equal */
+ if (len == 0) return 1;
+
+ /* len > 0, but empty buffers -> not equal */
+ if (b1->used == 0 || b2->used == 0) return 0;
+
+ /* buffers too small -> not equal */
+ if (b1->used - 1 < len || b2->used - 1 < len) return 0;
+
+ return 0 == memcmp(b1->ptr + b1->used - 1 - len, b2->ptr + b2->used - 1 - len, len);
+}
+
+
+void li_tohex_lc(char *buf, size_t buf_len, const char *s, size_t s_len) {
+ force_assert(2 * s_len > s_len);
+ force_assert(2 * s_len < buf_len);
+
+ for (size_t i = 0; i < s_len; ++i) {
+ buf[2*i] = hex_chars_lc[(s[i] >> 4) & 0x0F];
+ buf[2*i+1] = hex_chars_lc[s[i] & 0x0F];
+ }
+ buf[2*s_len] = '\0';
+}
+
+void li_tohex_uc(char *buf, size_t buf_len, const char *s, size_t s_len) {
+ force_assert(2 * s_len > s_len);
+ force_assert(2 * s_len < buf_len);
+
+ for (size_t i = 0; i < s_len; ++i) {
+ buf[2*i] = hex_chars_uc[(s[i] >> 4) & 0x0F];
+ buf[2*i+1] = hex_chars_uc[s[i] & 0x0F];
+ }
+ buf[2*s_len] = '\0';
+}
+
+
+void buffer_substr_replace (buffer * const b, const size_t offset,
+ const size_t len, const buffer * const replace)
+{
+ const size_t blen = buffer_string_length(b);
+ const size_t rlen = buffer_string_length(replace);
+
+ if (rlen > len) {
+ buffer_string_set_length(b, blen-len+rlen);
+ memmove(b->ptr+offset+rlen, b->ptr+offset+len, blen-offset-len);
+ }
+
+ memcpy(b->ptr+offset, replace->ptr, rlen);
+
+ if (rlen < len) {
+ memmove(b->ptr+offset+rlen, b->ptr+offset+len, blen-offset-len);
+ buffer_string_set_length(b, blen-len+rlen);
+ }
+}
+
+
+void buffer_append_string_encoded_hex_lc(buffer *b, const char *s, size_t len) {
+ unsigned char * const p =
+ (unsigned char*) buffer_string_prepare_append(b, len*2);
+ buffer_commit(b, len*2); /* fill below */
+ for (size_t i = 0; i < len; ++i) {
+ p[(i<<1)] = hex_chars_lc[(s[i] >> 4) & 0x0F];
+ p[(i<<1)+1] = hex_chars_lc[(s[i]) & 0x0F];
+ }
+}
+
+void buffer_append_string_encoded_hex_uc(buffer *b, const char *s, size_t len) {
+ unsigned char * const p =
+ (unsigned char*) buffer_string_prepare_append(b, len*2);
+ buffer_commit(b, len*2); /* fill below */
+ for (size_t i = 0; i < len; ++i) {
+ p[(i<<1)] = hex_chars_uc[(s[i] >> 4) & 0x0F];
+ p[(i<<1)+1] = hex_chars_uc[(s[i]) & 0x0F];
+ }
+}
+
+
+/* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
+static const char encoded_chars_rel_uri_part[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; < = > ? */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F @ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* 50 - 5F [ \ ] ^ */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* 70 - 7F { | } DEL */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* B0 - BF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0 - CF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* D0 - DF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0 - EF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
+};
+
+/* everything except: ! ( ) * - . / 0-9 A-Z _ a-z */
+static const char encoded_chars_rel_uri[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; < = > ? */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F @ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* 50 - 5F [ \ ] ^ */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* 70 - 7F { | } DEL */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* B0 - BF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0 - CF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* D0 - DF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0 - EF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
+};
+
+static const char encoded_chars_html[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F " & ' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* B0 - BF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0 - CF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* D0 - DF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0 - EF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
+};
+
+static const char encoded_chars_minimal_xml[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F " & ' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
+
+
+void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
+ unsigned char *ds, *d;
+ size_t d_len, ndx;
+ const char *map = NULL;
+
+ force_assert(NULL != b);
+ force_assert(NULL != s || 0 == s_len);
+
+ if (0 == s_len) return;
+
+ switch(encoding) {
+ case ENCODING_REL_URI:
+ map = encoded_chars_rel_uri;
+ break;
+ case ENCODING_REL_URI_PART:
+ map = encoded_chars_rel_uri_part;
+ break;
+ case ENCODING_HTML:
+ map = encoded_chars_html;
+ break;
+ case ENCODING_MINIMAL_XML:
+ map = encoded_chars_minimal_xml;
+ break;
+ }
+
+ force_assert(NULL != map);
+
+ /* count to-be-encoded-characters */
+ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
+ if (map[*ds]) {
+ switch(encoding) {
+ case ENCODING_REL_URI:
+ case ENCODING_REL_URI_PART:
+ d_len += 3;
+ break;
+ case ENCODING_HTML:
+ case ENCODING_MINIMAL_XML:
+ d_len += 6;
+ break;
+ }
+ } else {
+ d_len++;
+ }
+ }
+
+ d = (unsigned char*) buffer_string_prepare_append(b, d_len);
+ buffer_commit(b, d_len); /* fill below */
+
+ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
+ if (map[*ds]) {
+ switch(encoding) {
+ case ENCODING_REL_URI:
+ case ENCODING_REL_URI_PART:
+ d[d_len++] = '%';
+ d[d_len++] = hex_chars_uc[((*ds) >> 4) & 0x0F];
+ d[d_len++] = hex_chars_uc[(*ds) & 0x0F];
+ break;
+ case ENCODING_HTML:
+ case ENCODING_MINIMAL_XML:
+ d[d_len++] = '&';
+ d[d_len++] = '#';
+ d[d_len++] = 'x';
+ d[d_len++] = hex_chars_uc[((*ds) >> 4) & 0x0F];
+ d[d_len++] = hex_chars_uc[(*ds) & 0x0F];
+ d[d_len++] = ';';
+ break;
+ }
+ } else {
+ d[d_len++] = *ds;
+ }
+ }
+}
+
+void buffer_append_string_c_escaped(buffer *b, const char *s, size_t s_len) {
+ unsigned char *ds, *d;
+ size_t d_len, ndx;
+
+ force_assert(NULL != b);
+ force_assert(NULL != s || 0 == s_len);
+
+ if (0 == s_len) return;
+
+ /* count to-be-encoded-characters */
+ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
+ if ((*ds < 0x20) /* control character */
+ || (*ds >= 0x7f)) { /* DEL + non-ASCII characters */
+ switch (*ds) {
+ case '\t':
+ case '\r':
+ case '\n':
+ d_len += 2;
+ break;
+ default:
+ d_len += 4; /* \xCC */
+ break;
+ }
+ } else {
+ d_len++;
+ }
+ }
+
+ d = (unsigned char*) buffer_string_prepare_append(b, d_len);
+ buffer_commit(b, d_len); /* fill below */
+
+ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
+ if ((*ds < 0x20) /* control character */
+ || (*ds >= 0x7f)) { /* DEL + non-ASCII characters */
+ d[d_len++] = '\\';
+ switch (*ds) {
+ case '\t':
+ d[d_len++] = 't';
+ break;
+ case '\r':
+ d[d_len++] = 'r';
+ break;
+ case '\n':
+ d[d_len++] = 'n';
+ break;
+ default:
+ d[d_len++] = 'x';
+ d[d_len++] = hex_chars_lc[((*ds) >> 4) & 0x0F];
+ d[d_len++] = hex_chars_lc[(*ds) & 0x0F];
+ break;
+ }
+ } else {
+ d[d_len++] = *ds;
+ }
+ }
+}
+
+
+void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header) {
+ size_t i, j = 0;
+
+ force_assert(NULL != b);
+ force_assert(NULL != s || 0 == s_len);
+
+ buffer_string_prepare_copy(b, s_len + 5);
+
+ if (is_http_header && NULL != s && 0 != strcasecmp(s, "CONTENT-TYPE")) {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP_"));
+ j = 5; /* "HTTP_" */
+ }
+
+ for (i = 0; i < s_len; ++i) {
+ unsigned char cr = s[i];
+ if (light_isalpha(cr)) {
+ /* upper-case */
+ cr &= ~32;
+ } else if (!light_isdigit(cr)) {
+ cr = '_';
+ }
+ b->ptr[j++] = cr;
+ }
+ b->used = j;
+ b->ptr[b->used++] = '\0';
+}
+
+/* decodes url-special-chars inplace.
+ * replaces non-printable characters with '_'
+ */
+
+static void buffer_urldecode_internal(buffer *url, int is_query) {
+ unsigned char high, low;
+ char *src;
+ char *dst;
+
+ force_assert(NULL != url);
+ if (buffer_string_is_empty(url)) return;
+
+ force_assert('\0' == url->ptr[url->used-1]);
+
+ src = (char*) url->ptr;
+
+ while ('\0' != *src) {
+ if ('%' == *src) break;
+ if (is_query && '+' == *src) *src = ' ';
+ src++;
+ }
+ dst = src;
+
+ while ('\0' != *src) {
+ if (is_query && *src == '+') {
+ *dst = ' ';
+ } else if (*src == '%') {
+ *dst = '%';
+
+ high = hex2int(*(src + 1));
+ if (0xFF != high) {
+ low = hex2int(*(src + 2));
+ if (0xFF != low) {
+ high = (high << 4) | low;
+
+ /* map control-characters out */
+ if (high < 32 || high == 127) high = '_';
+
+ *dst = high;
+ src += 2;
+ }
+ }
+ } else {
+ *dst = *src;
+ }
+
+ dst++;
+ src++;
+ }
+
+ *dst = '\0';
+ url->used = (dst - url->ptr) + 1;
+}
+
+void buffer_urldecode_path(buffer *url) {
+ buffer_urldecode_internal(url, 0);
+}
+
+void buffer_urldecode_query(buffer *url) {
+ buffer_urldecode_internal(url, 1);
+}
+
+int buffer_is_valid_UTF8(const buffer *b) {
+ /* https://www.w3.org/International/questions/qa-forms-utf-8 */
+ const unsigned char *c = (unsigned char *)b->ptr;
+ while (*c) {
+
+ /*(note: includes ctrls)*/
+ if ( c[0] < 0x80 ) { ++c; continue; }
+
+ if ( 0xc2 <= c[0] && c[0] <= 0xdf
+ && 0x80 <= c[1] && c[1] <= 0xbf ) { c+=2; continue; }
+
+ if ( ( ( 0xe0 == c[0]
+ && 0xa0 <= c[1] && c[1] <= 0xbf)
+ || ( 0xe1 <= c[0] && c[0] <= 0xef && c[0] != 0xed
+ && 0x80 <= c[1] && c[1] <= 0xbf)
+ || ( 0xed == c[0]
+ && 0x80 <= c[1] && c[1] <= 0x9f) )
+ && 0x80 <= c[2] && c[2] <= 0xbf ) { c+=3; continue; }
+
+ if ( ( ( 0xf0 == c[0]
+ && 0x90 <= c[1] && c[1] <= 0xbf)
+ || ( 0xf1 <= c[0] && c[0] <= 0xf3
+ && 0x80 <= c[1] && c[1] <= 0xbf)
+ || ( 0xf4 == c[0]
+ && 0x80 <= c[1] && c[1] <= 0x8f) )
+ && 0x80 <= c[2] && c[2] <= 0xbf
+ && 0x80 <= c[3] && c[3] <= 0xbf ) { c+=4; continue; }
+
+ return 0; /* invalid */
+ }
+ return 1; /* valid */
+}
+
+/* - special case: empty string returns empty string
+ * - on windows or cygwin: replace \ with /
+ * - strip leading spaces
+ * - prepends "/" if not present already
+ * - resolve "/../", "//" and "/./" the usual way:
+ * the first one removes a preceding component, the other two
+ * get compressed to "/".
+ * - "/." and "/.." at the end are similar, but always leave a trailing
+ * "/"
+ *
+ * /blah/.. gets /
+ * /blah/../foo gets /foo
+ * /abc/./xyz gets /abc/xyz
+ * /abc//xyz gets /abc/xyz
+ *
+ * NOTE: src and dest can point to the same buffer, in which case,
+ * the operation is performed in-place.
+ */
+
+void buffer_path_simplify(buffer *dest, buffer *src)
+{
+ /* current character, the one before, and the one before that from input */
+ char c, pre1, pre2;
+ char *start, *slash, *walk, *out;
+
+ force_assert(NULL != dest && NULL != src);
+
+ if (buffer_string_is_empty(src)) {
+ buffer_copy_string_len(dest, CONST_STR_LEN(""));
+ return;
+ }
+
+ force_assert('\0' == src->ptr[src->used-1]);
+
+#if defined(__WIN32) || defined(__CYGWIN__)
+ /* cygwin is treating \ and / the same, so we have to that too */
+ {
+ char *p;
+ for (p = src->ptr; *p; p++) {
+ if (*p == '\\') *p = '/';
+ }
+ }
+#endif
+
+ walk = src->ptr;
+ start = dest->ptr;
+ out = dest->ptr;
+ slash = dest->ptr;
+
+ /* skip leading spaces */
+ while (*walk == ' ') {
+ walk++;
+ }
+ if (*walk == '.') {
+ if (walk[1] == '/' || walk[1] == '\0')
+ ++walk;
+ else if (walk[1] == '.' && (walk[2] == '/' || walk[2] == '\0'))
+ walk+=2;
+ }
+
+ pre1 = 0;
+ c = *(walk++);
+
+ while (c != '\0') {
+ /* assert((src != dest || out <= walk) && slash <= out); */
+ /* the following comments about out and walk are only interesting if
+ * src == dest; otherwise the memory areas don't overlap anyway.
+ */
+ pre2 = pre1;
+ pre1 = c;
+
+ /* possibly: out == walk - need to read first */
+ c = *walk;
+ *out = pre1;
+
+ out++;
+ walk++;
+ /* (out <= walk) still true; also now (slash < out) */
+
+ if (c == '/' || c == '\0') {
+ const size_t toklen = out - slash;
+ if (toklen == 3 && pre2 == '.' && pre1 == '.' && *slash == '/') {
+ /* "/../" or ("/.." at end of string) */
+ out = slash;
+ /* if there is something before "/..", there is at least one
+ * component, which needs to be removed */
+ if (out > start) {
+ out--;
+ while (out > start && *out != '/') out--;
+ }
+
+ /* don't kill trailing '/' at end of path */
+ if (c == '\0') out++;
+ /* slash < out before, so out_new <= slash + 1 <= out_before <= walk */
+ } else if (toklen == 1 || (pre2 == '/' && pre1 == '.')) {
+ /* "//" or "/./" or (("/" or "/.") at end of string) */
+ out = slash;
+ /* don't kill trailing '/' at end of path */
+ if (c == '\0') out++;
+ /* slash < out before, so out_new <= slash + 1 <= out_before <= walk */
+ }
+
+ slash = out;
+ }
+ }
+
+ buffer_string_set_length(dest, out - start);
+}
+
+void buffer_to_lower(buffer *b) {
+ size_t i;
+
+ for (i = 0; i < b->used; ++i) {
+ char c = b->ptr[i];
+ if (c >= 'A' && c <= 'Z') b->ptr[i] |= 0x20;
+ }
+}
+
+
+void buffer_to_upper(buffer *b) {
+ size_t i;
+
+ for (i = 0; i < b->used; ++i) {
+ char c = b->ptr[i];
+ if (c >= 'a' && c <= 'z') b->ptr[i] &= ~0x20;
+ }
+}
+
+
+#include <stdio.h>
+
+#ifdef HAVE_LIBUNWIND
+# define UNW_LOCAL_ONLY
+# include <libunwind.h>
+
+static void print_backtrace(FILE *file) {
+ unw_cursor_t cursor;
+ unw_context_t context;
+ int ret;
+ unsigned int frame = 0;
+
+ if (0 != (ret = unw_getcontext(&context))) goto error;
+ if (0 != (ret = unw_init_local(&cursor, &context))) goto error;
+
+ fprintf(file, "Backtrace:\n");
+
+ while (0 < (ret = unw_step(&cursor))) {
+ unw_word_t proc_ip = 0;
+ unw_proc_info_t procinfo;
+ char procname[256];
+ unw_word_t proc_offset = 0;
+
+ if (0 != (ret = unw_get_reg(&cursor, UNW_REG_IP, &proc_ip))) goto error;
+
+ if (0 == proc_ip) {
+ /* without an IP the other functions are useless; unw_get_proc_name would return UNW_EUNSPEC */
+ ++frame;
+ fprintf(file, "%u: (nil)\n", frame);
+ continue;
+ }
+
+ if (0 != (ret = unw_get_proc_info(&cursor, &procinfo))) goto error;
+
+ if (0 != (ret = unw_get_proc_name(&cursor, procname, sizeof(procname), &proc_offset))) {
+ switch (-ret) {
+ case UNW_ENOMEM:
+ memset(procname + sizeof(procname) - 4, '.', 3);
+ procname[sizeof(procname) - 1] = '\0';
+ break;
+ case UNW_ENOINFO:
+ procname[0] = '?';
+ procname[1] = '\0';
+ proc_offset = 0;
+ break;
+ default:
+ snprintf(procname, sizeof(procname), "?? (unw_get_proc_name error %d)", -ret);
+ break;
+ }
+ }
+
+ ++frame;
+ fprintf(file, "%u: %s (+0x%x) [%p]\n",
+ frame,
+ procname,
+ (unsigned int) proc_offset,
+ (void*)(uintptr_t)proc_ip);
+ }
+
+ if (0 != ret) goto error;
+
+ return;
+
+error:
+ fprintf(file, "Error while generating backtrace: unwind error %i\n", (int) -ret);
+}
+#else
+static void print_backtrace(FILE *file) {
+ UNUSED(file);
+}
+#endif
+
+void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
+ /* can't use buffer here; could lead to recursive assertions */
+ fprintf(stderr, "%s.%u: %s\n", filename, line, msg);
+ print_backtrace(stderr);
+ fflush(stderr);
+ abort();
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/buffer.h b/data/lighttpd/lighttpd-1.4.53/src/buffer.h
new file mode 100644
index 000000000..df461e1a8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/buffer.h
@@ -0,0 +1,226 @@
+#ifndef _BUFFER_H_
+#define _BUFFER_H_
+#include "first.h"
+
+struct tm; /* declaration */
+
+/* generic string + binary data container; contains a terminating 0 in both
+ * cases
+ *
+ * used == 0 indicates a special "empty" state (unset config values); ptr
+ * might be NULL too then. otherwise an empty string has used == 1 (and ptr[0]
+ * == 0);
+ *
+ * copy/append functions will ensure used >= 1 (i.e. never leave it in the
+ * special empty state); only buffer_copy_buffer will copy the special empty
+ * state.
+ */
+typedef struct {
+ char *ptr;
+
+ /* "used" includes a terminating 0 */
+ size_t used;
+ /* size of allocated buffer at *ptr */
+ size_t size;
+} buffer;
+
+/* create new buffer; either empty or copy given data */
+buffer* buffer_init(void);
+buffer* buffer_init_buffer(const buffer *src); /* src can be NULL */
+buffer* buffer_init_string(const char *str); /* str can be NULL */
+
+void buffer_free(buffer *b); /* b can be NULL */
+/* truncates to used == 0; frees large buffers, might keep smaller ones for reuse */
+void buffer_reset(buffer *b); /* b can be NULL */
+
+/* reset b. if NULL != b && NULL != src, move src content to b. reset src. */
+void buffer_move(buffer *b, buffer *src);
+
+/* make sure buffer is large enough to store a string of given size
+ * and a terminating zero.
+ * sets b to an empty string, and may drop old content.
+ * @return b->ptr
+ */
+char* buffer_string_prepare_copy(buffer *b, size_t size);
+
+/* allocate buffer large enough to be able to append a string of given size
+ * if b was empty (used == 0) it will contain an empty string (used == 1)
+ * afterwards
+ * "used" data is preserved; if not empty buffer must contain a
+ * zero terminated string.
+ */
+char* buffer_string_prepare_append(buffer *b, size_t size);
+
+/* use after prepare_(copy,append) when you have written data to the buffer
+ * to increase the buffer length by size. also sets the terminating zero.
+ * requires enough space is present for the terminating zero (prepare with the
+ * same size to be sure).
+ */
+void buffer_commit(buffer *b, size_t size);
+
+/* sets string length:
+ * - always stores a terminating zero to terminate the "new" string
+ * - does not modify the string data apart from terminating zero
+ * - reallocates the buffer iff needed
+ */
+void buffer_string_set_length(buffer *b, size_t len);
+
+/* clear buffer
+ * - invalidate buffer contents
+ * - unsets used chars but does not modify existing ptr contents
+ * (b->ptr *is not* set to an empty, '\0'-terminated string "")
+ */
+static inline void buffer_clear(buffer *b);
+
+void buffer_copy_string(buffer *b, const char *s);
+void buffer_copy_string_len(buffer *b, const char *s, size_t s_len);
+static inline void buffer_copy_buffer(buffer *b, const buffer *src);
+
+void buffer_append_string(buffer *b, const char *s);
+void buffer_append_string_len(buffer *b, const char *s, size_t s_len);
+static inline void buffer_append_string_buffer(buffer *b, const buffer *src);
+
+#define buffer_append_uint_hex(b,len) buffer_append_uint_hex_lc((b),(len))
+void buffer_append_uint_hex_lc(buffer *b, uintmax_t len);
+void buffer_append_int(buffer *b, intmax_t val);
+void buffer_copy_int(buffer *b, intmax_t val);
+
+void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm);
+
+/* '-', log_10 (2^bits) = bits * log 2 / log 10 < bits * 0.31, terminating 0 */
+#define LI_ITOSTRING_LENGTH (2 + (8 * sizeof(intmax_t) * 31 + 99) / 100)
+
+void li_itostrn(char *buf, size_t buf_len, intmax_t val);
+void li_utostrn(char *buf, size_t buf_len, uintmax_t val);
+
+/* buf must be (at least) 2*s_len + 1 big. uses lower-case hex letters. */
+#define li_tohex(buf,buf_len,s,s_len) li_tohex_lc((buf),(buf_len),(s),(s_len))
+void li_tohex_lc(char *buf, size_t buf_len, const char *s, size_t s_len);
+void li_tohex_uc(char *buf, size_t buf_len, const char *s, size_t s_len);
+
+/* NULL buffer or empty buffer (used == 0);
+ * unset "string" (buffer) config options are initialized to used == 0,
+ * while setting an empty string leads to used == 1
+ */
+static inline int buffer_is_empty(const buffer *b);
+/* NULL buffer, empty buffer (used == 0) or empty string (used == 1) */
+static inline int buffer_string_is_empty(const buffer *b);
+
+int buffer_is_equal(const buffer *a, const buffer *b);
+int buffer_is_equal_right_len(const buffer *a, const buffer *b, size_t len);
+int buffer_is_equal_string(const buffer *a, const char *s, size_t b_len);
+int buffer_is_equal_caseless_string(const buffer *a, const char *s, size_t b_len);
+int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len);
+
+void buffer_substr_replace (buffer *b, size_t offset, size_t len, const buffer *replace);
+
+void buffer_append_string_encoded_hex_lc(buffer *b, const char *s, size_t len);
+void buffer_append_string_encoded_hex_uc(buffer *b, const char *s, size_t len);
+
+typedef enum {
+ ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
+ ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
+ ENCODING_HTML, /* & becomes &amp; and so on */
+ ENCODING_MINIMAL_XML /* minimal encoding for xml */
+} buffer_encoding_t;
+
+void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
+
+/* escape non-printable characters; simple escapes for \t, \r, \n; fallback to \xCC */
+void buffer_append_string_c_escaped(buffer *b, const char *s, size_t s_len);
+
+/* to upper case, replace non alpha-numerics with '_'; if is_http_header prefix with "HTTP_" unless s is "content-type" */
+void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header);
+
+void buffer_urldecode_path(buffer *url);
+void buffer_urldecode_query(buffer *url);
+int buffer_is_valid_UTF8(const buffer *b);
+void buffer_path_simplify(buffer *dest, buffer *src);
+
+void buffer_to_lower(buffer *b);
+void buffer_to_upper(buffer *b);
+
+
+/** deprecated */
+char hex2int(unsigned char c);
+char int2hex(char i);
+
+static inline int light_isdigit(int c);
+static inline int light_isxdigit(int c);
+static inline int light_isalpha(int c);
+static inline int light_isalnum(int c);
+
+static inline int light_isdigit(int c) {
+ return (c >= '0' && c <= '9');
+}
+
+static inline int light_isxdigit(int c) {
+ return light_isdigit(c) || (c |= 32, c >= 'a' && c <= 'f');
+}
+
+static inline int light_isalpha(int c) {
+ return (c |= 32, c >= 'a' && c <= 'z');
+}
+
+static inline int light_isalnum(int c) {
+ return light_isdigit(c) || light_isalpha(c);
+}
+
+
+static inline size_t buffer_string_length(const buffer *b); /* buffer string length without terminating 0 */
+static inline size_t buffer_string_space(const buffer *b); /* maximum length of string that can be stored without reallocating */
+static inline void buffer_append_slash(buffer *b); /* append '/' no non-empty strings not ending in '/' */
+void buffer_append_path_len(buffer *b, const char *a, size_t alen); /* join strings with '/', if '/' not present */
+
+#define BUFFER_APPEND_STRING_CONST(x, y) \
+ buffer_append_string_len(x, y, sizeof(y) - 1)
+
+#define BUFFER_COPY_STRING_CONST(x, y) \
+ buffer_copy_string_len(x, y, sizeof(y) - 1)
+
+#define CONST_STR_LEN(x) x, (x) ? sizeof(x) - 1 : 0
+#define CONST_BUF_LEN(x) ((x) ? (x)->ptr : NULL), buffer_string_length(x)
+
+
+#define LI_NORETURN __attribute_noreturn__
+
+__attribute_cold__
+void log_failed_assert(const char *filename, unsigned int line, const char *msg) LI_NORETURN;
+#define force_assert(x) do { if (!(x)) log_failed_assert(__FILE__, __LINE__, "assertion failed: " #x); } while(0)
+#define SEGFAULT() log_failed_assert(__FILE__, __LINE__, "aborted");
+
+/* inline implementations */
+
+static inline int buffer_is_empty(const buffer *b) {
+ return NULL == b || 0 == b->used;
+}
+static inline int buffer_string_is_empty(const buffer *b) {
+ return NULL == b || b->used < 2;
+}
+
+static inline size_t buffer_string_length(const buffer *b) {
+ return NULL != b && 0 != b->used ? b->used - 1 : 0;
+}
+
+static inline size_t buffer_string_space(const buffer *b) {
+ return NULL != b && b->size ? b->size - (b->used | (0 == b->used)) : 0;
+}
+
+static inline void buffer_copy_buffer(buffer *b, const buffer *src) {
+ buffer_copy_string_len(b, CONST_BUF_LEN(src));
+}
+
+static inline void buffer_append_string_buffer(buffer *b, const buffer *src) {
+ buffer_append_string_len(b, CONST_BUF_LEN(src));
+}
+
+static inline void buffer_append_slash(buffer *b) {
+ size_t len = buffer_string_length(b);
+ if (len > 0 && '/' != b->ptr[len-1]) BUFFER_APPEND_STRING_CONST(b, "/");
+}
+
+static inline void buffer_clear(buffer *b) {
+ b->used = 0;
+}
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/burl.c b/data/lighttpd/lighttpd-1.4.53/src/burl.c
new file mode 100644
index 000000000..511826286
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/burl.c
@@ -0,0 +1,512 @@
+#include "first.h"
+#include "burl.h"
+
+#include <string.h>
+
+#include "buffer.h"
+#include "base64.h"
+
+static const char hex_chars_uc[] = "0123456789ABCDEF";
+
+/* everything except: ! $ & ' ( ) * + , - . / 0-9 : ; = ? @ A-Z _ a-z ~ */
+static const char encoded_chars_http_uri_reqd[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F space " # % */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* 50 - 5F [ \ ] ^ */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* 70 - 7F { | } DEL */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* B0 - BF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0 - CF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* D0 - DF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0 - EF */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
+};
+
+
+/* c (char) and n (nibble) MUST be unsigned integer types */
+#define li_cton(c,n) \
+ (((n) = (c) - '0') <= 9 || (((n) = ((c)&0xdf) - 'A') <= 5 ? ((n) += 10) : 0))
+
+/* b (byte) MUST be unsigned integer type
+ * https://en.wikipedia.org/wiki/UTF-8
+ * reject overlong encodings of 7-byte ASCII and invalid UTF-8
+ * (but does not detect other overlong multi-byte encodings) */
+#define li_utf8_invalid_byte(b) ((b) >= 0xF5 || ((b)|0x1) == 0xC1)
+
+
+static int burl_is_unreserved (const int c)
+{
+ return (light_isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~');
+}
+
+
+static int burl_normalize_basic_unreserved_fix (buffer *b, buffer *t, int i, int qs)
+{
+ int j = i;
+ const int used = (int)buffer_string_length(b);
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ unsigned char * const p =
+ (unsigned char *)buffer_string_prepare_copy(t,i+(used-i)*3+1);
+ unsigned int n1, n2;
+ memcpy(p, s, (size_t)i);
+ for (; i < used; ++i, ++j) {
+ if (!encoded_chars_http_uri_reqd[s[i]]) {
+ if (s[i] == '?' && -1 == qs) qs = j;
+ p[j] = s[i];
+ }
+ else if (s[i]=='%' && li_cton(s[i+1], n1) && li_cton(s[i+2], n2)) {
+ const unsigned int x = (n1 << 4) | n2;
+ if (burl_is_unreserved(x)) {
+ p[j] = x;
+ }
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[n1]; /*(s[i+1] & 0xdf)*/
+ p[++j] = hex_chars_uc[n2]; /*(s[i+2] & 0xdf)*/
+ if (li_utf8_invalid_byte(x)) qs = -2;
+ }
+ i+=2;
+ }
+ else if (s[i] == '#') break; /* ignore fragment */
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[(s[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[s[i] & 0xF];
+ if (li_utf8_invalid_byte(s[i])) qs = -2;
+ }
+ }
+ buffer_commit(t, (size_t)j);
+ buffer_copy_buffer(b, t);
+ return qs;
+}
+
+
+static int burl_normalize_basic_unreserved (buffer *b, buffer *t)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ const int used = (int)buffer_string_length(b);
+ unsigned int n1, n2, x;
+ int qs = -1;
+
+ for (int i = 0; i < used; ++i) {
+ if (!encoded_chars_http_uri_reqd[s[i]]) {
+ if (s[i] == '?' && -1 == qs) qs = i;
+ }
+ else if (s[i]=='%' && li_cton(s[i+1], n1) && li_cton(s[i+2], n2)
+ && !burl_is_unreserved((x = (n1 << 4) | n2))) {
+ if (li_utf8_invalid_byte(x)) qs = -2;
+ if (s[i+1] >= 'a') b->ptr[i+1] &= 0xdf; /* uppercase hex */
+ if (s[i+2] >= 'a') b->ptr[i+2] &= 0xdf; /* uppercase hex */
+ i+=2;
+ }
+ else if (s[i] == '#') { /* ignore fragment */
+ buffer_string_set_length(b, (size_t)i);
+ break;
+ }
+ else {
+ qs = burl_normalize_basic_unreserved_fix(b, t, i, qs);
+ break;
+ }
+ }
+
+ return qs;
+}
+
+
+static int burl_normalize_basic_required_fix (buffer *b, buffer *t, int i, int qs)
+{
+ int j = i;
+ const int used = (int)buffer_string_length(b);
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ unsigned char * const p =
+ (unsigned char *)buffer_string_prepare_copy(t,i+(used-i)*3+1);
+ unsigned int n1, n2;
+ memcpy(p, s, (size_t)i);
+ for (; i < used; ++i, ++j) {
+ if (!encoded_chars_http_uri_reqd[s[i]]) {
+ if (s[i] == '?' && -1 == qs) qs = j;
+ p[j] = s[i];
+ }
+ else if (s[i]=='%' && li_cton(s[i+1], n1) && li_cton(s[i+2], n2)) {
+ const unsigned int x = (n1 << 4) | n2;
+ if (!encoded_chars_http_uri_reqd[x]
+ && (qs < 0 ? (x!='/'&&x!='?') : (x!='&'&&x!='='&&x!=';'))) {
+ p[j] = x;
+ }
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[n1]; /*(s[i+1] & 0xdf)*/
+ p[++j] = hex_chars_uc[n2]; /*(s[i+2] & 0xdf)*/
+ if (li_utf8_invalid_byte(x)) qs = -2;
+ }
+ i+=2;
+ }
+ else if (s[i] == '#') break; /* ignore fragment */
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[(s[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[s[i] & 0xF];
+ if (li_utf8_invalid_byte(s[i])) qs = -2;
+ }
+ }
+ buffer_commit(t, (size_t)j);
+ buffer_copy_buffer(b, t);
+ return qs;
+}
+
+
+static int burl_normalize_basic_required (buffer *b, buffer *t)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ const int used = (int)buffer_string_length(b);
+ unsigned int n1, n2, x;
+ int qs = -1;
+
+ for (int i = 0; i < used; ++i) {
+ if (!encoded_chars_http_uri_reqd[s[i]]) {
+ if (s[i] == '?' && -1 == qs) qs = i;
+ }
+ else if (s[i]=='%' && li_cton(s[i+1], n1) && li_cton(s[i+2], n2)
+ && (encoded_chars_http_uri_reqd[(x = (n1 << 4) | n2)]
+ ||(qs < 0 ? (x=='/'||x=='?') : (x=='&'||x=='='||x==';')))){
+ if (li_utf8_invalid_byte(x)) qs = -2;
+ if (s[i+1] >= 'a') b->ptr[i+1] &= 0xdf; /* uppercase hex */
+ if (s[i+2] >= 'a') b->ptr[i+2] &= 0xdf; /* uppercase hex */
+ i+=2;
+ }
+ else if (s[i] == '#') { /* ignore fragment */
+ buffer_string_set_length(b, (size_t)i);
+ break;
+ }
+ else {
+ qs = burl_normalize_basic_required_fix(b, t, i, qs);
+ break;
+ }
+ }
+
+ return qs;
+}
+
+
+static int burl_contains_ctrls (const buffer *b)
+{
+ const char * const s = b->ptr;
+ const int used = (int)buffer_string_length(b);
+ for (int i = 0; i < used; ++i) {
+ if (s[i] == '%' && (s[i+1] < '2' || (s[i+1] == '7' && s[i+2] == 'F')))
+ return 1;
+ }
+ return 0;
+}
+
+
+static void burl_normalize_qs20_to_plus_fix (buffer *b, int i)
+{
+ char * const s = b->ptr;
+ const int used = (int)buffer_string_length(b);
+ int j = i;
+ for (; i < used; ++i, ++j) {
+ s[j] = s[i];
+ if (s[i] == '%' && s[i+1] == '2' && s[i+2] == '0') {
+ s[j] = '+';
+ i+=2;
+ }
+ }
+ buffer_string_set_length(b, j);
+}
+
+
+static void burl_normalize_qs20_to_plus (buffer *b, int qs)
+{
+ const char * const s = b->ptr;
+ const int used = qs < 0 ? 0 : (int)buffer_string_length(b);
+ int i;
+ if (qs < 0) return;
+ for (i = qs+1; i < used; ++i) {
+ if (s[i] == '%' && s[i+1] == '2' && s[i+2] == '0') break;
+ }
+ if (i != used) burl_normalize_qs20_to_plus_fix(b, i);
+}
+
+
+static int burl_normalize_2F_to_slash_fix (buffer *b, int qs, int i)
+{
+ char * const s = b->ptr;
+ const int blen = (int)buffer_string_length(b);
+ const int used = qs < 0 ? blen : qs;
+ int j = i;
+ for (; i < used; ++i, ++j) {
+ s[j] = s[i];
+ if (s[i] == '%' && s[i+1] == '2' && s[i+2] == 'F') {
+ s[j] = '/';
+ i+=2;
+ }
+ }
+ if (qs >= 0) {
+ memmove(s+j, s+qs, blen - qs);
+ j += blen - qs;
+ }
+ buffer_string_set_length(b, j);
+ return qs;
+}
+
+
+static int burl_normalize_2F_to_slash (buffer *b, int qs, int flags)
+{
+ /*("%2F" must already have been uppercased during normalization)*/
+ const char * const s = b->ptr;
+ const int used = qs < 0 ? (int)buffer_string_length(b) : qs;
+ for (int i = 0; i < used; ++i) {
+ if (s[i] == '%' && s[i+1] == '2' && s[i+2] == 'F') {
+ return (flags & HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE)
+ ? burl_normalize_2F_to_slash_fix(b, qs, i)
+ : -2; /*(flags & HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT)*/
+ }
+ }
+ return qs;
+}
+
+
+static int burl_normalize_path (buffer *b, buffer *t, int qs, int flags)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ const int used = (int)buffer_string_length(b);
+ int path_simplify = 0;
+ for (int i = 0, len = qs < 0 ? used : qs; i < len; ++i) {
+ if (s[i] == '.' && (s[i+1] != '.' || ++i)
+ && (s[i+1] == '/' || s[i+1] == '?' || s[i+1] == '\0')) {
+ path_simplify = 1;
+ break;
+ }
+ do { ++i; } while (i < len && s[i] != '/');
+ if (s[i] == '/' && s[i+1] == '/') { /*(s[len] != '/')*/
+ path_simplify = 1;
+ break;
+ }
+ }
+
+ if (path_simplify) {
+ if (flags & HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT) return -2;
+ if (qs >= 0) {
+ buffer_copy_string_len(t, b->ptr+qs, used - qs);
+ buffer_string_set_length(b, qs);
+ }
+
+ buffer_path_simplify(b, b);
+
+ if (qs >= 0) {
+ qs = (int)buffer_string_length(b);
+ buffer_append_string_len(b, CONST_BUF_LEN(t));
+ }
+ }
+
+ return qs;
+}
+
+
+int burl_normalize (buffer *b, buffer *t, int flags)
+{
+ int qs;
+
+ #if defined(__WIN32) || defined(__CYGWIN__)
+ /* Windows and Cygwin treat '\\' as '/' if '\\' is present in path;
+ * convert to '/' for consistency before percent-encoding
+ * normalization which will convert '\\' to "%5C" in the URL.
+ * (Clients still should not be sending '\\' unencoded in requests.) */
+ if (flags & HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS) {
+ for (char *p = b->ptr; *p != '?' && *p != '\0'; ++p) {
+ if (*p == '\\') *p = '/';
+ }
+ }
+ #endif
+
+ qs = (flags & HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED)
+ ? burl_normalize_basic_required(b, t)
+ : burl_normalize_basic_unreserved(b, t);
+ if (-2 == qs) return -2;
+
+ if (flags & HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT) {
+ if (burl_contains_ctrls(b)) return -2;
+ }
+
+ if (flags & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
+ |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT)) {
+ qs = burl_normalize_2F_to_slash(b, qs, flags);
+ if (-2 == qs) return -2;
+ }
+
+ if (flags & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE
+ |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT)) {
+ qs = burl_normalize_path(b, t, qs, flags);
+ if (-2 == qs) return -2;
+ }
+
+ if (flags & HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS) {
+ if (qs >= 0) burl_normalize_qs20_to_plus(b, qs);
+ }
+
+ return qs;
+}
+
+
+static void burl_append_encode_nde (buffer * const b, const char * const str, const size_t len)
+{
+ /* percent-encodes everything except unreserved - . 0-9 A-Z _ a-z ~
+ * unless already percent-encoded (does not double-encode) */
+ /* Note: not checking for invalid UTF-8 */
+ char * const p = buffer_string_prepare_append(b, len*3);
+ unsigned int n1, n2;
+ int j = 0;
+ for (unsigned int i = 0; i < len; ++i, ++j) {
+ if (str[i]=='%' && li_cton(str[i+1], n1) && li_cton(str[i+2], n2)) {
+ const unsigned int x = (n1 << 4) | n2;
+ if (burl_is_unreserved((int)x)) {
+ p[j] = (char)x;
+ }
+ else { /* leave UTF-8, control chars, and required chars encoded */
+ p[j] = '%';
+ p[++j] = str[i+1];
+ p[++j] = str[i+2];
+ }
+ i+=2;
+ }
+ else if (burl_is_unreserved(str[i])) {
+ p[j] = str[i];
+ }
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[(str[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[str[i] & 0xF];
+ }
+ }
+ buffer_commit(b, j);
+}
+
+
+static void burl_append_encode_psnde (buffer * const b, const char * const str, const size_t len)
+{
+ /* percent-encodes everything except unreserved - . 0-9 A-Z _ a-z ~ plus /
+ * unless already percent-encoded (does not double-encode) */
+ /* Note: not checking for invalid UTF-8 */
+ char * const p = buffer_string_prepare_append(b, len*3);
+ unsigned int n1, n2;
+ int j = 0;
+ for (unsigned int i = 0; i < len; ++i, ++j) {
+ if (str[i]=='%' && li_cton(str[i+1], n1) && li_cton(str[i+2], n2)) {
+ const unsigned int x = (n1 << 4) | n2;
+ if (burl_is_unreserved((int)x)) {
+ p[j] = (char)x;
+ }
+ else { /* leave UTF-8, control chars, and required chars encoded */
+ p[j] = '%';
+ p[++j] = str[i+1];
+ p[++j] = str[i+2];
+ }
+ i+=2;
+ }
+ else if (burl_is_unreserved(str[i]) || str[i] == '/') {
+ p[j] = str[i];
+ }
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[(str[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[str[i] & 0xF];
+ }
+ }
+ buffer_commit(b, j);
+}
+
+
+static void burl_append_encode_all (buffer * const b, const char * const str, const size_t len)
+{
+ /* percent-encodes everything except unreserved - . 0-9 A-Z _ a-z ~
+ * Note: double-encodes any existing '%') */
+ /* Note: not checking for invalid UTF-8 */
+ char * const p = buffer_string_prepare_append(b, len*3);
+ int j = 0;
+ for (unsigned int i = 0; i < len; ++i, ++j) {
+ if (burl_is_unreserved(str[i])) {
+ p[j] = str[i];
+ }
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[(str[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[str[i] & 0xF];
+ }
+ }
+ buffer_commit(b, j);
+}
+
+
+static void burl_offset_tolower (buffer * const b, const size_t off)
+{
+ /*(skips over all percent-encodings, including encoding of alpha chars)*/
+ for (char *p = b->ptr+off; p[0]; ++p) {
+ if (p[0] >= 'A' && p[0] <= 'Z') p[0] |= 0x20;
+ else if (p[0]=='%' && light_isxdigit(p[1]) && light_isxdigit(p[2]))
+ p+=2;
+ }
+}
+
+
+static void burl_offset_toupper (buffer * const b, const size_t off)
+{
+ /*(skips over all percent-encodings, including encoding of alpha chars)*/
+ for (char *p = b->ptr+off; p[0]; ++p) {
+ if (p[0] >= 'a' && p[0] <= 'z') p[0] &= 0xdf;
+ else if (p[0]=='%' && light_isxdigit(p[1]) && light_isxdigit(p[2]))
+ p+=2;
+ }
+}
+
+
+void burl_append (buffer * const b, const char * const str, const size_t len, const int flags)
+{
+ size_t off = 0;
+
+ if (0 == len) return;
+
+ if (0 == flags) {
+ buffer_append_string_len(b, str, len);
+ return;
+ }
+
+ if (flags & (BURL_TOUPPER|BURL_TOLOWER)) off = buffer_string_length(b);
+
+ if (flags & BURL_ENCODE_NONE) {
+ buffer_append_string_len(b, str, len);
+ }
+ else if (flags & BURL_ENCODE_ALL) {
+ burl_append_encode_all(b, str, len);
+ }
+ else if (flags & BURL_ENCODE_NDE) {
+ burl_append_encode_nde(b, str, len);
+ }
+ else if (flags & BURL_ENCODE_PSNDE) {
+ burl_append_encode_psnde(b, str, len);
+ }
+ else if (flags & BURL_ENCODE_B64U) {
+ const unsigned char *s = (const unsigned char *)str;
+ buffer_append_base64_encode_no_padding(b, s, len, BASE64_URL);
+ }
+ else if (flags & BURL_DECODE_B64U) {
+ buffer_append_base64_decode(b, str, len, BASE64_URL);
+ }
+
+ /* note: not normalizing str, which could come from arbitrary header,
+ * so it is possible that alpha chars are percent-encoded upper/lowercase */
+ if (flags & (BURL_TOLOWER|BURL_TOUPPER)) {
+ (flags & BURL_TOLOWER)
+ ? burl_offset_tolower(b, off) /*(flags & BURL_TOLOWER)*/
+ : burl_offset_toupper(b, off); /*(flags & BURL_TOUPPER)*/
+ }
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/burl.h b/data/lighttpd/lighttpd-1.4.53/src/burl.h
new file mode 100644
index 000000000..4eb8f3ea1
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/burl.h
@@ -0,0 +1,46 @@
+#ifndef INCLUDED_BURL_H
+#define INCLUDED_BURL_H
+#include "first.h"
+
+#include "buffer.h"
+
+struct burl_parts_t {
+ buffer *scheme;
+ buffer *authority;
+ unsigned short port;
+ buffer *path;
+ buffer *query;
+};
+
+enum burl_opts_e {
+ HTTP_PARSEOPT_HEADER_STRICT = 0x1
+ ,HTTP_PARSEOPT_HOST_STRICT = 0x2
+ ,HTTP_PARSEOPT_HOST_NORMALIZE = 0x4
+ ,HTTP_PARSEOPT_URL_NORMALIZE = 0x8/*normalize chars %-encoded, uppercase hex*/
+ ,HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED =0x10 /* decode unreserved */
+ ,HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED =0x20 /* decode (un)reserved*/
+ ,HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT =0x40
+ ,HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS=0x80 /* "\\" -> "/" Cygwin */
+ ,HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE =0x100/* "%2F"-> "/" */
+ ,HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT =0x200
+ ,HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE =0x400/* "." ".." "//" */
+ ,HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT =0x800
+ ,HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS =0x1000
+};
+
+int burl_normalize (buffer *b, buffer *t, int flags);
+
+enum burl_recoding_e {
+ BURL_TOLOWER = 0x0001
+ ,BURL_TOUPPER = 0x0002
+ ,BURL_ENCODE_NONE = 0x0004
+ ,BURL_ENCODE_ALL = 0x0008
+ ,BURL_ENCODE_NDE = 0x0010 /* encode delims, but no-double-encode (NDE) */
+ ,BURL_ENCODE_PSNDE = 0x0020 /* similar to NDE, but preserve literal slash */
+ ,BURL_ENCODE_B64U = 0x0040
+ ,BURL_DECODE_B64U = 0x0080
+};
+
+void burl_append (buffer * const b, const char * const str, const size_t len, const int flags);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/chunk.c b/data/lighttpd/lighttpd-1.4.53/src/chunk.c
new file mode 100644
index 000000000..b7b692201
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/chunk.c
@@ -0,0 +1,830 @@
+#include "first.h"
+
+/**
+ * the network chunk-API
+ *
+ *
+ */
+
+#include "chunk.h"
+#include "fdevent.h"
+#include "log.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sys-mmap.h"
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+/* default 1MB, upper limit 128MB */
+#define DEFAULT_TEMPFILE_SIZE (1 * 1024 * 1024)
+#define MAX_TEMPFILE_SIZE (128 * 1024 * 1024)
+
+static size_t chunk_buf_sz = 4096;
+static chunk *chunks;
+static chunk *chunk_buffers;
+static array *chunkqueue_default_tempdirs = NULL;
+static unsigned int chunkqueue_default_tempfile_size = DEFAULT_TEMPFILE_SIZE;
+
+void chunkqueue_set_chunk_size (size_t sz)
+{
+ chunk_buf_sz = sz > 0 ? ((sz + 1023) & ~1023uL) : 4096;
+}
+
+void chunkqueue_set_tempdirs_default_reset (void)
+{
+ chunkqueue_default_tempdirs = NULL;
+ chunkqueue_default_tempfile_size = DEFAULT_TEMPFILE_SIZE;
+}
+
+chunkqueue *chunkqueue_init(void) {
+ chunkqueue *cq;
+
+ cq = calloc(1, sizeof(*cq));
+ force_assert(NULL != cq);
+
+ cq->first = NULL;
+ cq->last = NULL;
+
+ cq->tempdirs = chunkqueue_default_tempdirs;
+ cq->upload_temp_file_size = chunkqueue_default_tempfile_size;
+
+ return cq;
+}
+
+static chunk *chunk_init(size_t sz) {
+ chunk *c;
+
+ c = calloc(1, sizeof(*c));
+ force_assert(NULL != c);
+
+ c->type = MEM_CHUNK;
+ c->mem = buffer_init();
+ c->file.start = c->file.length = c->file.mmap.offset = 0;
+ c->file.fd = -1;
+ c->file.mmap.start = MAP_FAILED;
+ c->file.mmap.length = 0;
+ c->file.is_temp = 0;
+ c->offset = 0;
+ c->next = NULL;
+
+ buffer_string_prepare_copy(c->mem, sz-1);
+
+ return c;
+}
+
+static void chunk_reset_file_chunk(chunk *c) {
+ if (c->file.is_temp && !buffer_string_is_empty(c->mem)) {
+ unlink(c->mem->ptr);
+ }
+ if (c->file.fd != -1) {
+ close(c->file.fd);
+ c->file.fd = -1;
+ }
+ if (MAP_FAILED != c->file.mmap.start) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ }
+ c->file.start = c->file.length = c->file.mmap.offset = 0;
+ c->file.mmap.length = 0;
+ c->file.is_temp = 0;
+ c->type = MEM_CHUNK;
+}
+
+static void chunk_reset(chunk *c) {
+ if (c->type == FILE_CHUNK) chunk_reset_file_chunk(c);
+
+ buffer_clear(c->mem);
+ c->offset = 0;
+}
+
+static void chunk_free(chunk *c) {
+ if (c->type == FILE_CHUNK) chunk_reset_file_chunk(c);
+ buffer_free(c->mem);
+ free(c);
+}
+
+buffer * chunk_buffer_acquire(void) {
+ chunk *c;
+ buffer *b;
+ if (chunks) {
+ c = chunks;
+ chunks = c->next;
+ }
+ else {
+ c = chunk_init(chunk_buf_sz);
+ }
+ c->next = chunk_buffers;
+ chunk_buffers = c;
+ b = c->mem;
+ c->mem = NULL;
+ return b;
+}
+
+void chunk_buffer_release(buffer *b) {
+ if (NULL == b) return;
+ if (b->size >= chunk_buf_sz && chunk_buffers) {
+ chunk *c = chunk_buffers;
+ chunk_buffers = c->next;
+ c->mem = b;
+ c->next = chunks;
+ chunks = c;
+ buffer_clear(b);
+ }
+ else {
+ buffer_free(b);
+ }
+}
+
+static chunk * chunk_acquire(void) {
+ if (chunks) {
+ chunk *c = chunks;
+ chunks = c->next;
+ return c;
+ }
+ else {
+ return chunk_init(chunk_buf_sz);
+ }
+}
+
+static void chunk_release(chunk *c) {
+ if (c->mem->size >= chunk_buf_sz) {
+ chunk_reset(c);
+ c->next = chunks;
+ chunks = c;
+ }
+ else {
+ chunk_free(c);
+ }
+}
+
+void chunkqueue_chunk_pool_clear(void)
+{
+ for (chunk *next, *c = chunks; c; c = next) {
+ next = c->next;
+ chunk_free(c);
+ }
+ chunks = NULL;
+}
+
+void chunkqueue_chunk_pool_free(void)
+{
+ chunkqueue_chunk_pool_clear();
+ for (chunk *next, *c = chunk_buffers; c; c = next) {
+ next = c->next;
+ c->mem = buffer_init(); /*(chunk_reset() expects c->mem != NULL)*/
+ chunk_free(c);
+ }
+ chunk_buffers = NULL;
+}
+
+static off_t chunk_remaining_length(const chunk *c) {
+ off_t len = 0;
+ switch (c->type) {
+ case MEM_CHUNK:
+ len = buffer_string_length(c->mem);
+ break;
+ case FILE_CHUNK:
+ len = c->file.length;
+ break;
+ default:
+ force_assert(c->type == MEM_CHUNK || c->type == FILE_CHUNK);
+ break;
+ }
+ force_assert(c->offset <= len);
+ return len - c->offset;
+}
+
+void chunkqueue_free(chunkqueue *cq) {
+ chunk *c, *pc;
+
+ if (NULL == cq) return;
+
+ for (c = cq->first; c; ) {
+ pc = c;
+ c = c->next;
+ chunk_release(pc);
+ }
+
+ free(cq);
+}
+
+static void chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
+ c->next = cq->first;
+ cq->first = c;
+
+ if (NULL == cq->last) {
+ cq->last = c;
+ }
+}
+
+static void chunkqueue_append_chunk(chunkqueue *cq, chunk *c) {
+ c->next = NULL;
+ if (cq->last) {
+ cq->last->next = c;
+ }
+ cq->last = c;
+
+ if (NULL == cq->first) {
+ cq->first = c;
+ }
+}
+
+static chunk * chunkqueue_prepend_mem_chunk(chunkqueue *cq) {
+ chunk *c = chunk_acquire();
+ chunkqueue_prepend_chunk(cq, c);
+ return c;
+}
+
+static chunk * chunkqueue_append_mem_chunk(chunkqueue *cq) {
+ chunk *c = chunk_acquire();
+ chunkqueue_append_chunk(cq, c);
+ return c;
+}
+
+static chunk * chunkqueue_append_file_chunk(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
+ chunk *c = chunk_acquire();
+ chunkqueue_append_chunk(cq, c);
+ c->type = FILE_CHUNK;
+ c->file.start = offset;
+ c->file.length = len;
+ cq->bytes_in += len;
+ buffer_copy_buffer(c->mem, fn);
+ return c;
+}
+
+void chunkqueue_reset(chunkqueue *cq) {
+ chunk *cur = cq->first;
+
+ cq->first = cq->last = NULL;
+
+ while (NULL != cur) {
+ chunk *next = cur->next;
+ chunk_release(cur);
+ cur = next;
+ }
+
+ cq->bytes_in = 0;
+ cq->bytes_out = 0;
+ cq->tempdir_idx = 0;
+}
+
+void chunkqueue_append_file_fd(chunkqueue *cq, buffer *fn, int fd, off_t offset, off_t len) {
+ if (len > 0) {
+ (chunkqueue_append_file_chunk(cq, fn, offset, len))->file.fd = fd;
+ }
+ else {
+ close(fd);
+ }
+}
+
+void chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
+ if (len > 0) {
+ chunkqueue_append_file_chunk(cq, fn, offset, len);
+ }
+}
+
+
+static int chunkqueue_append_mem_extend_chunk(chunkqueue *cq, const char *mem, size_t len) {
+ chunk *c = cq->last;
+ if (0 == len) return 1;
+ if (c != NULL && c->type == MEM_CHUNK
+ && buffer_string_space(c->mem) >= len) {
+ buffer_append_string_len(c->mem, mem, len);
+ cq->bytes_in += len;
+ return 1;
+ }
+ return 0;
+}
+
+
+void chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
+ chunk *c;
+ size_t len = buffer_string_length(mem);
+ if (len < 256 && chunkqueue_append_mem_extend_chunk(cq, mem->ptr, len)) return;
+
+ c = chunkqueue_append_mem_chunk(cq);
+ cq->bytes_in += len;
+ buffer_move(c->mem, mem);
+}
+
+
+void chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
+ chunk *c;
+ if (len < chunk_buf_sz && chunkqueue_append_mem_extend_chunk(cq, mem, len))
+ return;
+
+ c = chunkqueue_append_mem_chunk(cq);
+ cq->bytes_in += len;
+ buffer_copy_string_len(c->mem, mem, len);
+}
+
+
+void chunkqueue_append_mem_min(chunkqueue *cq, const char * mem, size_t len) {
+ chunk *c;
+ if (len < chunk_buf_sz && chunkqueue_append_mem_extend_chunk(cq, mem, len))
+ return;
+
+ c = chunk_init(len+1);
+ chunkqueue_append_chunk(cq, c);
+ cq->bytes_in += len;
+ buffer_copy_string_len(c->mem, mem, len);
+}
+
+
+void chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src) {
+ if (src == NULL || NULL == src->first) return;
+
+ if (NULL == cq->first) {
+ cq->first = src->first;
+ } else {
+ cq->last->next = src->first;
+ }
+ cq->last = src->last;
+ cq->bytes_in += (src->bytes_in - src->bytes_out);
+
+ src->first = NULL;
+ src->last = NULL;
+ src->bytes_out = src->bytes_in;
+}
+
+
+__attribute_cold__
+static void chunkqueue_buffer_open_resize(chunk *c, size_t sz) {
+ chunk * const n = chunk_init((sz + 4095) & ~4095uL);
+ buffer * const b = c->mem;
+ c->mem = n->mem;
+ n->mem = b;
+ chunk_release(n);
+}
+
+
+buffer * chunkqueue_prepend_buffer_open_sz(chunkqueue *cq, size_t sz) {
+ chunk * const c = chunkqueue_prepend_mem_chunk(cq);
+ if (buffer_string_space(c->mem) < sz) {
+ chunkqueue_buffer_open_resize(c, sz);
+ }
+ return c->mem;
+}
+
+
+buffer * chunkqueue_prepend_buffer_open(chunkqueue *cq) {
+ chunk *c = chunkqueue_prepend_mem_chunk(cq);
+ return c->mem;
+}
+
+
+void chunkqueue_prepend_buffer_commit(chunkqueue *cq) {
+ cq->bytes_in += buffer_string_length(cq->first->mem);
+}
+
+
+buffer * chunkqueue_append_buffer_open_sz(chunkqueue *cq, size_t sz) {
+ chunk * const c = chunkqueue_append_mem_chunk(cq);
+ if (buffer_string_space(c->mem) < sz) {
+ chunkqueue_buffer_open_resize(c, sz);
+ }
+ return c->mem;
+}
+
+
+buffer * chunkqueue_append_buffer_open(chunkqueue *cq) {
+ chunk *c = chunkqueue_append_mem_chunk(cq);
+ return c->mem;
+}
+
+
+void chunkqueue_append_buffer_commit(chunkqueue *cq) {
+ cq->bytes_in += buffer_string_length(cq->last->mem);
+}
+
+
+char * chunkqueue_get_memory(chunkqueue *cq, size_t *len) {
+ size_t sz = *len ? *len : (chunk_buf_sz >> 1);
+ buffer *b;
+ chunk *c = cq->last;
+ if (NULL != c && MEM_CHUNK == c->type) {
+ /* return pointer into existing buffer if large enough */
+ size_t avail = buffer_string_space(c->mem);
+ if (avail >= sz) {
+ *len = avail;
+ b = c->mem;
+ return b->ptr + buffer_string_length(b);
+ }
+ }
+
+ /* allocate new chunk */
+ b = chunkqueue_append_buffer_open_sz(cq, sz);
+ *len = buffer_string_space(b);
+ return b->ptr;
+}
+
+void chunkqueue_use_memory(chunkqueue *cq, size_t len) {
+ buffer *b;
+
+ force_assert(NULL != cq);
+ force_assert(NULL != cq->last && MEM_CHUNK == cq->last->type);
+ b = cq->last->mem;
+
+ if (len > 0) {
+ buffer_commit(b, len);
+ cq->bytes_in += len;
+ } else if (buffer_string_is_empty(b)) {
+ /* unused buffer: can't remove chunk easily from
+ * end of list, so just reset the buffer
+ */
+ buffer_clear(b);
+ }
+}
+
+void chunkqueue_set_tempdirs_default (array *tempdirs, unsigned int upload_temp_file_size) {
+ chunkqueue_default_tempdirs = tempdirs;
+ chunkqueue_default_tempfile_size
+ = (0 == upload_temp_file_size) ? DEFAULT_TEMPFILE_SIZE
+ : (upload_temp_file_size > MAX_TEMPFILE_SIZE) ? MAX_TEMPFILE_SIZE
+ : upload_temp_file_size;
+}
+
+#if 0
+void chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs, unsigned int upload_temp_file_size) {
+ force_assert(NULL != cq);
+ cq->tempdirs = tempdirs;
+ cq->upload_temp_file_size
+ = (0 == upload_temp_file_size) ? DEFAULT_TEMPFILE_SIZE
+ : (upload_temp_file_size > MAX_TEMPFILE_SIZE) ? MAX_TEMPFILE_SIZE
+ : upload_temp_file_size;
+ cq->tempdir_idx = 0;
+}
+#endif
+
+void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len) {
+ while (len > 0) {
+ chunk *c = src->first;
+ off_t clen = 0, use;
+
+ if (NULL == c) break;
+
+ clen = chunk_remaining_length(c);
+ if (0 == clen) {
+ /* drop empty chunk */
+ src->first = c->next;
+ if (c == src->last) src->last = NULL;
+ chunk_release(c);
+ continue;
+ }
+
+ use = len >= clen ? clen : len;
+ len -= use;
+
+ if (use == clen) {
+ /* move complete chunk */
+ src->first = c->next;
+ if (c == src->last) src->last = NULL;
+
+ chunkqueue_append_chunk(dest, c);
+ dest->bytes_in += use;
+ } else {
+ /* partial chunk with length "use" */
+
+ switch (c->type) {
+ case MEM_CHUNK:
+ chunkqueue_append_mem(dest, c->mem->ptr + c->offset, use);
+ break;
+ case FILE_CHUNK:
+ /* tempfile flag is in "last" chunk after the split */
+ chunkqueue_append_file(dest, c->mem, c->file.start + c->offset, use);
+ break;
+ }
+
+ c->offset += use;
+ force_assert(0 == len);
+ }
+
+ src->bytes_out += use;
+ }
+}
+
+static chunk *chunkqueue_get_append_tempfile(server *srv, chunkqueue *cq) {
+ chunk *c;
+ buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
+ int fd = -1;
+
+ if (cq->tempdirs && cq->tempdirs->used) {
+ /* we have several tempdirs, only if all of them fail we jump out */
+
+ for (errno = EIO; cq->tempdir_idx < cq->tempdirs->used; ++cq->tempdir_idx) {
+ data_string *ds = (data_string *)cq->tempdirs->data[cq->tempdir_idx];
+
+ buffer_copy_buffer(template, ds->value);
+ buffer_append_path_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX"));
+
+ #ifdef __COVERITY__
+ /* POSIX-2008 requires mkstemp create file with 0600 perms */
+ umask(0600);
+ #endif
+ /* coverity[secure_temp : FALSE] */
+ if (-1 != (fd = mkstemp(template->ptr))) break;
+ }
+ } else {
+ #ifdef __COVERITY__
+ /* POSIX-2008 requires mkstemp create file with 0600 perms */
+ umask(0600);
+ #endif
+ /* coverity[secure_temp : FALSE] */
+ fd = mkstemp(template->ptr);
+ }
+
+ if (fd < 0) {
+ /* (report only the last error to mkstemp()
+ * if multiple temp dirs attempted) */
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "opening temp-file failed:",
+ template, strerror(errno));
+ buffer_free(template);
+ return NULL;
+ }
+
+ if (0 != fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_APPEND)) {
+ /* (should not happen; fd is regular file) */
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "fcntl():", template, strerror(errno));
+ close(fd);
+ buffer_free(template);
+ return NULL;
+ }
+ fdevent_setfd_cloexec(fd);
+
+ c = chunkqueue_append_file_chunk(cq, template, 0, 0);
+ c->file.fd = fd;
+ c->file.is_temp = 1;
+
+ buffer_free(template);
+
+ return c;
+}
+
+static void chunkqueue_remove_empty_chunks(chunkqueue *cq);
+
+int chunkqueue_append_mem_to_tempfile(server *srv, chunkqueue *dest, const char *mem, size_t len) {
+ chunk *dst_c;
+ ssize_t written;
+
+ do {
+ /*
+ * if the last chunk is
+ * - smaller than dest->upload_temp_file_size
+ * - not read yet (offset == 0)
+ * -> append to it (so it might actually become larger than dest->upload_temp_file_size)
+ * otherwise
+ * -> create a new chunk
+ *
+ * */
+
+ dst_c = dest->last;
+ if (NULL != dst_c
+ && FILE_CHUNK == dst_c->type
+ && dst_c->file.is_temp
+ && dst_c->file.fd >= 0
+ && 0 == dst_c->offset) {
+ /* ok, take the last chunk for our job */
+
+ if (dst_c->file.length >= (off_t)dest->upload_temp_file_size) {
+ /* the chunk is too large now, close it */
+ int rc = close(dst_c->file.fd);
+ dst_c->file.fd = -1;
+ if (0 != rc) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "close() temp-file", dst_c->mem, "failed:",
+ strerror(errno));
+ return -1;
+ }
+ dst_c = NULL;
+ }
+ } else {
+ dst_c = NULL;
+ }
+
+ if (NULL == dst_c && NULL == (dst_c = chunkqueue_get_append_tempfile(srv, dest))) {
+ return -1;
+ }
+ #ifdef __COVERITY__
+ if (dst_c->file.fd < 0) return -1;
+ #endif
+
+ /* (dst_c->file.fd >= 0) */
+ /* coverity[negative_returns : FALSE] */
+ written = write(dst_c->file.fd, mem, len);
+
+ if ((size_t) written == len) {
+ dst_c->file.length += len;
+ dest->bytes_in += len;
+
+ return 0;
+ } else if (written >= 0) {
+ /*(assume EINTR if partial write and retry write();
+ * retry write() might fail with ENOSPC if no more space on volume)*/
+ dest->bytes_in += written;
+ mem += written;
+ len -= (size_t)written;
+ dst_c->file.length += (size_t)written;
+ /* continue; retry */
+ } else if (errno == EINTR) {
+ /* continue; retry */
+ } else {
+ int retry = (errno == ENOSPC && dest->tempdirs && ++dest->tempdir_idx < dest->tempdirs->used);
+ if (!retry) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "write() temp-file", dst_c->mem, "failed:",
+ strerror(errno));
+ }
+
+ if (0 == chunk_remaining_length(dst_c)) {
+ /*(remove empty chunk and unlink tempfile)*/
+ chunkqueue_remove_empty_chunks(dest);
+ } else {/*(close tempfile; avoid later attempts to append)*/
+ int rc = close(dst_c->file.fd);
+ dst_c->file.fd = -1;
+ if (0 != rc) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "close() temp-file", dst_c->mem, "failed:",
+ strerror(errno));
+ return -1;
+ }
+ }
+ if (!retry) break; /* return -1; */
+
+ /* continue; retry */
+ }
+
+ } while (dst_c);
+
+ return -1;
+}
+
+int chunkqueue_steal_with_tempfiles(server *srv, chunkqueue *dest, chunkqueue *src, off_t len) {
+ while (len > 0) {
+ chunk *c = src->first;
+ off_t clen = 0, use;
+
+ if (NULL == c) break;
+
+ clen = chunk_remaining_length(c);
+ if (0 == clen) {
+ /* drop empty chunk */
+ src->first = c->next;
+ if (c == src->last) src->last = NULL;
+ chunk_release(c);
+ continue;
+ }
+
+ use = (len >= clen) ? clen : len;
+ len -= use;
+
+ switch (c->type) {
+ case FILE_CHUNK:
+ if (use == clen) {
+ /* move complete chunk */
+ src->first = c->next;
+ if (c == src->last) src->last = NULL;
+ chunkqueue_append_chunk(dest, c);
+ dest->bytes_in += use;
+ } else {
+ /* partial chunk with length "use" */
+ /* tempfile flag is in "last" chunk after the split */
+ chunkqueue_append_file(dest, c->mem, c->file.start + c->offset, use);
+
+ c->offset += use;
+ force_assert(0 == len);
+ }
+ break;
+
+ case MEM_CHUNK:
+ /* store "use" bytes from memory chunk in tempfile */
+ if (0 != chunkqueue_append_mem_to_tempfile(srv, dest, c->mem->ptr + c->offset, use)) {
+ return -1;
+ }
+
+ if (use == clen) {
+ /* finished chunk */
+ src->first = c->next;
+ if (c == src->last) src->last = NULL;
+ chunk_release(c);
+ } else {
+ /* partial chunk */
+ c->offset += use;
+ force_assert(0 == len);
+ }
+ break;
+ }
+
+ src->bytes_out += use;
+ }
+
+ return 0;
+}
+
+off_t chunkqueue_length(chunkqueue *cq) {
+ off_t len = 0;
+ chunk *c;
+
+ for (c = cq->first; c; c = c->next) {
+ len += chunk_remaining_length(c);
+ }
+
+ return len;
+}
+
+void chunkqueue_mark_written(chunkqueue *cq, off_t len) {
+ off_t written = len;
+ chunk *c;
+ force_assert(len >= 0);
+
+ for (c = cq->first; NULL != c; c = cq->first) {
+ off_t c_len = chunk_remaining_length(c);
+
+ if (0 == written && 0 != c_len) break; /* no more finished chunks */
+
+ if (written >= c_len) { /* chunk got finished */
+ c->offset += c_len;
+ written -= c_len;
+
+ cq->first = c->next;
+ if (c == cq->last) cq->last = NULL;
+ chunk_release(c);
+ } else { /* partial chunk */
+ c->offset += written;
+ written = 0;
+ break; /* chunk not finished */
+ }
+ }
+
+ force_assert(0 == written);
+ cq->bytes_out += len;
+}
+
+void chunkqueue_remove_finished_chunks(chunkqueue *cq) {
+ chunk *c;
+
+ for (c = cq->first; c; c = cq->first) {
+ if (0 != chunk_remaining_length(c)) break; /* not finished yet */
+
+ cq->first = c->next;
+ if (c == cq->last) cq->last = NULL;
+ chunk_release(c);
+ }
+}
+
+static void chunkqueue_remove_empty_chunks(chunkqueue *cq) {
+ chunk *c;
+ chunkqueue_remove_finished_chunks(cq);
+ if (chunkqueue_is_empty(cq)) return;
+
+ for (c = cq->first; c && c->next; c = c->next) {
+ if (0 == chunk_remaining_length(c->next)) {
+ chunk *empty = c->next;
+ c->next = empty->next;
+ if (empty == cq->last) cq->last = c;
+ chunk_release(empty);
+ }
+ }
+}
+
+int chunkqueue_open_file_chunk(server *srv, chunkqueue *cq) {
+ chunk* const c = cq->first;
+ off_t offset, toSend;
+ struct stat st;
+
+ force_assert(NULL != c);
+ force_assert(FILE_CHUNK == c->type);
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+
+ if (-1 == c->file.fd) {
+ if (-1 == (c->file.fd = fdevent_open_cloexec(c->mem->ptr, O_RDONLY, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "open failed:", strerror(errno), c->mem);
+ return -1;
+ }
+ }
+
+ /*(skip file size checks if file is temp file created by lighttpd)*/
+ if (c->file.is_temp) return 0;
+
+ if (-1 == fstat(c->file.fd, &st)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fstat failed:", strerror(errno));
+ return -1;
+ }
+
+ if (offset > st.st_size || toSend > st.st_size || offset > st.st_size - toSend) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "file shrunk:", c->mem);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/chunk.h b/data/lighttpd/lighttpd-1.4.53/src/chunk.h
new file mode 100644
index 000000000..e31177ffc
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/chunk.h
@@ -0,0 +1,111 @@
+#ifndef _CHUNK_H_
+#define _CHUNK_H_
+#include "first.h"
+
+#ifdef _AIX /*(AIX might #define mmap mmap64)*/
+#include "sys-mmap.h"
+#endif
+
+#include "buffer.h"
+#include "array.h"
+
+typedef struct chunk {
+ struct chunk *next;
+ enum { MEM_CHUNK, FILE_CHUNK } type;
+
+ buffer *mem; /* either the storage of the mem-chunk or the name of the file */
+
+ /* the size of the chunk is either:
+ * - mem-chunk: buffer_string_length(chunk::mem)
+ * - file-chunk: chunk::file.length
+ */
+ off_t offset; /* octets sent from this chunk */
+
+ struct {
+ /* filechunk */
+ off_t start; /* starting offset in the file */
+ off_t length; /* octets to send from the starting offset */
+
+ int fd;
+ int is_temp; /* file is temporary and will be deleted if on cleanup */
+ struct {
+ char *start; /* the start pointer of the mmap'ed area */
+ size_t length; /* size of the mmap'ed area */
+ off_t offset; /* start is <n> octet away from the start of the file */
+ } mmap;
+ } file;
+} chunk;
+
+typedef struct {
+ chunk *first;
+ chunk *last;
+
+ off_t bytes_in, bytes_out;
+
+ array *tempdirs;
+ unsigned int upload_temp_file_size;
+ unsigned int tempdir_idx;
+} chunkqueue;
+
+buffer * chunk_buffer_acquire(void);
+void chunk_buffer_release(buffer *b);
+
+void chunkqueue_chunk_pool_clear(void);
+void chunkqueue_chunk_pool_free(void);
+
+chunkqueue *chunkqueue_init(void);
+void chunkqueue_set_chunk_size (size_t sz);
+void chunkqueue_set_tempdirs_default_reset (void);
+void chunkqueue_set_tempdirs_default (array *tempdirs, unsigned int upload_temp_file_size);
+void chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len); /* copies "fn" */
+void chunkqueue_append_file_fd(chunkqueue *cq, buffer *fn, int fd, off_t offset, off_t len); /* copies "fn" */
+void chunkqueue_append_mem(chunkqueue *cq, const char *mem, size_t len); /* copies memory */
+void chunkqueue_append_mem_min(chunkqueue *cq, const char * mem, size_t len); /* copies memory */
+void chunkqueue_append_buffer(chunkqueue *cq, buffer *mem); /* may reset "mem" */
+void chunkqueue_append_chunkqueue(chunkqueue *cq, chunkqueue *src);
+
+buffer * chunkqueue_prepend_buffer_open_sz(chunkqueue *cq, size_t sz);
+buffer * chunkqueue_prepend_buffer_open(chunkqueue *cq);
+void chunkqueue_prepend_buffer_commit(chunkqueue *cq);
+buffer * chunkqueue_append_buffer_open_sz(chunkqueue *cq, size_t sz);
+buffer * chunkqueue_append_buffer_open(chunkqueue *cq);
+void chunkqueue_append_buffer_commit(chunkqueue *cq);
+
+struct server; /*(declaration)*/
+int chunkqueue_append_mem_to_tempfile(struct server *srv, chunkqueue *cq, const char *mem, size_t len);
+
+/* functions to handle buffers to read into: */
+/* obtain/reserve memory in chunkqueue at least len (input) size,
+ * return pointer to memory with len (output) available for use
+ * modifying the chunkqueue invalidates the memory area.
+ * should always be followed by chunkqueue_get_memory(),
+ * even if nothing was read.
+ * pass 0 in len for mem at least half of chunk_buf_sz
+ */
+char * chunkqueue_get_memory(chunkqueue *cq, size_t *len);
+/* commit len bytes of mem obtained from chunkqueue_get_memory() */
+void chunkqueue_use_memory(chunkqueue *cq, size_t len);
+
+/* mark first "len" bytes as written (incrementing chunk offsets)
+ * and remove finished chunks
+ */
+void chunkqueue_mark_written(chunkqueue *cq, off_t len);
+
+void chunkqueue_remove_finished_chunks(chunkqueue *cq);
+
+void chunkqueue_steal(chunkqueue *dest, chunkqueue *src, off_t len);
+struct server;
+int chunkqueue_steal_with_tempfiles(struct server *srv, chunkqueue *dest, chunkqueue *src, off_t len);
+
+int chunkqueue_open_file_chunk(struct server *srv, chunkqueue *cq);
+
+off_t chunkqueue_length(chunkqueue *cq);
+void chunkqueue_free(chunkqueue *cq);
+void chunkqueue_reset(chunkqueue *cq);
+
+static inline int chunkqueue_is_empty(const chunkqueue *cq);
+static inline int chunkqueue_is_empty(const chunkqueue *cq) {
+ return NULL == cq->first;
+}
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/config.h.cmake b/data/lighttpd/lighttpd-1.4.53/src/config.h.cmake
new file mode 100644
index 000000000..4afc01035
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/config.h.cmake
@@ -0,0 +1,169 @@
+/*
+ CMake autogenerated config.h file. Do not edit!
+*/
+
+/* Package details */
+#define LIGHTTPD_VERSION_ID ${LIGHTTPD_VERSION_ID}
+#define PACKAGE_NAME "${PACKAGE_NAME}"
+#define PACKAGE_VERSION "${PACKAGE_VERSION}"
+#define LIBRARY_DIR "${LIGHTTPD_LIBRARY_DIR}"
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+/* System */
+#cmakedefine HAVE_SYS_DEVPOLL_H
+#cmakedefine HAVE_SYS_EPOLL_H
+#cmakedefine HAVE_SYS_EVENT_H
+#cmakedefine HAVE_SYS_MMAN_H
+#cmakedefine HAVE_SYS_POLL_H
+#cmakedefine HAVE_SYS_PORT_H
+#cmakedefine HAVE_SYS_PRCTL_H
+#cmakedefine HAVE_SYS_RESOURCE_H
+#cmakedefine HAVE_SYS_SENDFILE_H
+#cmakedefine HAVE_SYS_SELECT_H
+#cmakedefine HAVE_SYS_TYPES_H
+#cmakedefine HAVE_SYS_UIO_H
+#cmakedefine HAVE_SYS_UN_H
+#cmakedefine HAVE_SYS_WAIT_H
+#cmakedefine HAVE_SYS_TIME_H
+#cmakedefine HAVE_UNISTD_H
+#cmakedefine HAVE_PTHREAD_H
+#cmakedefine HAVE_IPV6
+#cmakedefine HAVE_WEAK_SYMBOLS
+
+/* XATTR */
+#cmakedefine HAVE_ATTR_ATTRIBUTES_H
+#cmakedefine HAVE_XATTR
+
+/* mySQL */
+#cmakedefine HAVE_MYSQL_H
+#cmakedefine HAVE_MYSQL
+
+/* OpenSSL */
+#cmakedefine HAVE_OPENSSL_SSL_H
+#cmakedefine HAVE_LIBCRYPTO
+#cmakedefine HAVE_LIBSSL
+
+/* BZip */
+#cmakedefine HAVE_BZLIB_H
+#cmakedefine HAVE_LIBBZ2
+
+/* FAM */
+#cmakedefine HAVE_FAM_H
+#cmakedefine HAVE_FAMNOEXISTS
+
+/* getopt */
+#cmakedefine HAVE_GETOPT_H
+
+#cmakedefine HAVE_INTTYPES_H
+
+/* LDAP */
+#cmakedefine HAVE_LDAP_H
+#cmakedefine HAVE_LIBLDAP
+#cmakedefine HAVE_LBER_H
+#cmakedefine HAVE_LIBLBER
+
+/* XML */
+#cmakedefine HAVE_LIBXML_H
+#cmakedefine HAVE_LIBXML
+
+/* PCRE */
+#cmakedefine HAVE_PCRE_H
+#cmakedefine HAVE_LIBPCRE
+
+#cmakedefine HAVE_POLL_H
+#cmakedefine HAVE_PWD_H
+
+/* sqlite3 */
+#cmakedefine HAVE_SQLITE3_H
+#cmakedefine HAVE_LIBPCRE
+
+#cmakedefine HAVE_STDDEF_H
+#cmakedefine HAVE_STDINT_H
+#cmakedefine HAVE_SYSLOG_H
+
+/* UUID */
+#cmakedefine HAVE_UUID_UUID_H
+#cmakedefine HAVE_LIBUUID
+
+/* ZLIB */
+#cmakedefine HAVE_ZLIB_H
+#cmakedefine HAVE_LIBZ
+
+/* lua */
+#cmakedefine HAVE_LUA_H
+#cmakedefine HAVE_LIBLUA
+
+/* gdbm */
+#cmakedefine HAVE_GDBM_H
+#cmakedefine HAVE_GDBM
+
+/* memcache */
+#cmakedefine USE_MEMCACHED
+
+/* inotify */
+#cmakedefine HAVE_INOTIFY_INIT
+#cmakedefine HAVE_SYS_INOTIFY_H
+
+/* Types */
+#cmakedefine HAVE_SOCKLEN_T
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T}
+
+/* Functions */
+#cmakedefine HAVE_CHROOT
+#cmakedefine HAVE_EPOLL_CTL
+#cmakedefine HAVE_FORK
+#cmakedefine HAVE_GETRLIMIT
+#cmakedefine HAVE_GETUID
+#cmakedefine HAVE_GMTIME_R
+#cmakedefine HAVE_INET_NTOP
+#cmakedefine HAVE_KQUEUE
+#cmakedefine HAVE_LOCALTIME_R
+#cmakedefine HAVE_LSTAT
+#cmakedefine HAVE_MADVISE
+#cmakedefine HAVE_MEMCPY
+#cmakedefine HAVE_MEMSET
+#cmakedefine HAVE_MMAP
+#cmakedefine HAVE_PATHCONF
+#cmakedefine HAVE_POLL
+#cmakedefine HAVE_PORT_CREATE
+#cmakedefine HAVE_PRCTL
+#cmakedefine HAVE_PREAD
+#cmakedefine HAVE_POSIX_FADVISE
+#cmakedefine HAVE_SELECT
+#cmakedefine HAVE_SENDFILE
+#cmakedefine HAVE_SEND_FILE
+#cmakedefine HAVE_SENDFILE64
+#cmakedefine HAVE_SENDFILEV
+#cmakedefine HAVE_SIGACTION
+#cmakedefine HAVE_SIGNAL
+#cmakedefine HAVE_SIGTIMEDWAIT
+#cmakedefine HAVE_STRPTIME
+#cmakedefine HAVE_SYSLOG
+#cmakedefine HAVE_WRITEV
+#cmakedefine HAVE_INET_ATON
+#cmakedefine HAVE_ISSETUGID
+#cmakedefine HAVE_INET_PTON
+#cmakedefine HAVE_MEMSET_S
+#cmakedefine HAVE_EXPLICIT_BZERO
+
+/* libcrypt */
+#cmakedefine HAVE_CRYPT_H
+#cmakedefine HAVE_LIBCRYPT
+#cmakedefine HAVE_CRYPT
+#cmakedefine HAVE_CRYPT_R
+
+/* fastcgi */
+#cmakedefine HAVE_FASTCGI_H
+#cmakedefine HAVE_FASTCGI_FASTCGI_H
+
+/* libev */
+#cmakedefine HAVE_LIBEV
+
+/* libunwind */
+#cmakedefine HAVE_LIBUNWIND
+
+#cmakedefine LIGHTTPD_STATIC
diff --git a/data/lighttpd/lighttpd-1.4.53/src/configfile-glue.c b/data/lighttpd/lighttpd-1.4.53/src/configfile-glue.c
new file mode 100644
index 000000000..94c8909ab
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/configfile-glue.c
@@ -0,0 +1,584 @@
+#include "first.h"
+
+#include "base.h"
+#include "buffer.h"
+#include "array.h"
+#include "log.h"
+#include "fdevent.h"
+#include "http_header.h"
+#include "sock_addr.h"
+
+#include "configfile.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+/**
+ * like all glue code this file contains functions which
+ * are the external interface of lighttpd. The functions
+ * are used by the server itself and the plugins.
+ *
+ * The main-goal is to have a small library in the end
+ * which is linked against both and which will define
+ * the interface itself in the end.
+ *
+ */
+
+
+/* handle global options */
+
+/* parse config array */
+int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
+ size_t i;
+ data_unset *du;
+
+ for (i = 0; cv[i].key; i++) {
+
+ if (NULL == (du = array_get_element_klen(ca, cv[i].key, strlen(cv[i].key)))) {
+ /* no found */
+
+ continue;
+ }
+
+ if ((T_CONFIG_SCOPE_SERVER == cv[i].scope)
+ && (T_CONFIG_SCOPE_SERVER != scope)) {
+ /* server scope options should only be set in server scope, not in conditionals */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "DEPRECATED: don't set server options in conditionals, variable:",
+ cv[i].key);
+ }
+
+ switch (cv[i].type) {
+ case T_CONFIG_ARRAY:
+ if (du->type == TYPE_ARRAY) {
+ size_t j;
+ data_array *da = (data_array *)du;
+
+ for (j = 0; j < da->value->used; j++) {
+ data_unset *ds = da->value->data[j];
+ if (ds->type == TYPE_STRING || ds->type == TYPE_INTEGER || ds->type == TYPE_ARRAY) {
+ array_insert_unique(cv[i].destination, ds->fn->copy(ds));
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sssbsd",
+ "the value of an array can only be a string, variable:",
+ cv[i].key, "[", ds->key, "], type:", ds->type);
+
+ return -1;
+ }
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
+
+ return -1;
+ }
+ break;
+ case T_CONFIG_STRING:
+ if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+
+ buffer_copy_buffer(cv[i].destination, ds->value);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a string like ... = \"...\"");
+
+ return -1;
+ }
+ break;
+ case T_CONFIG_SHORT:
+ switch(du->type) {
+ case TYPE_INTEGER: {
+ data_integer *di = (data_integer *)du;
+
+ *((unsigned short *)(cv[i].destination)) = di->value;
+ break;
+ }
+ case TYPE_STRING: {
+ data_string *ds = (data_string *)du;
+
+ /* If the value came from an environment variable, then it is a
+ * data_string, although it may contain a number in ASCII
+ * decimal format. We try to interpret the string as a decimal
+ * short before giving up, in order to support setting numeric
+ * values with environment variables (eg, port number).
+ */
+ if (ds->value->ptr && *ds->value->ptr) {
+ char *e;
+ long l = strtol(ds->value->ptr, &e, 10);
+ if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
+ *((unsigned short *)(cv[i].destination)) = l;
+ break;
+ }
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
+
+ return -1;
+ }
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
+ return -1;
+ }
+ break;
+ case T_CONFIG_INT:
+ switch(du->type) {
+ case TYPE_INTEGER: {
+ data_integer *di = (data_integer *)du;
+
+ *((unsigned int *)(cv[i].destination)) = di->value;
+ break;
+ }
+ case TYPE_STRING: {
+ data_string *ds = (data_string *)du;
+
+ if (ds->value->ptr && *ds->value->ptr) {
+ char *e;
+ long l = strtol(ds->value->ptr, &e, 10);
+ if (e != ds->value->ptr && !*e && l >= 0) {
+ *((unsigned int *)(cv[i].destination)) = l;
+ break;
+ }
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
+
+ return -1;
+ }
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
+ return -1;
+ }
+ break;
+ case T_CONFIG_BOOLEAN:
+ if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
+ *((unsigned short *)(cv[i].destination)) = 1;
+ } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
+ *((unsigned short *)(cv[i].destination)) = 0;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
+
+ return -1;
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
+
+ return -1;
+ }
+ break;
+ case T_CONFIG_LOCAL:
+ case T_CONFIG_UNSET:
+ break;
+ case T_CONFIG_UNSUPPORTED:
+ log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
+
+ srv->config_unsupported = 1;
+
+ break;
+ case T_CONFIG_DEPRECATED:
+ log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
+
+ srv->config_deprecated = 1;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
+ size_t i;
+ data_unset *du;
+
+ for (i = 0; cv[i].key; i++) {
+ if (NULL == (du = array_get_element_klen(ca, cv[i].key, strlen(cv[i].key)))) {
+ /* no found */
+
+ continue;
+ }
+ array_set_key_value(srv->config_touched, CONST_BUF_LEN(du->key), CONST_STR_LEN(""));
+ }
+
+ return config_insert_values_internal(srv, ca, cv, scope);
+}
+
+static const char* cond_result_to_string(cond_result_t cond_result) {
+ switch (cond_result) {
+ case COND_RESULT_UNSET: return "unset";
+ case COND_RESULT_SKIP: return "skipped";
+ case COND_RESULT_FALSE: return "false";
+ case COND_RESULT_TRUE: return "true";
+ default: return "invalid cond_result_t";
+ }
+}
+
+static int config_addrstr_eq_remote_ip_mask(server *srv, const char *addrstr, int nm_bits, sock_addr *rmt) {
+ /* special-case 0 == nm_bits to mean "all bits of the address" in addrstr */
+ sock_addr addr;
+ if (1 == sock_addr_inet_pton(&addr, addrstr, AF_INET, 0)) {
+ if (nm_bits > 32) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv4 netmask too large:", nm_bits);
+ return -1;
+ }
+ } else if (1 == sock_addr_inet_pton(&addr, addrstr, AF_INET6, 0)) {
+ if (nm_bits > 128) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv6 netmask too large:", nm_bits);
+ return -1;
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ERROR: ip addr is invalid:", addrstr);
+ return -1;
+ }
+ return sock_addr_is_addr_eq_bits(&addr, rmt, nm_bits);
+}
+
+static int config_addrbuf_eq_remote_ip_mask(server *srv, buffer *string, char *nm_slash, sock_addr *rmt) {
+ char *err;
+ int nm_bits = strtol(nm_slash + 1, &err, 10);
+ size_t addrstrlen = (size_t)(nm_slash - string->ptr);
+ char addrstr[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
+
+ if (*err) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", string, err);
+ return -1;
+ }
+
+ if (nm_bits <= 0) {
+ if (*(nm_slash+1) == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", string);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask <= 0:", string, err);
+ }
+ return -1;
+ }
+
+ if (addrstrlen >= sizeof(addrstr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: address string too long:", string);
+ return -1;
+ }
+
+ memcpy(addrstr, string->ptr, addrstrlen);
+ addrstr[addrstrlen] = '\0';
+
+ return config_addrstr_eq_remote_ip_mask(srv, addrstr, nm_bits, rmt);
+}
+
+static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
+
+static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
+ buffer *l;
+ server_socket *srv_sock = con->srv_socket;
+ cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
+
+ /* check parent first */
+ if (dc->parent && dc->parent->context_ndx) {
+ /**
+ * a nested conditional
+ *
+ * if the parent is not decided yet or false, we can't be true either
+ */
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
+ }
+
+ switch (config_check_cond_cached(srv, con, dc->parent)) {
+ case COND_RESULT_UNSET:
+ /* decide later */
+ return COND_RESULT_UNSET;
+ case COND_RESULT_SKIP:
+ case COND_RESULT_FALSE:
+ /* failed precondition */
+ return COND_RESULT_SKIP;
+ case COND_RESULT_TRUE:
+ /* proceed */
+ break;
+ }
+ }
+
+ if (dc->prev) {
+ /**
+ * a else branch; can only be executed if the previous branch
+ * was evaluated as "false" (not unset/skipped/true)
+ */
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
+ }
+
+ /* make sure prev is checked first */
+ switch (config_check_cond_cached(srv, con, dc->prev)) {
+ case COND_RESULT_UNSET:
+ /* decide later */
+ return COND_RESULT_UNSET;
+ case COND_RESULT_SKIP:
+ case COND_RESULT_TRUE:
+ /* failed precondition */
+ return COND_RESULT_SKIP;
+ case COND_RESULT_FALSE:
+ /* proceed */
+ break;
+ }
+ }
+
+ if (!con->conditional_is_valid[dc->comp]) {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "dss",
+ dc->comp,
+ dc->key->ptr,
+ "not available yet");
+ }
+
+ return COND_RESULT_UNSET;
+ }
+
+ /* if we had a real result before and weren't cleared just return it */
+ switch (cache->local_result) {
+ case COND_RESULT_TRUE:
+ case COND_RESULT_FALSE:
+ return cache->local_result;
+ default:
+ break;
+ }
+
+ if (CONFIG_COND_ELSE == dc->cond) return COND_RESULT_TRUE;
+
+ /* pass the rules */
+
+ switch (dc->comp) {
+ case COMP_HTTP_HOST: {
+ char *ck_colon = NULL, *val_colon = NULL;
+ unsigned short port;
+
+ if (!buffer_string_is_empty(con->uri.authority)) {
+
+ /*
+ * append server-port to the HTTP_POST if necessary
+ */
+
+ l = con->uri.authority;
+
+ switch(dc->cond) {
+ case CONFIG_COND_NE:
+ case CONFIG_COND_EQ:
+ port = sock_addr_get_port(&srv_sock->addr);
+ if (0 == port) break;
+ ck_colon = strchr(dc->string->ptr, ':');
+ val_colon = strchr(l->ptr, ':');
+
+ if (NULL != ck_colon && NULL == val_colon) {
+ /* condition "host:port" but client send "host" */
+ buffer_copy_buffer(srv->cond_check_buf, l);
+ buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
+ buffer_append_int(srv->cond_check_buf, port);
+ l = srv->cond_check_buf;
+ } else if (NULL != val_colon && NULL == ck_colon) {
+ /* condition "host" but client send "host:port" */
+ buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
+ l = srv->cond_check_buf;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ l = srv->empty_string;
+ }
+ break;
+ }
+ case COMP_HTTP_REMOTE_IP: {
+ char *nm_slash;
+ /* handle remoteip limitations
+ *
+ * "10.0.0.1" is provided for all comparisions
+ *
+ * only for == and != we support
+ *
+ * "10.0.0.1/24"
+ */
+
+ if ((dc->cond == CONFIG_COND_EQ ||
+ dc->cond == CONFIG_COND_NE) &&
+ (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
+ switch (config_addrbuf_eq_remote_ip_mask(srv, dc->string, nm_slash, &con->dst_addr)) {
+ case 1: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
+ case 0: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
+ case -1: return COND_RESULT_FALSE; /*(error parsing configfile entry)*/
+ }
+ }
+ l = con->dst_addr_buf;
+ break;
+ }
+ case COMP_HTTP_SCHEME:
+ l = con->uri.scheme;
+ break;
+
+ case COMP_HTTP_URL:
+ l = con->uri.path;
+ break;
+
+ case COMP_HTTP_QUERY_STRING:
+ l = con->uri.query;
+ break;
+
+ case COMP_SERVER_SOCKET:
+ l = srv_sock->srv_token;
+ break;
+
+ case COMP_HTTP_REQUEST_HEADER:
+ l = http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(dc->comp_tag));
+ if (NULL == l) l = srv->empty_string;
+ break;
+ case COMP_HTTP_REQUEST_METHOD:
+ l = srv->tmp_buf;
+ buffer_clear(l);
+ http_method_append(l, con->request.http_method);
+ break;
+ default:
+ return COND_RESULT_FALSE;
+ }
+
+ if (NULL == l) {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
+ "(", l, ") compare to NULL");
+ }
+ return COND_RESULT_FALSE;
+ }
+
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
+ "(", l, ") compare to ", dc->string);
+ }
+ switch(dc->cond) {
+ case CONFIG_COND_NE:
+ case CONFIG_COND_EQ:
+ if (buffer_is_equal(l, dc->string)) {
+ return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
+ } else {
+ return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
+ }
+ case CONFIG_COND_NOMATCH:
+ case CONFIG_COND_MATCH: {
+ if (data_config_pcre_exec(dc, cache, l) > 0) {
+ return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
+ } else {
+ /* cache is already cleared */
+ return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
+ }
+ }
+ default:
+ /* no way */
+ break;
+ }
+
+ return COND_RESULT_FALSE;
+}
+
+static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
+ cond_cache_t *caches = con->cond_cache;
+
+ if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
+ caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc);
+ switch (caches[dc->context_ndx].result) {
+ case COND_RESULT_FALSE:
+ case COND_RESULT_TRUE:
+ /* remember result of local condition for a partial reset */
+ caches[dc->context_ndx].local_result = caches[dc->context_ndx].result;
+ break;
+ default:
+ break;
+ }
+
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "dss",
+ dc->context_ndx,
+ "(uncached) result:",
+ cond_result_to_string(caches[dc->context_ndx].result));
+ }
+ } else {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "dss",
+ dc->context_ndx,
+ "(cached) result:",
+ cond_result_to_string(caches[dc->context_ndx].result));
+ }
+ }
+ return caches[dc->context_ndx].result;
+}
+
+/* if we reset the cache result for a node, we also need to clear all
+ * child nodes and else-branches*/
+static void config_cond_clear_node(server *srv, connection *con, data_config *dc) {
+ /* if a node is "unset" all children are unset too */
+ if (con->cond_cache[dc->context_ndx].result != COND_RESULT_UNSET) {
+ size_t i;
+
+ #if 0
+ /* (redundant; matches not relevant unless COND_RESULT_TRUE) */
+ switch (con->cond_cache[dc->context_ndx].local_result) {
+ case COND_RESULT_TRUE:
+ case COND_RESULT_FALSE:
+ break;
+ default:
+ con->cond_cache[dc->context_ndx].patterncount = 0;
+ con->cond_cache[dc->context_ndx].comp_value = NULL;
+ }
+ #endif
+ con->cond_cache[dc->context_ndx].result = COND_RESULT_UNSET;
+
+ for (i = 0; i < dc->children.used; ++i) {
+ data_config *dc_child = dc->children.data[i];
+ if (NULL == dc_child->prev) {
+ /* only call for first node in if-else chain */
+ config_cond_clear_node(srv, con, dc_child);
+ }
+ }
+ if (NULL != dc->next) config_cond_clear_node(srv, con, dc->next);
+ }
+}
+
+/**
+ * reset the config-cache for a named item
+ *
+ * if the item is COND_LAST_ELEMENT we reset all items
+ */
+void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+
+ if (item == dc->comp) {
+ /* clear local_result */
+ con->cond_cache[i].local_result = COND_RESULT_UNSET;
+ /* clear result in subtree (including the node itself) */
+ config_cond_clear_node(srv, con, dc);
+ }
+ }
+}
+
+/**
+ * reset the config cache to its initial state at connection start
+ */
+void config_cond_cache_reset(server *srv, connection *con) {
+ size_t i;
+
+ /* resetting all entries; no need to follow children as in config_cond_cache_reset_item */
+ for (i = 0; i < srv->config_context->used; i++) {
+ con->cond_cache[i].result = COND_RESULT_UNSET;
+ con->cond_cache[i].local_result = COND_RESULT_UNSET;
+ con->cond_cache[i].patterncount = 0;
+ con->cond_cache[i].comp_value = NULL;
+ }
+
+ for (i = 0; i < COMP_LAST_ELEMENT; i++) {
+ con->conditional_is_valid[i] = 0;
+ }
+}
+
+int config_check_cond(server *srv, connection *con, data_config *dc) {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
+ }
+ return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/configfile.c b/data/lighttpd/lighttpd-1.4.53/src/configfile.c
new file mode 100644
index 000000000..b359dcbeb
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/configfile.c
@@ -0,0 +1,1665 @@
+#include "first.h"
+
+#include "base.h"
+#include "burl.h"
+#include "fdevent.h"
+#include "keyvalue.h"
+#include "log.h"
+#include "stream.h"
+
+#include "configparser.h"
+#include "configfile.h"
+#include "stat_cache.h"
+#include "sys-crypto.h"
+
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <glob.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#if defined(HAVE_MYSQL) || (defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER))
+static void config_warn_authn_module (server *srv, const char *module, size_t len) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ const data_config *config = (data_config const*)srv->config_context->data[i];
+ const data_unset *du = array_get_element(config->value, "auth.backend");
+ if (NULL != du && du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+ if (buffer_is_equal_string(ds->value, module, len)) {
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("mod_authn_"));
+ buffer_append_string_len(srv->tmp_buf, module, len);
+ array_insert_value(srv->srvconf.modules, CONST_BUF_LEN(srv->tmp_buf));
+ log_error_write(srv, __FILE__, __LINE__, "SSSsSSS", "Warning: please add \"mod_authn_", module, "\" to server.modules list in lighttpd.conf. A future release of lighttpd 1.4.x will not automatically load mod_authn_", module, "and lighttpd will fail to start up since your lighttpd.conf uses auth.backend = \"", module, "\".");
+ return;
+ }
+ }
+ }
+}
+#endif
+
+#ifdef USE_OPENSSL_CRYPTO
+static void config_warn_openssl_module (server *srv) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ const data_config *config = (data_config const*)srv->config_context->data[i];
+ for (size_t j = 0; j < config->value->used; ++j) {
+ data_unset *du = config->value->data[j];
+ if (0 == strncmp(du->key->ptr, "ssl.", sizeof("ssl.")-1)) {
+ /* mod_openssl should be loaded after mod_extforward */
+ array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_openssl"));
+ log_error_write(srv, __FILE__, __LINE__, "S", "Warning: please add \"mod_openssl\" to server.modules list in lighttpd.conf. A future release of lighttpd 1.4.x *will not* automatically load mod_openssl and lighttpd *will not* use SSL/TLS where your lighttpd.conf contains ssl.* directives");
+ return;
+ }
+ }
+ }
+}
+#endif
+
+static int config_http_parseopts (server *srv, array *a) {
+ unsigned short int opts = srv->srvconf.http_url_normalize;
+ unsigned short int decode_2f = 1;
+ int rc = 1;
+ if (!array_is_kvstring(a)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for server.http-parseopts; "
+ "expected list of \"key\" => \"[enable|disable]\"");
+ return 0;
+ }
+ for (size_t i = 0; i < a->used; ++i) {
+ const data_string * const ds = (data_string *)a->data[i];
+ unsigned short int opt;
+ int val = 0;
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable")))
+ val = 1;
+ else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable")))
+ val = 0;
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs",
+ "unrecognized value for server.http-parseopts:",
+ ds->key, "=>", ds->value,
+ "(expect \"[enable|disable]\")");
+ rc = 0;
+ }
+ if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-normalize")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-normalize-unreserved")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-normalize-required")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-ctrls-reject")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-path-backslash-trans")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-path-2f-decode")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-path-2f-reject")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-path-dotseg-remove")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-path-dotseg-reject")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("url-query-20-plus")))
+ opt = HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS;
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("header-strict"))) {
+ srv->srvconf.http_header_strict = val;
+ continue;
+ }
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("host-strict"))) {
+ srv->srvconf.http_host_strict = val;
+ continue;
+ }
+ else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("host-normalize"))) {
+ srv->srvconf.http_host_normalize = val;
+ continue;
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "unrecognized key for server.http-parseopts:",
+ ds->key);
+ rc = 0;
+ continue;
+ }
+ if (val)
+ opts |= opt;
+ else {
+ opts &= ~opt;
+ if (opt == HTTP_PARSEOPT_URL_NORMALIZE) {
+ opts = 0;
+ break;
+ }
+ if (opt == HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE) {
+ decode_2f = 0;
+ }
+ }
+ }
+ if (opts != 0) {
+ opts |= HTTP_PARSEOPT_URL_NORMALIZE;
+ if ((opts & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
+ |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT))
+ == (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
+ |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "conflicting options in server.http-parseopts:"
+ "url-path-2f-decode, url-path-2f-reject");
+ rc = 0;
+ }
+ if ((opts & (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE
+ |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT))
+ == (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE
+ |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "conflicting options in server.http-parseopts:"
+ "url-path-dotseg-remove, url-path-dotseg-reject");
+ rc = 0;
+ }
+ if (!(opts & (HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED
+ |HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED))) {
+ opts |= HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED;
+ if (decode_2f
+ && !(opts & HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT))
+ opts |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE;
+ }
+ }
+ srv->srvconf.http_url_normalize = opts;
+ return rc;
+}
+
+static int config_insert(server *srv) {
+ size_t i;
+ int ret = 0;
+ buffer *stat_cache_string;
+ array *http_parseopts;
+ unsigned int chunk_sz = 0;
+
+ config_values_t cv[] = {
+ { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
+ { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
+ { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "server.chroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 3 */
+ { "server.username", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 4 */
+ { "server.groupname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 5 */
+ { "server.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 6 */
+ { "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */
+
+ { "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */
+ { "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */
+ { "server.max-request-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { "server.max-worker", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 13 */
+ { "server.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
+ { "server.force-lowercase-filenames", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
+ { "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
+ { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
+ { "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
+ { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
+
+ { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
+ { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
+ { "server.error-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
+ { "server.max-fds", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 23 */
+#ifdef HAVE_LSTAT
+ { "server.follow-symlink", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
+#else
+ { "server.follow-symlink",
+ "Your system lacks lstat(). We can not differ symlinks from files."
+ "Please remove server.follow-symlinks from your config.",
+ T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET },
+#endif
+ { "server.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 25 */
+ { "connection.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 26 */
+ { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
+ { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 29 */
+
+ { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 30 */
+ { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 31 */
+ { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 32 */
+ { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 33 */
+ { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 34 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 35 */
+ { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 36 */
+ { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
+ { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 38 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 39 */
+
+ { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 40 */
+ { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
+ { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 42 */
+ { "server.max-connections", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 43 */
+ { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 44 */
+ { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 45 */
+ { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 46 */
+ { "server.compat-module-load", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 47 */
+ { "server.chunkqueue-chunk-sz", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_SERVER }, /* 48 */
+ { "etag.use-inode", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 49 */
+
+ { "etag.use-mtime", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 50 */
+ { "etag.use-size", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 51 */
+ { "server.reject-expect-100-with-417", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 52 */
+ { "debug.log-timeouts", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 53 */
+ { "server.defer-accept", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 54 */
+ { "server.breakagelog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 55 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 56 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 57 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 58 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 59 */
+
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 60 */
+ { "server.set-v6only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 61 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 62 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 63 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 64 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 65 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 66 */
+ { "unused-slot-moved-to-mod-openssl", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 67 */
+ { "server.upload-temp-file-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_SERVER }, /* 68 */
+ { "mimetype.xattr-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 69 */
+ { "server.listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 70 */
+ { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 71 */
+ { "server.http-parseopt-header-strict",NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 72 */
+ { "server.http-parseopt-host-strict", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 73 */
+ { "server.http-parseopt-host-normalize",NULL,T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 74 */
+ { "server.bsd-accept-filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 75 */
+ { "server.stream-request-body", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 76 */
+ { "server.stream-response-body", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 77 */
+ { "server.max-request-field-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_SERVER }, /* 78 */
+ { "server.error-intercept", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 79 */
+ { "server.syslog-facility", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 80 */
+ { "server.socket-perms", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 81 */
+ { "server.http-parseopts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 82 */
+ { "server.systemd-socket-activation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 83 */
+
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ /* all T_CONFIG_SCOPE_SERVER options */
+ cv[0].destination = srv->srvconf.bindhost;
+ cv[1].destination = srv->srvconf.errorlog_file;
+ cv[3].destination = srv->srvconf.changeroot;
+ cv[4].destination = srv->srvconf.username;
+ cv[5].destination = srv->srvconf.groupname;
+ cv[6].destination = &(srv->srvconf.port);
+ cv[9].destination = srv->srvconf.modules;
+
+ cv[10].destination = srv->srvconf.event_handler;
+ cv[11].destination = srv->srvconf.pid_file;
+ cv[13].destination = &(srv->srvconf.max_worker);
+
+ cv[23].destination = &(srv->srvconf.max_fds);
+
+ cv[37].destination = &(srv->srvconf.log_request_header_on_error);
+ cv[38].destination = &(srv->srvconf.log_state_handling);
+
+ cv[40].destination = &(srv->srvconf.errorlog_use_syslog);
+ stat_cache_string = buffer_init();
+ cv[42].destination = stat_cache_string;
+ cv[43].destination = &(srv->srvconf.max_conns);
+ cv[44].destination = srv->srvconf.network_backend;
+ cv[45].destination = srv->srvconf.upload_tempdirs;
+ cv[46].destination = &(srv->srvconf.enable_cores);
+ cv[47].destination = &(srv->srvconf.compat_module_load);
+ cv[48].destination = &chunk_sz;
+
+ cv[52].destination = &(srv->srvconf.reject_expect_100_with_417);
+ cv[55].destination = srv->srvconf.breakagelog_file;
+
+ cv[68].destination = &(srv->srvconf.upload_temp_file_size);
+ cv[69].destination = srv->srvconf.xattr_name;
+ cv[72].destination = &(srv->srvconf.http_header_strict);
+ cv[73].destination = &(srv->srvconf.http_host_strict);
+ cv[74].destination = &(srv->srvconf.http_host_normalize);
+ cv[78].destination = &(srv->srvconf.max_request_field_size);
+ cv[80].destination = srv->srvconf.syslog_facility;
+ http_parseopts = array_init();
+ cv[82].destination = http_parseopts;
+ cv[83].destination = &(srv->srvconf.systemd_socket_activation);
+
+ srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ force_assert(srv->config_storage);
+ force_assert(srv->config_context->used); /* static analysis hint for ccc
+-analyzer */
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config * const config = (data_config *)srv->config_context->data[i];
+ specific_config *s;
+
+ s = calloc(1, sizeof(specific_config));
+ force_assert(s);
+ s->document_root = buffer_init();
+ s->mimetypes = array_init();
+ s->server_name = buffer_init();
+ s->error_handler = buffer_init();
+ s->error_handler_404 = buffer_init();
+ s->server_tag = buffer_init();
+ s->errorfile_prefix = buffer_init();
+ #if defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__DragonFly__)
+ s->bsd_accept_filter = (i == 0)
+ ? buffer_init()
+ : buffer_init_buffer(srv->config_storage[0]->bsd_accept_filter);
+ #endif
+ s->socket_perms = (i == 0 || buffer_string_is_empty(srv->config_storage[0]->socket_perms))
+ ? buffer_init()
+ : buffer_init_buffer(srv->config_storage[0]->socket_perms);
+ s->max_keep_alive_requests = 100;
+ s->max_keep_alive_idle = 5;
+ s->max_read_idle = 60;
+ s->max_write_idle = 360;
+ s->max_request_size = 0;
+ s->use_xattr = 0;
+ s->ssl_enabled = 0;
+ s->use_ipv6 = (i == 0) ? 0 : srv->config_storage[0]->use_ipv6;
+ s->set_v6only = (i == 0) ? 1 : srv->config_storage[0]->set_v6only;
+ s->defer_accept = (i == 0) ? 0 : srv->config_storage[0]->defer_accept;
+#ifdef HAVE_LSTAT
+ s->follow_symlink = 1;
+#endif
+ s->kbytes_per_second = 0;
+ s->allow_http11 = 1;
+ s->etag_use_inode = 1;
+ s->etag_use_mtime = 1;
+ s->etag_use_size = 1;
+ s->range_requests = 1;
+ s->force_lowercase_filenames = (i == 0) ? 2 : 0; /* we wan't to detect later if user changed this for global section */
+ s->global_kbytes_per_second = 0;
+ s->global_bytes_per_second_cnt = 0;
+ s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
+ s->listen_backlog = (0 == i ? 1024 : srv->config_storage[0]->listen_backlog);
+ s->stream_request_body = 0;
+ s->stream_response_body = 0;
+ s->error_intercept = 0;
+
+ /* all T_CONFIG_SCOPE_CONNECTION options */
+ cv[2].destination = s->errorfile_prefix;
+ cv[7].destination = s->server_tag;
+ cv[8].destination = &(s->use_ipv6);
+
+ cv[12].destination = &(s->max_request_size);
+ cv[14].destination = s->document_root;
+ cv[15].destination = &(s->force_lowercase_filenames);
+ cv[16].destination = &(s->log_condition_handling);
+ cv[17].destination = &(s->max_keep_alive_requests);
+ cv[18].destination = s->server_name;
+ cv[19].destination = &(s->max_keep_alive_idle);
+
+ cv[20].destination = &(s->max_read_idle);
+ cv[21].destination = &(s->max_write_idle);
+ cv[22].destination = s->error_handler;
+#ifdef HAVE_LSTAT
+ cv[24].destination = &(s->follow_symlink);
+#endif
+ cv[25].destination = &(s->global_kbytes_per_second);
+ cv[26].destination = &(s->kbytes_per_second);
+ cv[27].destination = &(s->use_xattr);
+ cv[28].destination = s->mimetypes;
+ /*cv[29].destination = s->unused;*/
+
+ cv[30].destination = &(s->ssl_enabled);
+ cv[31].destination = &(s->log_file_not_found);
+ cv[32].destination = &(s->log_request_handling);
+ cv[33].destination = &(s->log_response_header);
+ cv[34].destination = &(s->log_request_header);
+ /*cv[35].destination = &(s->unused);*/
+ cv[36].destination = &(s->allow_http11);
+ /*cv[39].destination = s->unused;*/
+
+ cv[41].destination = &(s->range_requests);
+ /*cv[47].destination = s->unused;*/
+ /*cv[48].destination = &(s->unused);*/
+ cv[49].destination = &(s->etag_use_inode);
+
+ cv[50].destination = &(s->etag_use_mtime);
+ cv[51].destination = &(s->etag_use_size);
+ cv[53].destination = &(s->log_timeouts);
+ cv[54].destination = &(s->defer_accept);
+ /*cv[56].destination = &(s->unused);*/
+ /*cv[57].destination = &(s->unused);*/
+ /*cv[58].destination = &(s->unused);*/
+ /*cv[59].destination = s->unused;*/
+
+ /*cv[60].destination = &(s->unused);*/
+ cv[61].destination = &(s->set_v6only);
+ /*cv[62].destination = &(s->unused);*/
+ /*cv[63].destination = s->unused;*/
+ /*cv[64].destination = s->unused;*/
+ /*cv[65].destination = &(s->unused);*/
+ /*cv[66].destination = &(s->unused);*/
+ /*cv[67].destination = &(s->unused);*/
+ cv[70].destination = &(s->listen_backlog);
+ cv[71].destination = s->error_handler_404;
+ #if defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__DragonFly__)
+ cv[75].destination = s->bsd_accept_filter;
+ #endif
+ cv[76].destination = &(s->stream_request_body);
+ cv[77].destination = &(s->stream_response_body);
+ cv[79].destination = &(s->error_intercept);
+ cv[81].destination = s->socket_perms;
+
+ srv->config_storage[i] = s;
+
+ if (0 != (ret = config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION))) {
+ break;
+ }
+
+ if (s->stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN) {
+ s->stream_request_body |= FDEVENT_STREAM_REQUEST;
+ }
+ if (s->stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) {
+ s->stream_response_body |= FDEVENT_STREAM_RESPONSE;
+ }
+
+ if (!array_is_kvstring(s->mimetypes)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for mimetype.assign; expected list of \"ext\" => \"mimetype\"");
+ }
+
+ if (!buffer_string_is_empty(s->server_tag)) {
+ for (char *t = strchr(s->server_tag->ptr,'\n'); NULL != t; t = strchr(t+2,'\n')) {
+ /* not expecting admin to define multi-line server.tag,
+ * but ensure server_tag has proper header continuation,
+ * if needed */
+ off_t off = t - s->server_tag->ptr;
+ size_t len;
+ if (t[1] == ' ' || t[1] == '\t') continue;
+ len = buffer_string_length(s->server_tag);
+ buffer_string_prepare_append(s->server_tag, 1);
+ t = s->server_tag->ptr+off;
+ memmove(t+2, t+1, len - off - 1);
+ t[1] = ' ';
+ buffer_commit(s->server_tag, 1);
+ }
+ }
+
+ if (0 == i) {
+ if (!config_http_parseopts(srv, http_parseopts)) {
+ ret = HANDLER_ERROR;
+ break;
+ }
+ }
+
+ if (srv->srvconf.http_url_normalize
+ && COMP_HTTP_QUERY_STRING == config->comp) {
+ switch(config->cond) {
+ case CONFIG_COND_NE:
+ case CONFIG_COND_EQ:
+ /* (can use this routine as long as it does not perform
+ * any regex-specific normalization of first arg) */
+ pcre_keyvalue_burl_normalize_key(config->string, srv->tmp_buf);
+ break;
+ case CONFIG_COND_NOMATCH:
+ case CONFIG_COND_MATCH:
+ pcre_keyvalue_burl_normalize_key(config->string, srv->tmp_buf);
+ if (!data_config_pcre_compile(config)) {
+ ret = HANDLER_ERROR;
+ }
+ break;
+ default:
+ break;
+ }
+ if (HANDLER_ERROR == ret) break;
+ }
+
+ #ifndef USE_OPENSSL_CRYPTO
+ if (s->ssl_enabled) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ssl support is missing, recompile with e.g. --with-openssl");
+ ret = HANDLER_ERROR;
+ break;
+ }
+ #endif
+ }
+ array_free(http_parseopts);
+
+ {
+ specific_config *s = srv->config_storage[0];
+ s->http_parseopts= /*(global, but stored in con->conf.http_parseopts)*/
+ (srv->srvconf.http_header_strict ?(HTTP_PARSEOPT_HEADER_STRICT) :0)
+ |(srv->srvconf.http_host_strict ?(HTTP_PARSEOPT_HOST_STRICT
+ |HTTP_PARSEOPT_HOST_NORMALIZE):0)
+ |(srv->srvconf.http_host_normalize ?(HTTP_PARSEOPT_HOST_NORMALIZE):0);
+ s->http_parseopts |= srv->srvconf.http_url_normalize;
+
+ if (s->log_request_handling || s->log_request_header)
+ srv->srvconf.log_request_header_on_error = 1;
+ }
+
+ if (0 != chunk_sz) {
+ chunkqueue_set_chunk_size(chunk_sz);
+ }
+
+ if (0 != stat_cache_choose_engine(srv, stat_cache_string)) {
+ ret = HANDLER_ERROR;
+ }
+ buffer_free(stat_cache_string);
+
+ if (!array_is_vlist(srv->srvconf.upload_tempdirs)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for server.upload-dirs; expected list of \"path\" strings");
+ ret = HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(srv->srvconf.modules)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for server.modules; expected list of \"mod_xxxxxx\" strings");
+ ret = HANDLER_ERROR;
+ } else if (srv->srvconf.compat_module_load) {
+ data_string *ds;
+ int prepend_mod_indexfile = 1;
+ int append_mod_dirlisting = 1;
+ int append_mod_staticfile = 1;
+ int append_mod_authn_file = 1;
+ int append_mod_authn_ldap = 1;
+ int append_mod_authn_mysql = 1;
+ int append_mod_openssl = 1;
+ int contains_mod_auth = 0;
+
+ /* prepend default modules */
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ ds = (data_string *)srv->srvconf.modules->data[i];
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_indexfile"))) {
+ prepend_mod_indexfile = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_staticfile"))) {
+ append_mod_staticfile = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_dirlisting"))) {
+ append_mod_dirlisting = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_openssl"))) {
+ append_mod_openssl = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_authn_file"))) {
+ append_mod_authn_file = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_authn_ldap"))) {
+ append_mod_authn_ldap = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_authn_mysql"))) {
+ append_mod_authn_mysql = 0;
+ }
+
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_auth"))) {
+ contains_mod_auth = 1;
+ }
+
+ if (0 == prepend_mod_indexfile &&
+ 0 == append_mod_dirlisting &&
+ 0 == append_mod_staticfile &&
+ 0 == append_mod_openssl &&
+ 0 == append_mod_authn_file &&
+ 0 == append_mod_authn_ldap &&
+ 0 == append_mod_authn_mysql &&
+ 1 == contains_mod_auth) {
+ break;
+ }
+ }
+
+ if (prepend_mod_indexfile) {
+ /* mod_indexfile has to be loaded before mod_fastcgi and friends */
+ array *modules = array_init();
+ array_insert_value(modules, CONST_STR_LEN("mod_indexfile"));
+
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ ds = (data_string *)srv->srvconf.modules->data[i];
+ array_insert_value(modules, CONST_BUF_LEN(ds->value));
+ }
+
+ array_free(srv->srvconf.modules);
+ srv->srvconf.modules = modules;
+ }
+
+ /* append default modules */
+ if (append_mod_dirlisting) {
+ array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_dirlisting"));
+ }
+
+ if (append_mod_staticfile) {
+ array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_staticfile"));
+ }
+
+ if (append_mod_openssl) {
+ #ifdef USE_OPENSSL_CRYPTO
+ config_warn_openssl_module(srv);
+ #endif
+ }
+
+ /* mod_auth.c,http_auth.c auth backends were split into separate modules
+ * Automatically load auth backend modules for compatibility with
+ * existing lighttpd 1.4.x configs */
+ if (contains_mod_auth) {
+ if (append_mod_authn_file) {
+ array_insert_value(srv->srvconf.modules, CONST_STR_LEN("mod_authn_file"));
+ }
+ if (append_mod_authn_ldap) {
+ #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
+ config_warn_authn_module(srv, CONST_STR_LEN("ldap"));
+ #endif
+ }
+ if (append_mod_authn_mysql) {
+ #if defined(HAVE_MYSQL)
+ config_warn_authn_module(srv, CONST_STR_LEN("mysql"));
+ #endif
+ }
+ }
+ }
+
+ return ret;
+
+}
+
+
+#define PATCH(x) con->conf.x = s->x
+int config_setup_connection(server *srv, connection *con) {
+ specific_config *s = srv->config_storage[0];
+
+ PATCH(http_parseopts);
+
+ PATCH(allow_http11);
+ PATCH(mimetypes);
+ PATCH(document_root);
+ PATCH(high_precision_timestamps);
+ PATCH(max_keep_alive_requests);
+ PATCH(max_keep_alive_idle);
+ PATCH(max_read_idle);
+ PATCH(max_write_idle);
+ PATCH(max_request_size);
+ PATCH(use_xattr);
+ PATCH(error_handler);
+ PATCH(error_handler_404);
+ PATCH(error_intercept);
+ PATCH(errorfile_prefix);
+#ifdef HAVE_LSTAT
+ PATCH(follow_symlink);
+#endif
+ PATCH(server_tag);
+ PATCH(kbytes_per_second);
+ PATCH(global_kbytes_per_second);
+ PATCH(global_bytes_per_second_cnt);
+
+ con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
+ buffer_copy_buffer(con->server_name, s->server_name);
+
+ PATCH(log_request_header);
+ PATCH(log_response_header);
+ PATCH(log_request_handling);
+ PATCH(log_condition_handling);
+ PATCH(log_file_not_found);
+ PATCH(log_timeouts);
+
+ PATCH(range_requests);
+ PATCH(force_lowercase_filenames);
+ /*PATCH(listen_backlog);*//*(not necessary; used only at startup)*/
+ PATCH(stream_request_body);
+ PATCH(stream_response_body);
+ PATCH(socket_perms);
+
+ PATCH(etag_use_inode);
+ PATCH(etag_use_mtime);
+ PATCH(etag_use_size);
+
+ return 0;
+}
+
+int config_patch_connection(server *srv, connection *con) {
+ size_t i, j;
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ specific_config *s = srv->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
+ PATCH(document_root);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
+ PATCH(range_requests);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler"))) {
+ PATCH(error_handler);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
+ PATCH(error_handler_404);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-intercept"))) {
+ PATCH(error_intercept);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.errorfile-prefix"))) {
+ PATCH(errorfile_prefix);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.assign"))) {
+ PATCH(mimetypes);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-requests"))) {
+ PATCH(max_keep_alive_requests);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-idle"))) {
+ PATCH(max_keep_alive_idle);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-write-idle"))) {
+ PATCH(max_write_idle);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-read-idle"))) {
+ PATCH(max_read_idle);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-request-size"))) {
+ PATCH(max_request_size);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.use-xattr"))) {
+ PATCH(use_xattr);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-inode"))) {
+ PATCH(etag_use_inode);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-mtime"))) {
+ PATCH(etag_use_mtime);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-size"))) {
+ PATCH(etag_use_size);
+#ifdef HAVE_LSTAT
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
+ PATCH(follow_symlink);
+#endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
+ buffer_copy_buffer(con->server_name, s->server_name);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
+ PATCH(server_tag);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.stream-request-body"))) {
+ PATCH(stream_request_body);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.stream-response-body"))) {
+ PATCH(stream_response_body);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connection.kbytes-per-second"))) {
+ PATCH(kbytes_per_second);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-handling"))) {
+ PATCH(log_request_handling);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-header"))) {
+ PATCH(log_request_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-response-header"))) {
+ PATCH(log_response_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
+ PATCH(log_condition_handling);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
+ PATCH(log_file_not_found);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-timeouts"))) {
+ PATCH(log_timeouts);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
+ PATCH(allow_http11);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
+ PATCH(force_lowercase_filenames);
+ #if 0 /*(not necessary; used only at startup)*/
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.listen-backlog"))) {
+ PATCH(listen_backlog);
+ #endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
+ PATCH(global_kbytes_per_second);
+ PATCH(global_bytes_per_second_cnt);
+ con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.socket-perms"))) {
+ PATCH(socket_perms);
+ }
+ }
+ }
+
+ con->etag_flags = (con->conf.etag_use_mtime ? ETAG_USE_MTIME : 0) |
+ (con->conf.etag_use_inode ? ETAG_USE_INODE : 0) |
+ (con->conf.etag_use_size ? ETAG_USE_SIZE : 0);
+
+ return 0;
+}
+#undef PATCH
+
+typedef struct {
+ int foo;
+ int bar;
+
+ const buffer *source;
+ const char *input;
+ size_t offset;
+ size_t size;
+
+ int line_pos;
+ int line;
+
+ int in_key;
+ int in_brace;
+ int in_cond;
+} tokenizer_t;
+
+#if 0
+static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
+ if (buffer_string_is_empty(basedir) ||
+ (fn[0] == '/' || fn[0] == '\\') ||
+ (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
+ t->file = buffer_init_string(fn);
+ } else {
+ t->file = buffer_init_buffer(basedir);
+ buffer_append_string(t->file, fn);
+ }
+
+ if (0 != stream_open(&(t->s), t->file)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "opening configfile ", t->file, "failed:", strerror(errno));
+ buffer_free(t->file);
+ return -1;
+ }
+
+ t->input = t->s.start;
+ t->offset = 0;
+ t->size = t->s.size;
+ t->line = 1;
+ t->line_pos = 1;
+
+ t->in_key = 1;
+ t->in_brace = 0;
+ t->in_cond = 0;
+ return 0;
+}
+
+static int tokenizer_close(server *srv, tokenizer_t *t) {
+ UNUSED(srv);
+
+ buffer_free(t->file);
+ return stream_close(&(t->s));
+}
+#endif
+static int config_skip_newline(tokenizer_t *t) {
+ int skipped = 1;
+ force_assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
+ if (t->input[t->offset] == '\r' && t->input[t->offset + 1] == '\n') {
+ skipped ++;
+ t->offset ++;
+ }
+ t->offset ++;
+ return skipped;
+}
+
+static int config_skip_comment(tokenizer_t *t) {
+ int i;
+ force_assert(t->input[t->offset] == '#');
+ for (i = 1; t->input[t->offset + i] &&
+ (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
+ i++);
+ t->offset += i;
+ return i;
+}
+
+static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
+ int tid = 0;
+ size_t i;
+
+ for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
+ char c = t->input[t->offset];
+ const char *start = NULL;
+
+ switch (c) {
+ case '=':
+ if (t->in_brace) {
+ if (t->input[t->offset + 1] == '>') {
+ t->offset += 2;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("=>"));
+
+ tid = TK_ARRAY_ASSIGN;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "use => for assignments in arrays");
+ return -1;
+ }
+ } else if (t->in_cond) {
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("=="));
+
+ tid = TK_EQ;
+ } else if (t->input[t->offset + 1] == '~') {
+ t->offset += 2;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("=~"));
+
+ tid = TK_MATCH;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "only =~ and == are allowed in the condition");
+ return -1;
+ }
+ t->in_key = 1;
+ t->in_cond = 0;
+ } else if (t->in_key) {
+ tid = TK_ASSIGN;
+
+ buffer_copy_string_len(token, t->input + t->offset, 1);
+
+ t->offset++;
+ t->line_pos++;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "unexpected equal-sign: =");
+ return -1;
+ }
+
+ break;
+ case '!':
+ if (t->in_cond) {
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("!="));
+
+ tid = TK_NE;
+ } else if (t->input[t->offset + 1] == '~') {
+ t->offset += 2;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("!~"));
+
+ tid = TK_NOMATCH;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "only !~ and != are allowed in the condition");
+ return -1;
+ }
+ t->in_key = 1;
+ t->in_cond = 0;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "unexpected exclamation-marks: !");
+ return -1;
+ }
+
+ break;
+ case '\t':
+ case ' ':
+ t->offset++;
+ t->line_pos++;
+ break;
+ case '\n':
+ case '\r':
+ if (t->in_brace == 0) {
+ int done = 0;
+ while (!done && t->offset < t->size) {
+ switch (t->input[t->offset]) {
+ case '\r':
+ case '\n':
+ config_skip_newline(t);
+ t->line_pos = 1;
+ t->line++;
+ break;
+
+ case '#':
+ t->line_pos += config_skip_comment(t);
+ break;
+
+ case '\t':
+ case ' ':
+ t->offset++;
+ t->line_pos++;
+ break;
+
+ default:
+ done = 1;
+ }
+ }
+ t->in_key = 1;
+ tid = TK_EOL;
+ buffer_copy_string_len(token, CONST_STR_LEN("(EOL)"));
+ } else {
+ config_skip_newline(t);
+ t->line_pos = 1;
+ t->line++;
+ }
+ break;
+ case ',':
+ if (t->in_brace > 0) {
+ tid = TK_COMMA;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(COMMA)"));
+ }
+
+ t->offset++;
+ t->line_pos++;
+ break;
+ case '"':
+ /* search for the terminating " */
+ start = t->input + t->offset + 1;
+ buffer_copy_string_len(token, CONST_STR_LEN(""));
+
+ for (i = 1; t->input[t->offset + i]; i++) {
+ if (t->input[t->offset + i] == '\\' &&
+ t->input[t->offset + i + 1] == '"') {
+
+ buffer_append_string_len(token, start, t->input + t->offset + i - start);
+
+ start = t->input + t->offset + i + 1;
+
+ /* skip the " */
+ i++;
+ continue;
+ }
+
+
+ if (t->input[t->offset + i] == '"') {
+ tid = TK_STRING;
+
+ buffer_append_string_len(token, start, t->input + t->offset + i - start);
+
+ break;
+ }
+ }
+
+ if (t->input[t->offset + i] == '\0') {
+ /* ERROR */
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "missing closing quote");
+
+ return -1;
+ }
+
+ t->offset += i + 1;
+ t->line_pos += i + 1;
+
+ break;
+ case '(':
+ t->offset++;
+ t->in_brace++;
+
+ tid = TK_LPARAN;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("("));
+ break;
+ case ')':
+ t->offset++;
+ t->in_brace--;
+
+ tid = TK_RPARAN;
+
+ buffer_copy_string_len(token, CONST_STR_LEN(")"));
+ break;
+ case '$':
+ t->offset++;
+
+ tid = TK_DOLLAR;
+ t->in_cond = 1;
+ t->in_key = 0;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("$"));
+
+ break;
+
+ case '+':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ buffer_copy_string_len(token, CONST_STR_LEN("+="));
+ tid = TK_APPEND;
+ } else {
+ t->offset++;
+ tid = TK_PLUS;
+ buffer_copy_string_len(token, CONST_STR_LEN("+"));
+ }
+ break;
+
+ case ':':
+ if (t->input[t->offset+1] == '=') {
+ t->offset += 2;
+ tid = TK_FORCE_ASSIGN;
+ buffer_copy_string_len(token, CONST_STR_LEN(":="));
+ }
+ break;
+
+ case '{':
+ t->offset++;
+
+ tid = TK_LCURLY;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("{"));
+
+ break;
+
+ case '}':
+ t->offset++;
+
+ tid = TK_RCURLY;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("}"));
+
+ break;
+
+ case '[':
+ t->offset++;
+
+ tid = TK_LBRACKET;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("["));
+
+ break;
+
+ case ']':
+ t->offset++;
+
+ tid = TK_RBRACKET;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("]"));
+
+ break;
+ case '#':
+ t->line_pos += config_skip_comment(t);
+
+ break;
+ default:
+ if (t->in_cond) {
+ for (i = 0; t->input[t->offset + i] &&
+ (isalpha((unsigned char)t->input[t->offset + i])
+ || t->input[t->offset + i] == '_'); ++i);
+
+ if (i && t->input[t->offset + i]) {
+ tid = TK_SRVVARNAME;
+ buffer_copy_string_len(token, t->input + t->offset, i);
+
+ t->offset += i;
+ t->line_pos += i;
+ } else {
+ /* ERROR */
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "invalid character in condition");
+ return -1;
+ }
+ } else if (isdigit((unsigned char)c)) {
+ /* take all digits */
+ for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
+
+ /* was there it least a digit ? */
+ if (i) {
+ tid = TK_INTEGER;
+
+ buffer_copy_string_len(token, t->input + t->offset, i);
+
+ t->offset += i;
+ t->line_pos += i;
+ }
+ } else {
+ /* the key might consist of [-.0-9a-z] */
+ for (i = 0; t->input[t->offset + i] &&
+ (isalnum((unsigned char)t->input[t->offset + i]) ||
+ t->input[t->offset + i] == '.' ||
+ t->input[t->offset + i] == '_' || /* for env.* */
+ t->input[t->offset + i] == '-'
+ ); i++);
+
+ if (i && t->input[t->offset + i]) {
+ buffer_copy_string_len(token, t->input + t->offset, i);
+
+ if (strcmp(token->ptr, "include") == 0) {
+ tid = TK_INCLUDE;
+ } else if (strcmp(token->ptr, "include_shell") == 0) {
+ tid = TK_INCLUDE_SHELL;
+ } else if (strcmp(token->ptr, "global") == 0) {
+ tid = TK_GLOBAL;
+ } else if (strcmp(token->ptr, "else") == 0) {
+ tid = TK_ELSE;
+ } else {
+ tid = TK_LKEY;
+ }
+
+ t->offset += i;
+ t->line_pos += i;
+ } else {
+ /* ERROR */
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "invalid character in variable name");
+ return -1;
+ }
+ }
+ break;
+ }
+ }
+
+ if (tid) {
+ *token_id = tid;
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ token, token->used - 1, tid);
+#endif
+
+ return 1;
+ } else if (t->offset < t->size) {
+ log_error_write(srv, __FILE__, __LINE__, "Dsb", tid, ",", token);
+ }
+ return 0;
+}
+
+static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
+ void *pParser;
+ int token_id;
+ buffer *token, *lasttoken;
+ int ret;
+
+ pParser = configparserAlloc( malloc );
+ force_assert(pParser);
+ lasttoken = buffer_init();
+ token = buffer_init();
+ while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
+ buffer_copy_buffer(lasttoken, token);
+ configparser(pParser, token_id, token, context);
+
+ token = buffer_init();
+ }
+ buffer_free(token);
+
+ if (ret != -1 && context->ok) {
+ /* add an EOL at EOF, better than say sorry */
+ configparser(pParser, TK_EOL, buffer_init_string("(EOL)"), context);
+ if (context->ok) {
+ configparser(pParser, 0, NULL, context);
+ }
+ }
+ configparserFree(pParser, free);
+
+ if (ret == -1) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "configfile parser failed at:", lasttoken);
+ } else if (context->ok == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
+ "parser failed somehow near here:", lasttoken);
+ ret = -1;
+ }
+ buffer_free(lasttoken);
+
+ return ret == -1 ? -1 : 0;
+}
+
+static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *input, size_t size) {
+
+ t->source = source;
+ t->input = input;
+ t->size = size;
+ t->offset = 0;
+ t->line = 1;
+ t->line_pos = 1;
+
+ t->in_key = 1;
+ t->in_brace = 0;
+ t->in_cond = 0;
+ return 0;
+}
+
+static int config_parse_file_stream(server *srv, config_t *context, const buffer *filename) {
+ tokenizer_t t;
+ stream s;
+ int ret;
+
+ if (0 != stream_open(&s, filename)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "opening configfile ", filename, "failed:", strerror(errno));
+ return -1;
+ } else {
+ tokenizer_init(&t, filename, s.start, s.size);
+ ret = config_parse(srv, context, &t);
+ }
+
+ stream_close(&s);
+ return ret;
+}
+
+int config_parse_file(server *srv, config_t *context, const char *fn) {
+ buffer *filename;
+ size_t i;
+ int ret = -1;
+ #ifdef GLOB_BRACE
+ int flags = GLOB_BRACE;
+ #else
+ int flags = 0;
+ #endif
+ glob_t gl;
+
+ if ((fn[0] == '/' || fn[0] == '\\') ||
+ (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\')) ||
+ (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\\'))) {
+ filename = buffer_init_string(fn);
+ } else {
+ filename = buffer_init_buffer(context->basedir);
+ buffer_append_string(filename, fn);
+ }
+
+ switch (glob(filename->ptr, flags, NULL, &gl)) {
+ case 0:
+ for (i = 0; i < gl.gl_pathc; ++i) {
+ buffer_copy_string(filename, gl.gl_pathv[i]);
+ ret = config_parse_file_stream(srv, context, filename);
+ if (0 != ret) break;
+ }
+ globfree(&gl);
+ break;
+ case GLOB_NOMATCH:
+ if (filename->ptr[strcspn(filename->ptr, "*?[]{}")] != '\0') { /*(contains glob metachars)*/
+ ret = 0; /* not an error if no files match glob pattern */
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "include file not found: ", filename);
+ }
+ break;
+ case GLOB_ABORTED:
+ case GLOB_NOSPACE:
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "glob()", filename, "failed:", strerror(errno));
+ break;
+ }
+
+ buffer_free(filename);
+ return ret;
+}
+
+#ifdef __CYGWIN__
+
+static char* getCWD(char *buf, size_t sz) {
+ if (NULL == getcwd(buf, sz)) {
+ return NULL;
+ }
+ for (size_t i = 0; buf[i]; ++i) {
+ if (buf[i] == '\\') buf[i] = '/';
+ }
+ return buf;
+}
+
+#define getcwd(buf, sz) getCWD((buf),(sz))
+
+#endif /* __CYGWIN__ */
+
+int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
+ int ret = 0;
+ int fds[2];
+ char oldpwd[PATH_MAX];
+
+ if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "cannot get cwd", strerror(errno));
+ return -1;
+ }
+
+ if (!buffer_string_is_empty(context->basedir)) {
+ if (0 != chdir(context->basedir->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "cannot change directory to", context->basedir, strerror(errno));
+ return -1;
+ }
+ }
+
+ if (pipe(fds)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "pipe failed: ", strerror(errno));
+ ret = -1;
+ }
+ else {
+ char *shell = getenv("SHELL");
+ char *args[4];
+ pid_t pid;
+ *(const char **)&args[0] = shell ? shell : "/bin/sh";
+ *(const char **)&args[1] = "-c";
+ *(const char **)&args[2] = cmd;
+ args[3] = NULL;
+
+ fdevent_setfd_cloexec(fds[0]);
+ pid = fdevent_fork_execve(args[0], args, NULL, -1, fds[1], -1, -1);
+ if (-1 == pid) {
+ log_error_write(srv, __FILE__, __LINE__, "SSss",
+ "fork/exec(", cmd, "):", strerror(errno));
+ ret = -1;
+ }
+ else {
+ ssize_t rd;
+ pid_t wpid;
+ int wstatus;
+ buffer *out = buffer_init();
+ close(fds[1]);
+ fds[1] = -1;
+ do {
+ rd = read(fds[0], buffer_string_prepare_append(out, 1023), 1023);
+ if (rd >= 0) buffer_commit(out, (size_t)rd);
+ } while (rd > 0 || (-1 == rd && errno == EINTR));
+ if (0 != rd) {
+ log_error_write(srv, __FILE__, __LINE__, "SSss",
+ "read \"", cmd, "\" failed:", strerror(errno));
+ ret = -1;
+ }
+ close(fds[0]);
+ fds[0] = -1;
+ while (-1 == (wpid = waitpid(pid, &wstatus, 0)) && errno == EINTR) ;
+ if (wpid != pid) {
+ log_error_write(srv, __FILE__, __LINE__, "SSss",
+ "waitpid \"", cmd, "\" failed:", strerror(errno));
+ ret = -1;
+ }
+ if (0 != wstatus) {
+ log_error_write(srv, __FILE__, __LINE__, "SSsd",
+ "command \"", cmd, "\" exited non-zero:", WEXITSTATUS(wstatus));
+ ret = -1;
+ }
+
+ if (-1 != ret) {
+ buffer *source = buffer_init_string(cmd);
+ tokenizer_t t;
+ tokenizer_init(&t, source, CONST_BUF_LEN(out));
+ ret = config_parse(srv, context, &t);
+ buffer_free(source);
+ }
+ buffer_free(out);
+ }
+ if (-1 != fds[0]) close(fds[0]);
+ if (-1 != fds[1]) close(fds[1]);
+ }
+
+ if (0 != chdir(oldpwd)) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "cannot change directory to", oldpwd, strerror(errno));
+ ret = -1;
+ }
+ return ret;
+}
+
+static void context_init(server *srv, config_t *context) {
+ context->srv = srv;
+ context->ok = 1;
+ vector_config_weak_init(&context->configs_stack);
+ context->basedir = buffer_init();
+}
+
+static void context_free(config_t *context) {
+ vector_config_weak_clear(&context->configs_stack);
+ buffer_free(context->basedir);
+}
+
+int config_read(server *srv, const char *fn) {
+ config_t context;
+ data_config *dc;
+ buffer *dcwd;
+ int ret;
+ char *pos;
+ buffer *filename;
+
+ context_init(srv, &context);
+ context.all_configs = srv->config_context;
+
+#ifdef __WIN32
+ pos = strrchr(fn, '\\');
+#else
+ pos = strrchr(fn, '/');
+#endif
+ if (pos) {
+ buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
+ }
+
+ dc = data_config_init();
+ buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));
+
+ force_assert(context.all_configs->used == 0);
+ dc->context_ndx = context.all_configs->used;
+ array_insert_unique(context.all_configs, (data_unset *)dc);
+ context.current = dc;
+
+ /* default context */
+ *array_get_int_ptr(dc->value, CONST_STR_LEN("var.PID")) = getpid();
+
+ dcwd = srv->tmp_buf;
+ buffer_string_prepare_copy(dcwd, PATH_MAX-1);
+ if (NULL != getcwd(dcwd->ptr, buffer_string_space(dcwd)+1)) {
+ buffer_commit(dcwd, strlen(dcwd->ptr));
+ array_set_key_value(dc->value, CONST_STR_LEN("var.CWD"), CONST_BUF_LEN(dcwd));
+ }
+
+ filename = buffer_init_string(fn);
+ ret = config_parse_file_stream(srv, &context, filename);
+ buffer_free(filename);
+
+ /* remains nothing if parser is ok */
+ force_assert(!(0 == ret && context.ok && 0 != context.configs_stack.used));
+ context_free(&context);
+
+ if (0 != ret) {
+ return ret;
+ }
+
+ if (0 != config_insert(srv)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int config_set_defaults(server *srv) {
+ size_t i;
+ specific_config *s = srv->config_storage[0];
+ struct stat st1, st2;
+
+ force_assert(sizeof(((connection *)0)->conditional_is_valid) >= COMP_LAST_ELEMENT);
+
+ if (0 != fdevent_config(srv)) return -1;
+
+ if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
+ if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.chroot doesn't exist:", srv->srvconf.changeroot);
+ return -1;
+ }
+ if (!S_ISDIR(st1.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.chroot isn't a directory:", srv->srvconf.changeroot);
+ return -1;
+ }
+ }
+
+ if (!srv->srvconf.upload_tempdirs->used) {
+ const char *tmpdir = getenv("TMPDIR");
+ if (NULL == tmpdir) tmpdir = "/var/tmp";
+ array_insert_value(srv->srvconf.upload_tempdirs, tmpdir, strlen(tmpdir));
+ }
+
+ if (srv->srvconf.upload_tempdirs->used) {
+ buffer * const b = srv->tmp_buf;
+ size_t len;
+ buffer_clear(b);
+ if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
+ buffer_copy_buffer(b, srv->srvconf.changeroot);
+ buffer_append_slash(b);
+ }
+ len = buffer_string_length(b);
+
+ for (i = 0; i < srv->srvconf.upload_tempdirs->used; ++i) {
+ const data_string * const ds = (data_string *)srv->srvconf.upload_tempdirs->data[i];
+ buffer_string_set_length(b, len); /*(truncate)*/
+ buffer_append_string_buffer(b, ds->value);
+ if (-1 == stat(b->ptr, &st1)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.upload-dirs doesn't exist:", b);
+ } else if (!S_ISDIR(st1.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.upload-dirs isn't a directory:", b);
+ }
+ }
+ }
+
+ chunkqueue_set_tempdirs_default(
+ srv->srvconf.upload_tempdirs,
+ srv->srvconf.upload_temp_file_size);
+
+ if (buffer_string_is_empty(s->document_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "a default document-root has to be set");
+
+ return -1;
+ }
+
+ buffer_copy_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_lower(srv->tmp_buf);
+
+ if (2 == s->force_lowercase_filenames) { /* user didn't configure it in global section? */
+ s->force_lowercase_filenames = 0; /* default to 0 */
+
+ if (0 == stat(srv->tmp_buf->ptr, &st1)) {
+ int is_lower = 0;
+
+ is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
+
+ /* lower-case existed, check upper-case */
+ buffer_copy_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_upper(srv->tmp_buf);
+
+ /* we have to handle the special case that upper and lower-casing results in the same filename
+ * as in server.document-root = "/" or "/12345/" */
+
+ if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
+ /* lower-casing and upper-casing didn't result in
+ * an other filename, no need to stat(),
+ * just assume it is case-sensitive. */
+
+ s->force_lowercase_filenames = 0;
+ } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
+
+ /* upper case exists too, doesn't the FS handle this ? */
+
+ /* upper and lower have the same inode -> case-insensitve FS */
+
+ if (st1.st_ino == st2.st_ino) {
+ /* upper and lower have the same inode -> case-insensitve FS */
+
+ s->force_lowercase_filenames = 1;
+ }
+ }
+ }
+ }
+
+ if (srv->srvconf.port == 0) {
+ srv->srvconf.port = s->ssl_enabled ? 443 : 80;
+ }
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/configfile.h b/data/lighttpd/lighttpd-1.4.53/src/configfile.h
new file mode 100644
index 000000000..1cef1209f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/configfile.h
@@ -0,0 +1,140 @@
+#ifndef _CONFIG_PARSER_H_
+#define _CONFIG_PARSER_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "array.h"
+#include "buffer.h"
+#include "vector.h"
+
+/**
+ * possible compare ops in the configfile parser
+ */
+typedef enum {
+ CONFIG_COND_UNSET,
+ CONFIG_COND_EQ, /** == */
+ CONFIG_COND_MATCH, /** =~ */
+ CONFIG_COND_NE, /** != */
+ CONFIG_COND_NOMATCH, /** !~ */
+ CONFIG_COND_ELSE /** (always true if reached) */
+} config_cond_t;
+
+/**
+ * possible fields to match against
+ */
+typedef enum {
+ COMP_UNSET,
+ COMP_SERVER_SOCKET,
+ COMP_HTTP_URL,
+ COMP_HTTP_HOST,
+ COMP_HTTP_REFERER, /*(subsumed by COMP_HTTP_REQUEST_HEADER)*/
+ COMP_HTTP_USER_AGENT, /*(subsumed by COMP_HTTP_REQUEST_HEADER)*/
+ COMP_HTTP_LANGUAGE, /*(subsumed by COMP_HTTP_REQUEST_HEADER)*/
+ COMP_HTTP_COOKIE, /*(subsumed by COMP_HTTP_REQUEST_HEADER)*/
+ COMP_HTTP_REMOTE_IP,
+ COMP_HTTP_QUERY_STRING,
+ COMP_HTTP_SCHEME,
+ COMP_HTTP_REQUEST_METHOD,
+ COMP_HTTP_REQUEST_HEADER,
+
+ COMP_LAST_ELEMENT
+} comp_key_t;
+
+/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
+ * for print: comp_key op string
+ * for compare: comp cond string/regex
+ */
+
+#ifdef HAVE_PCRE_H
+struct pcre_extra; /* declaration */
+#endif
+
+typedef struct data_config data_config;
+DEFINE_TYPED_VECTOR_NO_RELEASE(config_weak, data_config*);
+
+struct data_config {
+ DATA_UNSET;
+
+ array *value;
+
+ buffer *comp_tag;
+ buffer *comp_key;
+ comp_key_t comp;
+
+ config_cond_t cond;
+ buffer *op;
+
+ int context_ndx; /* more or less like an id */
+ vector_config_weak children;
+ /* nested */
+ data_config *parent;
+ /* for chaining only */
+ data_config *prev;
+ data_config *next;
+
+ buffer *string;
+#ifdef HAVE_PCRE_H
+ void *regex;
+ struct pcre_extra *regex_study;
+#endif
+};
+
+struct cond_cache_t; /* declaration */
+
+data_config *data_config_init(void);
+int data_config_pcre_compile(data_config *dc);
+int data_config_pcre_exec(data_config *dc, struct cond_cache_t *cache, buffer *b);
+
+typedef struct {
+ server *srv;
+ int ok;
+ array *all_configs;
+ vector_config_weak configs_stack; /* to parse nested block */
+ data_config *current; /* current started with { */
+ buffer *basedir;
+} config_t;
+
+int config_read(server *srv, const char *fn);
+int config_set_defaults(server *srv);
+void *configparserAlloc(void *(*mallocProc)(size_t));
+void configparserFree(void *p, void (*freeProc)(void*));
+void configparser(void *yyp, int yymajor, buffer *yyminor, config_t *ctx);
+int config_parse_file(server *srv, config_t *context, const char *fn);
+int config_parse_cmd(server *srv, config_t *context, const char *cmd);
+data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2);
+
+int config_setup_connection(server *srv, connection *con);
+int config_patch_connection(server *srv, connection *con);
+
+void config_cond_cache_reset(server *srv, connection *con);
+void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item);
+
+typedef enum { T_CONFIG_UNSET,
+ T_CONFIG_STRING,
+ T_CONFIG_SHORT,
+ T_CONFIG_INT,
+ T_CONFIG_BOOLEAN,
+ T_CONFIG_ARRAY,
+ T_CONFIG_LOCAL,
+ T_CONFIG_DEPRECATED,
+ T_CONFIG_UNSUPPORTED
+} config_values_type_t;
+
+typedef enum { T_CONFIG_SCOPE_UNSET,
+ T_CONFIG_SCOPE_SERVER,
+ T_CONFIG_SCOPE_CONNECTION
+} config_scope_type_t;
+
+typedef struct {
+ const char *key;
+ void *destination;
+
+ config_values_type_t type;
+ config_scope_type_t scope;
+} config_values_t;
+
+int config_insert_values_global(server *srv, array *ca, const config_values_t *cv, config_scope_type_t scope);
+int config_insert_values_internal(server *srv, array *ca, const config_values_t *cv, config_scope_type_t scope);
+int config_check_cond(server *srv, connection *con, data_config *dc);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/configparser.c b/data/lighttpd/lighttpd-1.4.53/src/configparser.c
new file mode 100644
index 000000000..5c50db121
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/configparser.c
@@ -0,0 +1,1870 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+*/
+/* First off, code is include which follows the "include" declaration
+** in the input file. */
+#include "first.h"
+#include <stdio.h>
+#line 5 "../../src/configparser.y"
+
+#include "first.h"
+#include "base.h"
+#include "configfile.h"
+#include "buffer.h"
+#include "array.h"
+#include "request.h" /* http_request_host_normalize() */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
+ if (isnew) {
+ dc->context_ndx = ctx->all_configs->used;
+ force_assert(dc->context_ndx > ctx->current->context_ndx);
+ array_insert_unique(ctx->all_configs, (data_unset *)dc);
+ dc->parent = ctx->current;
+ vector_config_weak_push(&dc->parent->children, dc);
+ }
+ if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) {
+ fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
+ exit(-1);
+ }
+ vector_config_weak_push(&ctx->configs_stack, ctx->current);
+ ctx->current = dc;
+}
+
+static data_config *configparser_pop(config_t *ctx) {
+ data_config *old = ctx->current;
+ ctx->current = vector_config_weak_pop(&ctx->configs_stack);
+ return old;
+}
+
+/* return a copied variable */
+static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
+ data_unset *du;
+ data_config *dc;
+
+#if 0
+ fprintf(stderr, "get var %s\n", key->ptr);
+#endif
+ for (dc = ctx->current; dc; dc = dc->parent) {
+#if 0
+ fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
+ array_print(dc->value, 0);
+#endif
+ if (NULL != (du = array_get_element_klen(dc->value, CONST_BUF_LEN(key)))) {
+ du = du->fn->copy(du);
+ buffer_clear(du->key);
+ return du;
+ }
+ }
+ return NULL;
+}
+
+/* op1 is to be eat/return by this function if success, op1->key is not cared
+ op2 is left untouch, unreferenced
+ */
+data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
+ /* type mismatch */
+ if (op1->type != op2->type) {
+ if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
+ data_string *ds = (data_string *)op1;
+ buffer_append_int(ds->value, ((data_integer*)op2)->value);
+ return op1;
+ } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
+ data_string *ds = data_string_init();
+ buffer_append_int(ds->value, ((data_integer*)op1)->value);
+ buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
+ op1->fn->free(op1);
+ return (data_unset *)ds;
+ } else {
+ fprintf(stderr, "data type mismatch, cannot merge\n");
+ op1->fn->free(op1);
+ return NULL;
+ }
+ }
+
+ switch (op1->type) {
+ case TYPE_STRING:
+ buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
+ break;
+ case TYPE_INTEGER:
+ ((data_integer *)op1)->value += ((data_integer *)op2)->value;
+ break;
+ case TYPE_ARRAY: {
+ array *dst = ((data_array *)op1)->value;
+ array *src = ((data_array *)op2)->value;
+ data_unset *du;
+ size_t i;
+
+ for (i = 0; i < src->used; i ++) {
+ du = (data_unset *)src->data[i];
+ if (du) {
+ if (du->is_index_key || buffer_is_empty(du->key) || !array_get_element_klen(dst, CONST_BUF_LEN(du->key))) {
+ array_insert_unique(dst, du->fn->copy(du));
+ } else {
+ fprintf(stderr, "Duplicate array-key '%s'\n", du->key->ptr);
+ op1->fn->free(op1);
+ return NULL;
+ }
+ }
+ }
+ break;
+ default:
+ force_assert(0);
+ break;
+ }
+ }
+ return op1;
+}
+
+static int configparser_remoteip_normalize_compat(buffer *rvalue) {
+ /* $HTTP["remoteip"] IPv6 accepted with or without '[]' for config compat
+ * http_request_host_normalize() expects IPv6 with '[]',
+ * and config processing at runtime expects COMP_HTTP_REMOTE_IP
+ * compared without '[]', so strip '[]' after normalization */
+ buffer *b = buffer_init();
+ int rc;
+
+ if (rvalue->ptr[0] != '[') {
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ buffer_append_string_buffer(b, rvalue);
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ } else {
+ buffer_append_string_buffer(b, rvalue);
+ }
+
+ rc = http_request_host_normalize(b, 0);
+
+ if (0 == rc) {
+ /* remove surrounding '[]' */
+ size_t blen = buffer_string_length(b);
+ if (blen > 1) buffer_copy_string_len(rvalue, b->ptr+1, blen-2);
+ }
+
+ buffer_free(b);
+ return rc;
+}
+
+
+#line 154 "./configparser.c"
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** configparserTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
+** This is typically a union of many types, one of
+** which is configparserTOKENTYPE. The entry in the union
+** for base tokens is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** configparserARG_SDECL A static variable declaration for the %extra_argument
+** configparserARG_PDECL A parameter declaration for the %extra_argument
+** configparserARG_STORE Code to store %extra_argument into yypParser
+** configparserARG_FETCH Code to extract %extra_argument from yypParser
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+*/
+/*  */
+#define YYCODETYPE unsigned char
+#define YYNOCODE 51
+#define YYACTIONTYPE unsigned char
+#define configparserTOKENTYPE buffer *
+typedef union {
+ configparserTOKENTYPE yy0;
+ data_config * yy18;
+ buffer * yy29;
+ array * yy42;
+ config_cond_t yy53;
+ data_unset * yy91;
+ int yy101;
+} YYMINORTYPE;
+#define YYSTACKDEPTH 100
+#define configparserARG_SDECL config_t *ctx;
+#define configparserARG_PDECL ,config_t *ctx
+#define configparserARG_FETCH config_t *ctx = yypParser->ctx
+#define configparserARG_STORE yypParser->ctx = ctx
+#define YYNSTATE 70
+#define YYNRULE 44
+#define YYERRORSYMBOL 27
+#define YYERRSYMDT yy101
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+/* Next are that tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
+**
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
+**
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
+**
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+** yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+*/
+static YYACTIONTYPE yy_action[] = {
+ /* 0 */ 2, 3, 4, 5, 14, 15, 70, 16, 7, 48,
+ /* 10 */ 96, 21, 21, 17, 24, 25, 27, 44, 11, 43,
+ /* 20 */ 8, 16, 12, 49, 21, 21, 24, 25, 27, 30,
+ /* 30 */ 20, 61, 63, 43, 13, 65, 111, 49, 57, 58,
+ /* 40 */ 59, 60, 18, 39, 41, 61, 63, 16, 29, 28,
+ /* 50 */ 38, 21, 98, 31, 26, 23, 35, 9, 10, 43,
+ /* 60 */ 36, 47, 20, 49, 45, 16, 11, 66, 22, 21,
+ /* 70 */ 105, 61, 63, 6, 26, 23, 46, 43, 51, 69,
+ /* 80 */ 20, 49, 115, 1, 50, 29, 28, 34, 97, 61,
+ /* 90 */ 63, 26, 23, 35, 29, 19, 29, 52, 32, 33,
+ /* 100 */ 26, 23, 26, 23, 53, 106, 29, 52, 49, 29,
+ /* 110 */ 52, 67, 26, 23, 62, 26, 23, 64, 29, 37,
+ /* 120 */ 54, 55, 29, 40, 26, 23, 29, 42, 26, 23,
+ /* 130 */ 29, 56, 26, 23, 68, 96, 26, 23,
+};
+static YYCODETYPE yy_lookahead[] = {
+ /* 0 */ 30, 31, 32, 33, 34, 35, 0, 1, 46, 39,
+ /* 10 */ 16, 5, 5, 43, 7, 8, 9, 47, 48, 13,
+ /* 20 */ 16, 1, 14, 17, 5, 5, 7, 8, 9, 10,
+ /* 30 */ 6, 25, 26, 13, 29, 15, 12, 17, 21, 22,
+ /* 40 */ 23, 24, 2, 3, 4, 25, 26, 1, 36, 37,
+ /* 50 */ 38, 5, 14, 41, 42, 43, 44, 39, 40, 13,
+ /* 60 */ 12, 15, 6, 17, 14, 1, 48, 49, 36, 5,
+ /* 70 */ 14, 25, 26, 1, 42, 43, 29, 13, 19, 15,
+ /* 80 */ 6, 17, 28, 29, 18, 36, 37, 38, 16, 25,
+ /* 90 */ 26, 42, 43, 44, 36, 37, 36, 37, 10, 11,
+ /* 100 */ 42, 43, 42, 43, 44, 14, 36, 37, 17, 36,
+ /* 110 */ 37, 14, 42, 43, 44, 42, 43, 44, 36, 37,
+ /* 120 */ 20, 45, 36, 37, 42, 43, 36, 37, 42, 43,
+ /* 130 */ 36, 37, 42, 43, 29, 50, 42, 43,
+};
+#define YY_SHIFT_USE_DFLT (-7)
+static signed char yy_shift_ofst[] = {
+ /* 0 */ -7, 6, -7, -7, -7, 72, -6, 4, 91, -7,
+ /* 10 */ -7, 8, -7, 20, -7, -7, -7, 40, 7, 74,
+ /* 20 */ 7, -7, -7, -7, -7, -7, -7, 19, 24, -7,
+ /* 30 */ -7, 88, -7, 7, -7, 48, 7, 74, -7, 7,
+ /* 40 */ 74, 7, 74, 38, 50, -7, 46, -7, -7, 66,
+ /* 50 */ 59, 7, 74, 100, 17, 7, 56, -7, -7, -7,
+ /* 60 */ -7, 7, -7, 7, -7, -7, 97, -7, 64, -7,
+};
+#define YY_REDUCE_USE_DFLT (-39)
+static signed char yy_reduce_ofst[] = {
+ /* 0 */ 54, -30, -39, -39, -39, -38, -39, -39, 18, -39,
+ /* 10 */ -39, -39, 5, -30, -39, -39, -39, -39, 58, -39,
+ /* 20 */ 32, -39, -39, -39, -39, -39, -39, 12, -39, -39,
+ /* 30 */ -39, -39, -39, 49, -39, -39, 82, -39, -39, 86,
+ /* 40 */ -39, 90, -39, -39, -39, 47, -30, -39, -39, -39,
+ /* 50 */ -39, 60, -39, -39, 76, 94, -39, -39, -39, -39,
+ /* 60 */ -39, 70, -39, 73, -39, -39, -39, 105, -30, -39,
+};
+static YYACTIONTYPE yy_default[] = {
+ /* 0 */ 72, 114, 71, 73, 74, 114, 75, 114, 114, 100,
+ /* 10 */ 101, 114, 72, 114, 76, 77, 78, 114, 114, 79,
+ /* 20 */ 114, 82, 83, 85, 86, 87, 88, 114, 94, 84,
+ /* 30 */ 89, 114, 90, 92, 91, 114, 114, 95, 93, 114,
+ /* 40 */ 80, 114, 81, 114, 114, 72, 114, 99, 102, 114,
+ /* 50 */ 114, 114, 111, 114, 114, 114, 114, 107, 108, 109,
+ /* 60 */ 110, 114, 112, 114, 113, 103, 114, 72, 114, 104,
+};
+#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
+
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammer, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+ int stateno; /* The state-number */
+ int major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ int yyidx; /* Index of top element in stack */
+ int yyerrcnt; /* Shifts left before out of the error */
+ configparserARG_SDECL /* A place to hold %extra_argument */
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = NULL;
+static char *yyTracePrompt = NULL;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+#if 0
+void configparserTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *yyTokenName[] = {
+ "$", "EOL", "ASSIGN", "FORCE_ASSIGN",
+ "APPEND", "LKEY", "PLUS", "STRING",
+ "INTEGER", "LPARAN", "RPARAN", "COMMA",
+ "ARRAY_ASSIGN", "GLOBAL", "LCURLY", "RCURLY",
+ "ELSE", "DOLLAR", "SRVVARNAME", "LBRACKET",
+ "RBRACKET", "EQ", "MATCH", "NE",
+ "NOMATCH", "INCLUDE", "INCLUDE_SHELL", "error",
+ "input", "metalines", "metaline", "varline",
+ "global", "condlines", "include", "include_shell",
+ "value", "expression", "aelement", "condline",
+ "cond_else", "aelements", "array", "key",
+ "stringop", "cond", "eols", "globalstart",
+ "context", "context_else",
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *yyRuleName[] = {
+ /* 0 */ "input ::= metalines",
+ /* 1 */ "metalines ::= metalines metaline",
+ /* 2 */ "metalines ::=",
+ /* 3 */ "metaline ::= varline",
+ /* 4 */ "metaline ::= global",
+ /* 5 */ "metaline ::= condlines EOL",
+ /* 6 */ "metaline ::= include",
+ /* 7 */ "metaline ::= include_shell",
+ /* 8 */ "metaline ::= EOL",
+ /* 9 */ "varline ::= key ASSIGN expression",
+ /* 10 */ "varline ::= key FORCE_ASSIGN expression",
+ /* 11 */ "varline ::= key APPEND expression",
+ /* 12 */ "key ::= LKEY",
+ /* 13 */ "expression ::= expression PLUS value",
+ /* 14 */ "expression ::= value",
+ /* 15 */ "value ::= key",
+ /* 16 */ "value ::= STRING",
+ /* 17 */ "value ::= INTEGER",
+ /* 18 */ "value ::= array",
+ /* 19 */ "array ::= LPARAN RPARAN",
+ /* 20 */ "array ::= LPARAN aelements RPARAN",
+ /* 21 */ "aelements ::= aelements COMMA aelement",
+ /* 22 */ "aelements ::= aelements COMMA",
+ /* 23 */ "aelements ::= aelement",
+ /* 24 */ "aelement ::= expression",
+ /* 25 */ "aelement ::= stringop ARRAY_ASSIGN expression",
+ /* 26 */ "eols ::= EOL",
+ /* 27 */ "eols ::=",
+ /* 28 */ "globalstart ::= GLOBAL",
+ /* 29 */ "global ::= globalstart LCURLY metalines RCURLY",
+ /* 30 */ "condlines ::= condlines eols ELSE condline",
+ /* 31 */ "condlines ::= condlines eols ELSE cond_else",
+ /* 32 */ "condlines ::= condline",
+ /* 33 */ "condline ::= context LCURLY metalines RCURLY",
+ /* 34 */ "cond_else ::= context_else LCURLY metalines RCURLY",
+ /* 35 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
+ /* 36 */ "context_else ::=",
+ /* 37 */ "cond ::= EQ",
+ /* 38 */ "cond ::= MATCH",
+ /* 39 */ "cond ::= NE",
+ /* 40 */ "cond ::= NOMATCH",
+ /* 41 */ "stringop ::= expression",
+ /* 42 */ "include ::= INCLUDE stringop",
+ /* 43 */ "include_shell ::= INCLUDE_SHELL stringop",
+};
+#endif /* NDEBUG */
+
+/*
+** This function returns the symbolic name associated with a token
+** value.
+*/
+#if 0
+const char *configparserTokenName(int tokenType){
+#ifndef NDEBUG
+ if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
+ return yyTokenName[tokenType];
+ }else{
+ return "Unknown";
+ }
+#else
+ return "";
+#endif
+}
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to configparser and configparserFree.
+*/
+void *configparserAlloc(void *(*mallocProc)(size_t)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ if( pParser ){
+ pParser->yyidx = -1;
+ }
+ return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are not used
+ ** inside the C code.
+ */
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+#line 186 "../../src/configparser.y"
+{ buffer_free((yypminor->yy0)); }
+#line 574 "./configparser.c"
+ break;
+ case 36:
+#line 177 "../../src/configparser.y"
+{ if ((yypminor->yy91)) (yypminor->yy91)->fn->free((yypminor->yy91)); }
+#line 579 "./configparser.c"
+ break;
+ case 37:
+#line 178 "../../src/configparser.y"
+{ if ((yypminor->yy91)) (yypminor->yy91)->fn->free((yypminor->yy91)); }
+#line 584 "./configparser.c"
+ break;
+ case 38:
+#line 179 "../../src/configparser.y"
+{ if ((yypminor->yy91)) (yypminor->yy91)->fn->free((yypminor->yy91)); }
+#line 589 "./configparser.c"
+ break;
+ case 41:
+#line 180 "../../src/configparser.y"
+{ array_free((yypminor->yy42)); }
+#line 594 "./configparser.c"
+ break;
+ case 42:
+#line 181 "../../src/configparser.y"
+{ array_free((yypminor->yy42)); }
+#line 599 "./configparser.c"
+ break;
+ case 43:
+#line 182 "../../src/configparser.y"
+{ buffer_free((yypminor->yy29)); }
+#line 604 "./configparser.c"
+ break;
+ case 44:
+#line 183 "../../src/configparser.y"
+{ buffer_free((yypminor->yy29)); }
+#line 609 "./configparser.c"
+ break;
+ default: break; /* If no destructor action specified: do nothing */
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos;
+
+ if( pParser->yyidx<0 ) return 0;
+ yytos = &pParser->yystack[pParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE && pParser->yyidx>=0 ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yymajor = yytos->major;
+ yy_destructor( yymajor, &yytos->minor);
+ pParser->yyidx--;
+ return yymajor;
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from configparserAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
+*/
+void configparserFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+ if( pParser==NULL ) return;
+ while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ int iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+
+ /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
+ i = yy_shift_ofst[stateno];
+ if( i==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ if( iLookAhead==YYNOCODE ){
+ return YY_NO_ACTION;
+ }
+ i += iLookAhead;
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+ int iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+ yyParser *pParser, /* The parser */
+ int iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+
+ i = yy_reduce_ofst[stateno];
+ if( i==YY_REDUCE_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ if( iLookAhead==YYNOCODE ){
+ return YY_NO_ACTION;
+ }
+ i += iLookAhead;
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yyidx++;
+ if( yypParser->yyidx>=YYSTACKDEPTH ){
+ configparserARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+ configparserARG_STORE; /* Suppress warning about unused %extra_argument var */
+ return;
+ }
+ yytos = &yypParser->yystack[yypParser->yyidx];
+ yytos->stateno = yyNewState;
+ yytos->major = yyMajor;
+ yytos->minor = *yypMinor;
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+ { 28, 1 },
+ { 29, 2 },
+ { 29, 0 },
+ { 30, 1 },
+ { 30, 1 },
+ { 30, 2 },
+ { 30, 1 },
+ { 30, 1 },
+ { 30, 1 },
+ { 31, 3 },
+ { 31, 3 },
+ { 31, 3 },
+ { 43, 1 },
+ { 37, 3 },
+ { 37, 1 },
+ { 36, 1 },
+ { 36, 1 },
+ { 36, 1 },
+ { 36, 1 },
+ { 42, 2 },
+ { 42, 3 },
+ { 41, 3 },
+ { 41, 2 },
+ { 41, 1 },
+ { 38, 1 },
+ { 38, 3 },
+ { 46, 1 },
+ { 46, 0 },
+ { 47, 1 },
+ { 32, 4 },
+ { 33, 4 },
+ { 33, 4 },
+ { 33, 1 },
+ { 39, 4 },
+ { 40, 4 },
+ { 48, 7 },
+ { 49, 0 },
+ { 45, 1 },
+ { 45, 1 },
+ { 45, 1 },
+ { 45, 1 },
+ { 44, 1 },
+ { 34, 2 },
+ { 35, 2 },
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ configparserARG_FETCH;
+ yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE ) {
+ if (yyruleno>=0
+ && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
+ } else {
+ return; /*(should not happen)*/
+ }
+ }
+#endif /* NDEBUG */
+
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+ case 0:
+ /* No destructor defined for metalines */
+ break;
+ case 1:
+ /* No destructor defined for metalines */
+ /* No destructor defined for metaline */
+ break;
+ case 2:
+ break;
+ case 3:
+ /* No destructor defined for varline */
+ break;
+ case 4:
+ /* No destructor defined for global */
+ break;
+ case 5:
+#line 159 "../../src/configparser.y"
+{ yymsp[-1].minor.yy18 = NULL; }
+#line 888 "./configparser.c"
+ yy_destructor(1,&yymsp[0].minor);
+ break;
+ case 6:
+ /* No destructor defined for include */
+ break;
+ case 7:
+ /* No destructor defined for include_shell */
+ break;
+ case 8:
+ yy_destructor(1,&yymsp[0].minor);
+ break;
+ case 9:
+#line 188 "../../src/configparser.y"
+{
+ if (ctx->ok) {
+ buffer_copy_buffer(yymsp[0].minor.yy91->key, yymsp[-2].minor.yy29);
+ if (strncmp(yymsp[-2].minor.yy29->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, yymsp[-2].minor.yy29->ptr);
+ ctx->ok = 0;
+ } else if (NULL == array_get_element_klen(ctx->current->value, CONST_BUF_LEN(yymsp[0].minor.yy91->key))) {
+ array_insert_unique(ctx->current->value, yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+ } else {
+ fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, yymsp[0].minor.yy91->key->ptr);
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(yymsp[-2].minor.yy29);
+ yymsp[-2].minor.yy29 = NULL;
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 925 "./configparser.c"
+ yy_destructor(2,&yymsp[-1].minor);
+ break;
+ case 10:
+#line 212 "../../src/configparser.y"
+{
+ if (ctx->ok) {
+ if (strncmp(yymsp[-2].minor.yy29->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, yymsp[-2].minor.yy29->ptr);
+ ctx->ok = 0;
+ } else {
+ buffer_copy_buffer(yymsp[0].minor.yy91->key, yymsp[-2].minor.yy29);
+ array_replace(ctx->current->value, yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+ }
+ }
+ buffer_free(yymsp[-2].minor.yy29);
+ yymsp[-2].minor.yy29 = NULL;
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 948 "./configparser.c"
+ yy_destructor(3,&yymsp[-1].minor);
+ break;
+ case 11:
+#line 231 "../../src/configparser.y"
+{
+ if (ctx->ok) {
+ array *vars = ctx->current->value;
+ data_unset *du;
+
+ if (strncmp(yymsp[-2].minor.yy29->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, yymsp[-2].minor.yy29->ptr);
+ ctx->ok = 0;
+ } else if (NULL != (du = array_extract_element_klen(vars, CONST_BUF_LEN(yymsp[-2].minor.yy29))) || NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy29))) {
+ du = configparser_merge_data(du, yymsp[0].minor.yy91);
+ if (NULL == du) {
+ ctx->ok = 0;
+ }
+ else {
+ buffer_copy_buffer(du->key, yymsp[-2].minor.yy29);
+ array_insert_unique(ctx->current->value, du);
+ }
+ } else {
+ buffer_copy_buffer(yymsp[0].minor.yy91->key, yymsp[-2].minor.yy29);
+ array_insert_unique(ctx->current->value, yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+ }
+ }
+ buffer_free(yymsp[-2].minor.yy29);
+ yymsp[-2].minor.yy29 = NULL;
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 983 "./configparser.c"
+ yy_destructor(4,&yymsp[-1].minor);
+ break;
+ case 12:
+#line 262 "../../src/configparser.y"
+{
+ if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
+ yygotominor.yy29 = buffer_init_string("var.");
+ buffer_append_string_buffer(yygotominor.yy29, yymsp[0].minor.yy0);
+ } else {
+ yygotominor.yy29 = yymsp[0].minor.yy0;
+ yymsp[0].minor.yy0 = NULL;
+ }
+ buffer_free(yymsp[0].minor.yy0);
+ yymsp[0].minor.yy0 = NULL;
+}
+#line 999 "./configparser.c"
+ break;
+ case 13:
+#line 274 "../../src/configparser.y"
+{
+ yygotominor.yy91 = NULL;
+ if (ctx->ok) {
+ yygotominor.yy91 = configparser_merge_data(yymsp[-2].minor.yy91, yymsp[0].minor.yy91);
+ yymsp[-2].minor.yy91 = NULL;
+ if (NULL == yygotominor.yy91) {
+ ctx->ok = 0;
+ }
+ }
+ if (yymsp[-2].minor.yy91) yymsp[-2].minor.yy91->fn->free(yymsp[-2].minor.yy91);
+ yymsp[-2].minor.yy91 = NULL;
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1017 "./configparser.c"
+ yy_destructor(6,&yymsp[-1].minor);
+ break;
+ case 14:
+#line 289 "../../src/configparser.y"
+{
+ yygotominor.yy91 = yymsp[0].minor.yy91;
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1026 "./configparser.c"
+ break;
+ case 15:
+#line 294 "../../src/configparser.y"
+{
+ yygotominor.yy91 = NULL;
+ if (ctx->ok) {
+ if (strncmp(yymsp[0].minor.yy29->ptr, "env.", sizeof("env.") - 1) == 0) {
+ char *env;
+
+ if (NULL != (env = getenv(yymsp[0].minor.yy29->ptr + 4))) {
+ data_string *ds;
+ ds = data_string_init();
+ buffer_append_string(ds->value, env);
+ yygotominor.yy91 = (data_unset *)ds;
+ }
+ else {
+ fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy29->ptr + 4);
+ ctx->ok = 0;
+ }
+ } else if (NULL == (yygotominor.yy91 = configparser_get_variable(ctx, yymsp[0].minor.yy29))) {
+ fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy29->ptr);
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(yymsp[0].minor.yy29);
+ yymsp[0].minor.yy29 = NULL;
+}
+#line 1054 "./configparser.c"
+ break;
+ case 16:
+#line 319 "../../src/configparser.y"
+{
+ buffer *b;
+ yygotominor.yy91 = (data_unset *)data_string_init();
+ b = ((data_string *)(yygotominor.yy91))->value;
+ buffer_free(b);
+ ((data_string *)(yygotominor.yy91))->value = yymsp[0].minor.yy0;
+ yymsp[0].minor.yy0 = NULL;
+}
+#line 1066 "./configparser.c"
+ break;
+ case 17:
+#line 328 "../../src/configparser.y"
+{
+ char *endptr;
+ yygotominor.yy91 = (data_unset *)data_integer_init();
+ errno = 0;
+ ((data_integer *)(yygotominor.yy91))->value = strtol(yymsp[0].minor.yy0->ptr, &endptr, 10);
+ /* skip trailing whitespace */
+ if (endptr != yymsp[0].minor.yy0->ptr) while (isspace(*endptr)) endptr++;
+ if (0 != errno || *endptr != '\0') {
+ fprintf(stderr, "error parsing number: '%s'\n", yymsp[0].minor.yy0->ptr);
+ ctx->ok = 0;
+ }
+ buffer_free(yymsp[0].minor.yy0);
+ yymsp[0].minor.yy0 = NULL;
+}
+#line 1084 "./configparser.c"
+ break;
+ case 18:
+#line 342 "../../src/configparser.y"
+{
+ yygotominor.yy91 = (data_unset *)data_array_init();
+ array_free(((data_array *)(yygotominor.yy91))->value);
+ ((data_array *)(yygotominor.yy91))->value = yymsp[0].minor.yy42;
+ yymsp[0].minor.yy42 = NULL;
+}
+#line 1094 "./configparser.c"
+ break;
+ case 19:
+#line 348 "../../src/configparser.y"
+{
+ yygotominor.yy42 = array_init();
+}
+#line 1101 "./configparser.c"
+ yy_destructor(9,&yymsp[-1].minor);
+ yy_destructor(10,&yymsp[0].minor);
+ break;
+ case 20:
+#line 351 "../../src/configparser.y"
+{
+ yygotominor.yy42 = yymsp[-1].minor.yy42;
+ yymsp[-1].minor.yy42 = NULL;
+}
+#line 1111 "./configparser.c"
+ yy_destructor(9,&yymsp[-2].minor);
+ yy_destructor(10,&yymsp[0].minor);
+ break;
+ case 21:
+#line 356 "../../src/configparser.y"
+{
+ yygotominor.yy42 = NULL;
+ if (ctx->ok) {
+ if (buffer_is_empty(yymsp[0].minor.yy91->key) ||
+ NULL == array_get_element_klen(yymsp[-2].minor.yy42, CONST_BUF_LEN(yymsp[0].minor.yy91->key))) {
+ array_insert_unique(yymsp[-2].minor.yy42, yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+ } else {
+ fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
+ yymsp[0].minor.yy91->key->ptr);
+ ctx->ok = 0;
+ }
+
+ yygotominor.yy42 = yymsp[-2].minor.yy42;
+ yymsp[-2].minor.yy42 = NULL;
+ }
+ array_free(yymsp[-2].minor.yy42);
+ yymsp[-2].minor.yy42 = NULL;
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1138 "./configparser.c"
+ yy_destructor(11,&yymsp[-1].minor);
+ break;
+ case 22:
+#line 378 "../../src/configparser.y"
+{
+ yygotominor.yy42 = yymsp[-1].minor.yy42;
+ yymsp[-1].minor.yy42 = NULL;
+}
+#line 1147 "./configparser.c"
+ yy_destructor(11,&yymsp[0].minor);
+ break;
+ case 23:
+#line 383 "../../src/configparser.y"
+{
+ yygotominor.yy42 = NULL;
+ if (ctx->ok) {
+ yygotominor.yy42 = array_init();
+ array_insert_unique(yygotominor.yy42, yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+ }
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1162 "./configparser.c"
+ break;
+ case 24:
+#line 394 "../../src/configparser.y"
+{
+ yygotominor.yy91 = yymsp[0].minor.yy91;
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1170 "./configparser.c"
+ break;
+ case 25:
+#line 398 "../../src/configparser.y"
+{
+ yygotominor.yy91 = NULL;
+ if (ctx->ok) {
+ buffer_copy_buffer(yymsp[0].minor.yy91->key, yymsp[-2].minor.yy29);
+
+ yygotominor.yy91 = yymsp[0].minor.yy91;
+ yymsp[0].minor.yy91 = NULL;
+ }
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+ buffer_free(yymsp[-2].minor.yy29);
+ yymsp[-2].minor.yy29 = NULL;
+}
+#line 1187 "./configparser.c"
+ yy_destructor(12,&yymsp[-1].minor);
+ break;
+ case 26:
+ yy_destructor(1,&yymsp[0].minor);
+ break;
+ case 27:
+ break;
+ case 28:
+#line 415 "../../src/configparser.y"
+{
+ data_config *dc;
+ dc = (data_config *)array_get_element_klen(ctx->srv->config_context, CONST_STR_LEN("global"));
+ force_assert(dc);
+ configparser_push(ctx, dc, 0);
+}
+#line 1203 "./configparser.c"
+ yy_destructor(13,&yymsp[0].minor);
+ break;
+ case 29:
+#line 422 "../../src/configparser.y"
+{
+ force_assert(ctx->current);
+ configparser_pop(ctx);
+ force_assert(ctx->current);
+}
+#line 1213 "./configparser.c"
+ /* No destructor defined for globalstart */
+ yy_destructor(14,&yymsp[-2].minor);
+ /* No destructor defined for metalines */
+ yy_destructor(15,&yymsp[0].minor);
+ break;
+ case 30:
+#line 428 "../../src/configparser.y"
+{
+ yygotominor.yy18 = NULL;
+ if (ctx->ok) {
+ if (yymsp[-3].minor.yy18->context_ndx >= yymsp[0].minor.yy18->context_ndx) {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ }
+ if (yymsp[-3].minor.yy18->cond == CONFIG_COND_ELSE) {
+ fprintf(stderr, "unreachable condition following else catch-all\n");
+ ctx->ok = 0;
+ }
+ yymsp[0].minor.yy18->prev = yymsp[-3].minor.yy18;
+ yymsp[-3].minor.yy18->next = yymsp[0].minor.yy18;
+ yygotominor.yy18 = yymsp[0].minor.yy18;
+ }
+ yymsp[-3].minor.yy18 = NULL;
+ yymsp[0].minor.yy18 = NULL;
+}
+#line 1239 "./configparser.c"
+ /* No destructor defined for eols */
+ yy_destructor(16,&yymsp[-1].minor);
+ break;
+ case 31:
+#line 447 "../../src/configparser.y"
+{
+ yygotominor.yy18 = NULL;
+ if (ctx->ok) {
+ if (yymsp[-3].minor.yy18->context_ndx >= yymsp[0].minor.yy18->context_ndx) {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ }
+ if (yymsp[-3].minor.yy18->cond == CONFIG_COND_ELSE) {
+ fprintf(stderr, "unreachable condition following else catch-all\n");
+ ctx->ok = 0;
+ }
+ }
+ if (ctx->ok) {
+ size_t pos;
+ data_config *dc;
+ dc = (data_config *)array_extract_element_klen(ctx->all_configs, CONST_BUF_LEN(yymsp[0].minor.yy18->key));
+ force_assert(yymsp[0].minor.yy18 == dc);
+ buffer_copy_buffer(yymsp[0].minor.yy18->key, yymsp[-3].minor.yy18->key);
+ yymsp[0].minor.yy18->comp = yymsp[-3].minor.yy18->comp;
+ /*buffer_copy_buffer(yymsp[0].minor.yy18->comp_key, yymsp[-3].minor.yy18->comp_key);*/
+ /*yymsp[0].minor.yy18->string = buffer_init_buffer(yymsp[-3].minor.yy18->string);*/
+ pos = buffer_string_length(yymsp[0].minor.yy18->key)-buffer_string_length(yymsp[-3].minor.yy18->string)-2;
+ switch(yymsp[-3].minor.yy18->cond) {
+ case CONFIG_COND_NE:
+ yymsp[0].minor.yy18->key->ptr[pos] = '='; /* opposite cond */
+ /*buffer_copy_string_len(yymsp[0].minor.yy18->op, CONST_STR_LEN("=="));*/
+ break;
+ case CONFIG_COND_EQ:
+ yymsp[0].minor.yy18->key->ptr[pos] = '!'; /* opposite cond */
+ /*buffer_copy_string_len(yymsp[0].minor.yy18->op, CONST_STR_LEN("!="));*/
+ break;
+ case CONFIG_COND_NOMATCH:
+ yymsp[0].minor.yy18->key->ptr[pos] = '='; /* opposite cond */
+ /*buffer_copy_string_len(yymsp[0].minor.yy18->op, CONST_STR_LEN("=~"));*/
+ break;
+ case CONFIG_COND_MATCH:
+ yymsp[0].minor.yy18->key->ptr[pos] = '!'; /* opposite cond */
+ /*buffer_copy_string_len(yymsp[0].minor.yy18->op, CONST_STR_LEN("!~"));*/
+ break;
+ default: /* should not happen; CONFIG_COND_ELSE checked further above */
+ force_assert(0);
+ }
+
+ if (NULL == (dc = (data_config *)array_get_element_klen(ctx->all_configs, CONST_BUF_LEN(yymsp[0].minor.yy18->key)))) {
+ /* re-insert into ctx->all_configs with new yymsp[0].minor.yy18->key */
+ array_insert_unique(ctx->all_configs, (data_unset *)yymsp[0].minor.yy18);
+ yymsp[0].minor.yy18->prev = yymsp[-3].minor.yy18;
+ yymsp[-3].minor.yy18->next = yymsp[0].minor.yy18;
+ } else {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ yymsp[0].minor.yy18->fn->free((data_unset *)yymsp[0].minor.yy18);
+ yymsp[0].minor.yy18 = dc;
+ }
+
+ yygotominor.yy18 = yymsp[0].minor.yy18;
+ }
+ yymsp[-3].minor.yy18 = NULL;
+ yymsp[0].minor.yy18 = NULL;
+}
+#line 1305 "./configparser.c"
+ /* No destructor defined for eols */
+ yy_destructor(16,&yymsp[-1].minor);
+ break;
+ case 32:
+#line 508 "../../src/configparser.y"
+{
+ yygotominor.yy18 = yymsp[0].minor.yy18;
+ yymsp[0].minor.yy18 = NULL;
+}
+#line 1315 "./configparser.c"
+ break;
+ case 33:
+#line 513 "../../src/configparser.y"
+{
+ yygotominor.yy18 = NULL;
+ if (ctx->ok) {
+ data_config *cur;
+
+ cur = ctx->current;
+ configparser_pop(ctx);
+
+ force_assert(cur && ctx->current);
+
+ yygotominor.yy18 = cur;
+ }
+}
+#line 1332 "./configparser.c"
+ /* No destructor defined for context */
+ yy_destructor(14,&yymsp[-2].minor);
+ /* No destructor defined for metalines */
+ yy_destructor(15,&yymsp[0].minor);
+ break;
+ case 34:
+#line 527 "../../src/configparser.y"
+{
+ yygotominor.yy18 = NULL;
+ if (ctx->ok) {
+ data_config *cur;
+
+ cur = ctx->current;
+ configparser_pop(ctx);
+
+ force_assert(cur && ctx->current);
+
+ yygotominor.yy18 = cur;
+ }
+}
+#line 1353 "./configparser.c"
+ /* No destructor defined for context_else */
+ yy_destructor(14,&yymsp[-2].minor);
+ /* No destructor defined for metalines */
+ yy_destructor(15,&yymsp[0].minor);
+ break;
+ case 35:
+#line 541 "../../src/configparser.y"
+{
+ data_config *dc;
+ buffer *b = NULL, *rvalue, *op = NULL;
+
+ if (ctx->ok && yymsp[0].minor.yy91->type != TYPE_STRING) {
+ fprintf(stderr, "rvalue must be string");
+ ctx->ok = 0;
+ }
+
+ if (ctx->ok) {
+ switch(yymsp[-1].minor.yy53) {
+ case CONFIG_COND_NE:
+ op = buffer_init_string("!=");
+ break;
+ case CONFIG_COND_EQ:
+ op = buffer_init_string("==");
+ break;
+ case CONFIG_COND_NOMATCH:
+ op = buffer_init_string("!~");
+ break;
+ case CONFIG_COND_MATCH:
+ op = buffer_init_string("=~");
+ break;
+ default:
+ force_assert(0);
+ return; /* unreachable */
+ }
+
+ b = buffer_init();
+ buffer_copy_buffer(b, ctx->current->key);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_string_buffer(b, yymsp[-5].minor.yy0);
+ buffer_append_string_buffer(b, yymsp[-3].minor.yy29);
+ buffer_append_string_buffer(b, op);
+ rvalue = ((data_string*)yymsp[0].minor.yy91)->value;
+ buffer_append_string_buffer(b, rvalue);
+
+ if (NULL != (dc = (data_config *)array_get_element_klen(ctx->all_configs, CONST_BUF_LEN(b)))) {
+ configparser_push(ctx, dc, 0);
+ } else {
+ static const struct {
+ comp_key_t comp;
+ char *comp_key;
+ size_t len;
+ } comps[] = {
+ { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
+ { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
+ { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
+ { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"referer\"]" ) },
+ { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
+ { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
+ { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
+ { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"cookie\"]" ) },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
+ { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
+ { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
+ { COMP_UNSET, NULL, 0 },
+ };
+ size_t i;
+
+ dc = data_config_init();
+
+ buffer_copy_buffer(dc->key, b);
+ buffer_copy_buffer(dc->op, op);
+ buffer_copy_buffer(dc->comp_tag, yymsp[-3].minor.yy29);
+ buffer_copy_buffer(dc->comp_key, yymsp[-5].minor.yy0);
+ buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
+ buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy29);
+ buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
+ dc->cond = yymsp[-1].minor.yy53;
+
+ for (i = 0; comps[i].comp_key; i ++) {
+ if (buffer_is_equal_string(
+ dc->comp_key, comps[i].comp_key, comps[i].len)) {
+ dc->comp = comps[i].comp;
+ break;
+ }
+ }
+ if (COMP_UNSET == dc->comp) {
+ if (buffer_is_equal_string(yymsp[-5].minor.yy0, CONST_STR_LEN("REQUEST_HEADER"))) {
+ dc->comp = COMP_HTTP_REQUEST_HEADER;
+ }
+ else {
+ fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
+ ctx->ok = 0;
+ }
+ }
+ else if (COMP_HTTP_LANGUAGE == dc->comp) {
+ dc->comp = COMP_HTTP_REQUEST_HEADER;
+ buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("Accept-Language"));
+ }
+ else if (COMP_HTTP_USER_AGENT == dc->comp) {
+ dc->comp = COMP_HTTP_REQUEST_HEADER;
+ buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("User-Agent"));
+ }
+ else if (COMP_HTTP_REMOTE_IP == dc->comp
+ && (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) {
+ char * const slash = strchr(rvalue->ptr, '/'); /* CIDR mask */
+ char * const colon = strchr(rvalue->ptr, ':'); /* IPv6 */
+ if (NULL != slash && slash == rvalue->ptr){/*(skip AF_UNIX /path/file)*/
+ }
+ else if (NULL != slash) {
+ char *nptr;
+ const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10);
+ if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) {
+ /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/
+ fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ else {
+ int rc;
+ buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/
+ rc = (NULL == colon)
+ ? http_request_host_normalize(rvalue, 0)
+ : configparser_remoteip_normalize_compat(rvalue);
+ buffer_append_string_len(rvalue, CONST_STR_LEN("/"));
+ buffer_append_int(rvalue, (int)nm_bits);
+ if (0 != rc) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+ else {
+ int rc = (NULL == colon)
+ ? http_request_host_normalize(rvalue, 0)
+ : configparser_remoteip_normalize_compat(rvalue);
+ if (0 != rc) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+ else if (COMP_SERVER_SOCKET == dc->comp) {
+ /*(redundant with parsing in network.c; not actually required here)*/
+ if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/
+ && !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) {
+ if (http_request_host_normalize(rvalue, 0)) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+ else if (COMP_HTTP_HOST == dc->comp) {
+ if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) {
+ if (http_request_host_normalize(rvalue, 0)) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+
+ dc->string = buffer_init_buffer(rvalue);
+
+ if (ctx->ok) switch(yymsp[-1].minor.yy53) {
+ case CONFIG_COND_NE:
+ case CONFIG_COND_EQ:
+ break;
+ case CONFIG_COND_NOMATCH:
+ case CONFIG_COND_MATCH: {
+ if (!data_config_pcre_compile(dc)) {
+ ctx->ok = 0;
+ }
+ break;
+ }
+
+ default:
+ fprintf(stderr, "unknown condition for $%s[%s]\n",
+ yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy29->ptr);
+ ctx->ok = 0;
+ break;
+ }
+
+ if (ctx->ok) {
+ configparser_push(ctx, dc, 1);
+ } else {
+ dc->fn->free((data_unset*) dc);
+ }
+ }
+ }
+
+ buffer_free(b);
+ buffer_free(op);
+ buffer_free(yymsp[-5].minor.yy0);
+ yymsp[-5].minor.yy0 = NULL;
+ buffer_free(yymsp[-3].minor.yy29);
+ yymsp[-3].minor.yy29 = NULL;
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1554 "./configparser.c"
+ yy_destructor(17,&yymsp[-6].minor);
+ yy_destructor(19,&yymsp[-4].minor);
+ yy_destructor(20,&yymsp[-2].minor);
+ break;
+ case 36:
+#line 735 "../../src/configparser.y"
+{
+ if (ctx->ok) {
+ data_config *dc = data_config_init();
+ buffer_copy_buffer(dc->key, ctx->current->key);
+ buffer_append_string_len(dc->key, CONST_STR_LEN("/"));
+ buffer_append_string_len(dc->key, CONST_STR_LEN("else_tmp_token"));
+ dc->cond = CONFIG_COND_ELSE;
+ configparser_push(ctx, dc, 1);
+ }
+}
+#line 1571 "./configparser.c"
+ break;
+ case 37:
+#line 746 "../../src/configparser.y"
+{
+ yygotominor.yy53 = CONFIG_COND_EQ;
+}
+#line 1578 "./configparser.c"
+ yy_destructor(21,&yymsp[0].minor);
+ break;
+ case 38:
+#line 749 "../../src/configparser.y"
+{
+ yygotominor.yy53 = CONFIG_COND_MATCH;
+}
+#line 1586 "./configparser.c"
+ yy_destructor(22,&yymsp[0].minor);
+ break;
+ case 39:
+#line 752 "../../src/configparser.y"
+{
+ yygotominor.yy53 = CONFIG_COND_NE;
+}
+#line 1594 "./configparser.c"
+ yy_destructor(23,&yymsp[0].minor);
+ break;
+ case 40:
+#line 755 "../../src/configparser.y"
+{
+ yygotominor.yy53 = CONFIG_COND_NOMATCH;
+}
+#line 1602 "./configparser.c"
+ yy_destructor(24,&yymsp[0].minor);
+ break;
+ case 41:
+#line 759 "../../src/configparser.y"
+{
+ yygotominor.yy29 = NULL;
+ if (ctx->ok) {
+ if (yymsp[0].minor.yy91->type == TYPE_STRING) {
+ yygotominor.yy29 = ((data_string*)yymsp[0].minor.yy91)->value;
+ ((data_string*)yymsp[0].minor.yy91)->value = NULL;
+ } else if (yymsp[0].minor.yy91->type == TYPE_INTEGER) {
+ yygotominor.yy29 = buffer_init();
+ buffer_copy_int(yygotominor.yy29, ((data_integer *)yymsp[0].minor.yy91)->value);
+ } else {
+ fprintf(stderr, "operand must be string");
+ ctx->ok = 0;
+ }
+ }
+ if (yymsp[0].minor.yy91) yymsp[0].minor.yy91->fn->free(yymsp[0].minor.yy91);
+ yymsp[0].minor.yy91 = NULL;
+}
+#line 1624 "./configparser.c"
+ break;
+ case 42:
+#line 777 "../../src/configparser.y"
+{
+ if (ctx->ok) {
+ if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy29->ptr)) {
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(yymsp[0].minor.yy29);
+ yymsp[0].minor.yy29 = NULL;
+}
+#line 1637 "./configparser.c"
+ yy_destructor(25,&yymsp[-1].minor);
+ break;
+ case 43:
+#line 787 "../../src/configparser.y"
+{
+ if (ctx->ok) {
+ if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy29->ptr)) {
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(yymsp[0].minor.yy29);
+ yymsp[0].minor.yy29 = NULL;
+}
+#line 1651 "./configparser.c"
+ yy_destructor(26,&yymsp[-1].minor);
+ break;
+ };
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ yypParser->yyidx -= yysize;
+ yyact = yy_find_reduce_action(yypParser,yygoto);
+ if( yyact < YYNSTATE ){
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ configparserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+#line 150 "../../src/configparser.y"
+
+ ctx->ok = 0;
+
+#line 1685 "./configparser.c"
+ configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
+){
+ configparserARG_FETCH;
+ UNUSED(yymajor);
+ UNUSED(yyminor);
+#define TOKEN (yyminor.yy0)
+ configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ configparserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+ configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "configparserAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void configparser(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ configparserTOKENTYPE yyminor /* The value for the token */
+ configparserARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ int yyact; /* The parser action. */
+ int yyendofinput; /* True if we are at the end of input */
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+ yyParser *yypParser; /* The parser */
+
+ /* (re)initialize the parser, if necessary */
+ yypParser = (yyParser*)yyp;
+ if( yypParser->yyidx<0 ){
+ if( yymajor==0 ) return;
+ yypParser->yyidx = 0;
+ yypParser->yyerrcnt = -1;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+ }
+ yyminorunion.yy0 = yyminor;
+ yyendofinput = (yymajor==0);
+ configparserARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,yymajor);
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yypParser->yyerrcnt--;
+ if( yyendofinput && yypParser->yyidx>=0 ){
+ yymajor = 0;
+ }else{
+ yymajor = YYNOCODE;
+ }
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
+ }else if( yyact == YY_ERROR_ACTION ){
+ int yymx;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yymx = yypParser->yystack[yypParser->yyidx].major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while(
+ yypParser->yyidx >= 0 &&
+ yymx != YYERRORSYMBOL &&
+ (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yyidx < 0 || yymajor==0 ){
+ yy_destructor(yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ }
+ }
+ yypParser->yyerrcnt = 3;
+ yyerrorhit = 1;
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yypParser->yyerrcnt = 3;
+ yy_destructor(yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+ }
+ yymajor = YYNOCODE;
+#endif
+ }else{
+ yy_accept(yypParser);
+ yymajor = YYNOCODE;
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ return;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/configparser.h b/data/lighttpd/lighttpd-1.4.53/src/configparser.h
new file mode 100644
index 000000000..b052c01fd
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/configparser.h
@@ -0,0 +1,26 @@
+#define TK_EOL 1
+#define TK_ASSIGN 2
+#define TK_FORCE_ASSIGN 3
+#define TK_APPEND 4
+#define TK_LKEY 5
+#define TK_PLUS 6
+#define TK_STRING 7
+#define TK_INTEGER 8
+#define TK_LPARAN 9
+#define TK_RPARAN 10
+#define TK_COMMA 11
+#define TK_ARRAY_ASSIGN 12
+#define TK_GLOBAL 13
+#define TK_LCURLY 14
+#define TK_RCURLY 15
+#define TK_ELSE 16
+#define TK_DOLLAR 17
+#define TK_SRVVARNAME 18
+#define TK_LBRACKET 19
+#define TK_RBRACKET 20
+#define TK_EQ 21
+#define TK_MATCH 22
+#define TK_NE 23
+#define TK_NOMATCH 24
+#define TK_INCLUDE 25
+#define TK_INCLUDE_SHELL 26
diff --git a/data/lighttpd/lighttpd-1.4.53/src/configparser.y b/data/lighttpd/lighttpd-1.4.53/src/configparser.y
new file mode 100644
index 000000000..9e49ad733
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/configparser.y
@@ -0,0 +1,795 @@
+%token_prefix TK_
+%extra_argument {config_t *ctx}
+%name configparser
+
+%include {
+#include "first.h"
+#include "base.h"
+#include "configfile.h"
+#include "buffer.h"
+#include "array.h"
+#include "request.h" /* http_request_host_normalize() */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
+ if (isnew) {
+ dc->context_ndx = ctx->all_configs->used;
+ force_assert(dc->context_ndx > ctx->current->context_ndx);
+ array_insert_unique(ctx->all_configs, (data_unset *)dc);
+ dc->parent = ctx->current;
+ vector_config_weak_push(&dc->parent->children, dc);
+ }
+ if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) {
+ fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
+ exit(-1);
+ }
+ vector_config_weak_push(&ctx->configs_stack, ctx->current);
+ ctx->current = dc;
+}
+
+static data_config *configparser_pop(config_t *ctx) {
+ data_config *old = ctx->current;
+ ctx->current = vector_config_weak_pop(&ctx->configs_stack);
+ return old;
+}
+
+/* return a copied variable */
+static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
+ data_unset *du;
+ data_config *dc;
+
+#if 0
+ fprintf(stderr, "get var %s\n", key->ptr);
+#endif
+ for (dc = ctx->current; dc; dc = dc->parent) {
+#if 0
+ fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
+ array_print(dc->value, 0);
+#endif
+ if (NULL != (du = array_get_element_klen(dc->value, CONST_BUF_LEN(key)))) {
+ du = du->fn->copy(du);
+ buffer_clear(du->key);
+ return du;
+ }
+ }
+ return NULL;
+}
+
+/* op1 is to be eat/return by this function if success, op1->key is not cared
+ op2 is left untouch, unreferenced
+ */
+data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
+ /* type mismatch */
+ if (op1->type != op2->type) {
+ if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
+ data_string *ds = (data_string *)op1;
+ buffer_append_int(ds->value, ((data_integer*)op2)->value);
+ return op1;
+ } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
+ data_string *ds = data_string_init();
+ buffer_append_int(ds->value, ((data_integer*)op1)->value);
+ buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
+ op1->fn->free(op1);
+ return (data_unset *)ds;
+ } else {
+ fprintf(stderr, "data type mismatch, cannot merge\n");
+ op1->fn->free(op1);
+ return NULL;
+ }
+ }
+
+ switch (op1->type) {
+ case TYPE_STRING:
+ buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
+ break;
+ case TYPE_INTEGER:
+ ((data_integer *)op1)->value += ((data_integer *)op2)->value;
+ break;
+ case TYPE_ARRAY: {
+ array *dst = ((data_array *)op1)->value;
+ array *src = ((data_array *)op2)->value;
+ data_unset *du;
+ size_t i;
+
+ for (i = 0; i < src->used; i ++) {
+ du = (data_unset *)src->data[i];
+ if (du) {
+ if (du->is_index_key || buffer_is_empty(du->key) || !array_get_element_klen(dst, CONST_BUF_LEN(du->key))) {
+ array_insert_unique(dst, du->fn->copy(du));
+ } else {
+ fprintf(stderr, "Duplicate array-key '%s'\n", du->key->ptr);
+ op1->fn->free(op1);
+ return NULL;
+ }
+ }
+ }
+ break;
+ default:
+ force_assert(0);
+ break;
+ }
+ }
+ return op1;
+}
+
+static int configparser_remoteip_normalize_compat(buffer *rvalue) {
+ /* $HTTP["remoteip"] IPv6 accepted with or without '[]' for config compat
+ * http_request_host_normalize() expects IPv6 with '[]',
+ * and config processing at runtime expects COMP_HTTP_REMOTE_IP
+ * compared without '[]', so strip '[]' after normalization */
+ buffer *b = buffer_init();
+ int rc;
+
+ if (rvalue->ptr[0] != '[') {
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ buffer_append_string_buffer(b, rvalue);
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ } else {
+ buffer_append_string_buffer(b, rvalue);
+ }
+
+ rc = http_request_host_normalize(b, 0);
+
+ if (0 == rc) {
+ /* remove surrounding '[]' */
+ size_t blen = buffer_string_length(b);
+ if (blen > 1) buffer_copy_string_len(rvalue, b->ptr+1, blen-2);
+ }
+
+ buffer_free(b);
+ return rc;
+}
+
+}
+
+%parse_failure {
+ ctx->ok = 0;
+}
+
+input ::= metalines.
+metalines ::= metalines metaline.
+metalines ::= .
+metaline ::= varline.
+metaline ::= global.
+metaline ::= condlines(A) EOL. { A = NULL; }
+metaline ::= include.
+metaline ::= include_shell.
+metaline ::= EOL.
+
+%type value {data_unset *}
+%type expression {data_unset *}
+%type aelement {data_unset *}
+%type condline {data_config *}
+%type cond_else {data_config *}
+%type condlines {data_config *}
+%type aelements {array *}
+%type array {array *}
+%type key {buffer *}
+%type stringop {buffer *}
+
+%type cond {config_cond_t }
+
+%destructor value { if ($$) $$->fn->free($$); }
+%destructor expression { if ($$) $$->fn->free($$); }
+%destructor aelement { if ($$) $$->fn->free($$); }
+%destructor aelements { array_free($$); }
+%destructor array { array_free($$); }
+%destructor key { buffer_free($$); }
+%destructor stringop { buffer_free($$); }
+
+%token_type {buffer *}
+%token_destructor { buffer_free($$); }
+
+varline ::= key(A) ASSIGN expression(B). {
+ if (ctx->ok) {
+ buffer_copy_buffer(B->key, A);
+ if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, A->ptr);
+ ctx->ok = 0;
+ } else if (NULL == array_get_element_klen(ctx->current->value, CONST_BUF_LEN(B->key))) {
+ array_insert_unique(ctx->current->value, B);
+ B = NULL;
+ } else {
+ fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, B->key->ptr);
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(A);
+ A = NULL;
+ if (B) B->fn->free(B);
+ B = NULL;
+}
+
+varline ::= key(A) FORCE_ASSIGN expression(B). {
+ if (ctx->ok) {
+ if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, A->ptr);
+ ctx->ok = 0;
+ } else {
+ buffer_copy_buffer(B->key, A);
+ array_replace(ctx->current->value, B);
+ B = NULL;
+ }
+ }
+ buffer_free(A);
+ A = NULL;
+ if (B) B->fn->free(B);
+ B = NULL;
+}
+
+varline ::= key(A) APPEND expression(B). {
+ if (ctx->ok) {
+ array *vars = ctx->current->value;
+ data_unset *du;
+
+ if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, A->ptr);
+ ctx->ok = 0;
+ } else if (NULL != (du = array_extract_element_klen(vars, CONST_BUF_LEN(A))) || NULL != (du = configparser_get_variable(ctx, A))) {
+ du = configparser_merge_data(du, B);
+ if (NULL == du) {
+ ctx->ok = 0;
+ }
+ else {
+ buffer_copy_buffer(du->key, A);
+ array_insert_unique(ctx->current->value, du);
+ }
+ } else {
+ buffer_copy_buffer(B->key, A);
+ array_insert_unique(ctx->current->value, B);
+ B = NULL;
+ }
+ }
+ buffer_free(A);
+ A = NULL;
+ if (B) B->fn->free(B);
+ B = NULL;
+}
+
+key(A) ::= LKEY(B). {
+ if (strchr(B->ptr, '.') == NULL) {
+ A = buffer_init_string("var.");
+ buffer_append_string_buffer(A, B);
+ } else {
+ A = B;
+ B = NULL;
+ }
+ buffer_free(B);
+ B = NULL;
+}
+
+expression(A) ::= expression(B) PLUS value(C). {
+ A = NULL;
+ if (ctx->ok) {
+ A = configparser_merge_data(B, C);
+ B = NULL;
+ if (NULL == A) {
+ ctx->ok = 0;
+ }
+ }
+ if (B) B->fn->free(B);
+ B = NULL;
+ if (C) C->fn->free(C);
+ C = NULL;
+}
+
+expression(A) ::= value(B). {
+ A = B;
+ B = NULL;
+}
+
+value(A) ::= key(B). {
+ A = NULL;
+ if (ctx->ok) {
+ if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
+ char *env;
+
+ if (NULL != (env = getenv(B->ptr + 4))) {
+ data_string *ds;
+ ds = data_string_init();
+ buffer_append_string(ds->value, env);
+ A = (data_unset *)ds;
+ }
+ else {
+ fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
+ ctx->ok = 0;
+ }
+ } else if (NULL == (A = configparser_get_variable(ctx, B))) {
+ fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(B);
+ B = NULL;
+}
+
+value(A) ::= STRING(B). {
+ buffer *b;
+ A = (data_unset *)data_string_init();
+ b = ((data_string *)(A))->value;
+ buffer_free(b);
+ ((data_string *)(A))->value = B;
+ B = NULL;
+}
+
+value(A) ::= INTEGER(B). {
+ char *endptr;
+ A = (data_unset *)data_integer_init();
+ errno = 0;
+ ((data_integer *)(A))->value = strtol(B->ptr, &endptr, 10);
+ /* skip trailing whitespace */
+ if (endptr != B->ptr) while (isspace(*endptr)) endptr++;
+ if (0 != errno || *endptr != '\0') {
+ fprintf(stderr, "error parsing number: '%s'\n", B->ptr);
+ ctx->ok = 0;
+ }
+ buffer_free(B);
+ B = NULL;
+}
+value(A) ::= array(B). {
+ A = (data_unset *)data_array_init();
+ array_free(((data_array *)(A))->value);
+ ((data_array *)(A))->value = B;
+ B = NULL;
+}
+array(A) ::= LPARAN RPARAN. {
+ A = array_init();
+}
+array(A) ::= LPARAN aelements(B) RPARAN. {
+ A = B;
+ B = NULL;
+}
+
+aelements(A) ::= aelements(C) COMMA aelement(B). {
+ A = NULL;
+ if (ctx->ok) {
+ if (buffer_is_empty(B->key) ||
+ NULL == array_get_element_klen(C, CONST_BUF_LEN(B->key))) {
+ array_insert_unique(C, B);
+ B = NULL;
+ } else {
+ fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
+ B->key->ptr);
+ ctx->ok = 0;
+ }
+
+ A = C;
+ C = NULL;
+ }
+ array_free(C);
+ C = NULL;
+ if (B) B->fn->free(B);
+ B = NULL;
+}
+
+aelements(A) ::= aelements(C) COMMA. {
+ A = C;
+ C = NULL;
+}
+
+aelements(A) ::= aelement(B). {
+ A = NULL;
+ if (ctx->ok) {
+ A = array_init();
+ array_insert_unique(A, B);
+ B = NULL;
+ }
+ if (B) B->fn->free(B);
+ B = NULL;
+}
+
+aelement(A) ::= expression(B). {
+ A = B;
+ B = NULL;
+}
+aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
+ A = NULL;
+ if (ctx->ok) {
+ buffer_copy_buffer(C->key, B);
+
+ A = C;
+ C = NULL;
+ }
+ if (C) C->fn->free(C);
+ C = NULL;
+ buffer_free(B);
+ B = NULL;
+}
+
+eols ::= EOL.
+eols ::= .
+
+globalstart ::= GLOBAL. {
+ data_config *dc;
+ dc = (data_config *)array_get_element_klen(ctx->srv->config_context, CONST_STR_LEN("global"));
+ force_assert(dc);
+ configparser_push(ctx, dc, 0);
+}
+
+global ::= globalstart LCURLY metalines RCURLY. {
+ force_assert(ctx->current);
+ configparser_pop(ctx);
+ force_assert(ctx->current);
+}
+
+condlines(A) ::= condlines(B) eols ELSE condline(C). {
+ A = NULL;
+ if (ctx->ok) {
+ if (B->context_ndx >= C->context_ndx) {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ }
+ if (B->cond == CONFIG_COND_ELSE) {
+ fprintf(stderr, "unreachable condition following else catch-all\n");
+ ctx->ok = 0;
+ }
+ C->prev = B;
+ B->next = C;
+ A = C;
+ }
+ B = NULL;
+ C = NULL;
+}
+
+condlines(A) ::= condlines(B) eols ELSE cond_else(C). {
+ A = NULL;
+ if (ctx->ok) {
+ if (B->context_ndx >= C->context_ndx) {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ }
+ if (B->cond == CONFIG_COND_ELSE) {
+ fprintf(stderr, "unreachable condition following else catch-all\n");
+ ctx->ok = 0;
+ }
+ }
+ if (ctx->ok) {
+ size_t pos;
+ data_config *dc;
+ dc = (data_config *)array_extract_element_klen(ctx->all_configs, CONST_BUF_LEN(C->key));
+ force_assert(C == dc);
+ buffer_copy_buffer(C->key, B->key);
+ C->comp = B->comp;
+ /*buffer_copy_buffer(C->comp_key, B->comp_key);*/
+ /*C->string = buffer_init_buffer(B->string);*/
+ pos = buffer_string_length(C->key)-buffer_string_length(B->string)-2;
+ switch(B->cond) {
+ case CONFIG_COND_NE:
+ C->key->ptr[pos] = '='; /* opposite cond */
+ /*buffer_copy_string_len(C->op, CONST_STR_LEN("=="));*/
+ break;
+ case CONFIG_COND_EQ:
+ C->key->ptr[pos] = '!'; /* opposite cond */
+ /*buffer_copy_string_len(C->op, CONST_STR_LEN("!="));*/
+ break;
+ case CONFIG_COND_NOMATCH:
+ C->key->ptr[pos] = '='; /* opposite cond */
+ /*buffer_copy_string_len(C->op, CONST_STR_LEN("=~"));*/
+ break;
+ case CONFIG_COND_MATCH:
+ C->key->ptr[pos] = '!'; /* opposite cond */
+ /*buffer_copy_string_len(C->op, CONST_STR_LEN("!~"));*/
+ break;
+ default: /* should not happen; CONFIG_COND_ELSE checked further above */
+ force_assert(0);
+ }
+
+ if (NULL == (dc = (data_config *)array_get_element_klen(ctx->all_configs, CONST_BUF_LEN(C->key)))) {
+ /* re-insert into ctx->all_configs with new C->key */
+ array_insert_unique(ctx->all_configs, (data_unset *)C);
+ C->prev = B;
+ B->next = C;
+ } else {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ C->fn->free((data_unset *)C);
+ C = dc;
+ }
+
+ A = C;
+ }
+ B = NULL;
+ C = NULL;
+}
+
+condlines(A) ::= condline(B). {
+ A = B;
+ B = NULL;
+}
+
+condline(A) ::= context LCURLY metalines RCURLY. {
+ A = NULL;
+ if (ctx->ok) {
+ data_config *cur;
+
+ cur = ctx->current;
+ configparser_pop(ctx);
+
+ force_assert(cur && ctx->current);
+
+ A = cur;
+ }
+}
+
+cond_else(A) ::= context_else LCURLY metalines RCURLY. {
+ A = NULL;
+ if (ctx->ok) {
+ data_config *cur;
+
+ cur = ctx->current;
+ configparser_pop(ctx);
+
+ force_assert(cur && ctx->current);
+
+ A = cur;
+ }
+}
+
+context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
+ data_config *dc;
+ buffer *b = NULL, *rvalue, *op = NULL;
+
+ if (ctx->ok && D->type != TYPE_STRING) {
+ fprintf(stderr, "rvalue must be string");
+ ctx->ok = 0;
+ }
+
+ if (ctx->ok) {
+ switch(E) {
+ case CONFIG_COND_NE:
+ op = buffer_init_string("!=");
+ break;
+ case CONFIG_COND_EQ:
+ op = buffer_init_string("==");
+ break;
+ case CONFIG_COND_NOMATCH:
+ op = buffer_init_string("!~");
+ break;
+ case CONFIG_COND_MATCH:
+ op = buffer_init_string("=~");
+ break;
+ default:
+ force_assert(0);
+ return; /* unreachable */
+ }
+
+ b = buffer_init();
+ buffer_copy_buffer(b, ctx->current->key);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_string_buffer(b, B);
+ buffer_append_string_buffer(b, C);
+ buffer_append_string_buffer(b, op);
+ rvalue = ((data_string*)D)->value;
+ buffer_append_string_buffer(b, rvalue);
+
+ if (NULL != (dc = (data_config *)array_get_element_klen(ctx->all_configs, CONST_BUF_LEN(b)))) {
+ configparser_push(ctx, dc, 0);
+ } else {
+ static const struct {
+ comp_key_t comp;
+ char *comp_key;
+ size_t len;
+ } comps[] = {
+ { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
+ { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
+ { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
+ { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"referer\"]" ) },
+ { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
+ { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
+ { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
+ { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"cookie\"]" ) },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
+ { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
+ { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
+ { COMP_UNSET, NULL, 0 },
+ };
+ size_t i;
+
+ dc = data_config_init();
+
+ buffer_copy_buffer(dc->key, b);
+ buffer_copy_buffer(dc->op, op);
+ buffer_copy_buffer(dc->comp_tag, C);
+ buffer_copy_buffer(dc->comp_key, B);
+ buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
+ buffer_append_string_buffer(dc->comp_key, C);
+ buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
+ dc->cond = E;
+
+ for (i = 0; comps[i].comp_key; i ++) {
+ if (buffer_is_equal_string(
+ dc->comp_key, comps[i].comp_key, comps[i].len)) {
+ dc->comp = comps[i].comp;
+ break;
+ }
+ }
+ if (COMP_UNSET == dc->comp) {
+ if (buffer_is_equal_string(B, CONST_STR_LEN("REQUEST_HEADER"))) {
+ dc->comp = COMP_HTTP_REQUEST_HEADER;
+ }
+ else {
+ fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
+ ctx->ok = 0;
+ }
+ }
+ else if (COMP_HTTP_LANGUAGE == dc->comp) {
+ dc->comp = COMP_HTTP_REQUEST_HEADER;
+ buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("Accept-Language"));
+ }
+ else if (COMP_HTTP_USER_AGENT == dc->comp) {
+ dc->comp = COMP_HTTP_REQUEST_HEADER;
+ buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("User-Agent"));
+ }
+ else if (COMP_HTTP_REMOTE_IP == dc->comp
+ && (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) {
+ char * const slash = strchr(rvalue->ptr, '/'); /* CIDR mask */
+ char * const colon = strchr(rvalue->ptr, ':'); /* IPv6 */
+ if (NULL != slash && slash == rvalue->ptr){/*(skip AF_UNIX /path/file)*/
+ }
+ else if (NULL != slash) {
+ char *nptr;
+ const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10);
+ if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) {
+ /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/
+ fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ else {
+ int rc;
+ buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/
+ rc = (NULL == colon)
+ ? http_request_host_normalize(rvalue, 0)
+ : configparser_remoteip_normalize_compat(rvalue);
+ buffer_append_string_len(rvalue, CONST_STR_LEN("/"));
+ buffer_append_int(rvalue, (int)nm_bits);
+ if (0 != rc) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+ else {
+ int rc = (NULL == colon)
+ ? http_request_host_normalize(rvalue, 0)
+ : configparser_remoteip_normalize_compat(rvalue);
+ if (0 != rc) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+ else if (COMP_SERVER_SOCKET == dc->comp) {
+ /*(redundant with parsing in network.c; not actually required here)*/
+ if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/
+ && !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) {
+ if (http_request_host_normalize(rvalue, 0)) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+ else if (COMP_HTTP_HOST == dc->comp) {
+ if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) {
+ if (http_request_host_normalize(rvalue, 0)) {
+ fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
+ ctx->ok = 0;
+ }
+ }
+ }
+
+ dc->string = buffer_init_buffer(rvalue);
+
+ if (ctx->ok) switch(E) {
+ case CONFIG_COND_NE:
+ case CONFIG_COND_EQ:
+ break;
+ case CONFIG_COND_NOMATCH:
+ case CONFIG_COND_MATCH: {
+ if (!data_config_pcre_compile(dc)) {
+ ctx->ok = 0;
+ }
+ break;
+ }
+
+ default:
+ fprintf(stderr, "unknown condition for $%s[%s]\n",
+ B->ptr, C->ptr);
+ ctx->ok = 0;
+ break;
+ }
+
+ if (ctx->ok) {
+ configparser_push(ctx, dc, 1);
+ } else {
+ dc->fn->free((data_unset*) dc);
+ }
+ }
+ }
+
+ buffer_free(b);
+ buffer_free(op);
+ buffer_free(B);
+ B = NULL;
+ buffer_free(C);
+ C = NULL;
+ if (D) D->fn->free(D);
+ D = NULL;
+}
+
+context_else ::= . {
+ if (ctx->ok) {
+ data_config *dc = data_config_init();
+ buffer_copy_buffer(dc->key, ctx->current->key);
+ buffer_append_string_len(dc->key, CONST_STR_LEN("/"));
+ buffer_append_string_len(dc->key, CONST_STR_LEN("else_tmp_token"));
+ dc->cond = CONFIG_COND_ELSE;
+ configparser_push(ctx, dc, 1);
+ }
+}
+
+cond(A) ::= EQ. {
+ A = CONFIG_COND_EQ;
+}
+cond(A) ::= MATCH. {
+ A = CONFIG_COND_MATCH;
+}
+cond(A) ::= NE. {
+ A = CONFIG_COND_NE;
+}
+cond(A) ::= NOMATCH. {
+ A = CONFIG_COND_NOMATCH;
+}
+
+stringop(A) ::= expression(B). {
+ A = NULL;
+ if (ctx->ok) {
+ if (B->type == TYPE_STRING) {
+ A = ((data_string*)B)->value;
+ ((data_string*)B)->value = NULL;
+ } else if (B->type == TYPE_INTEGER) {
+ A = buffer_init();
+ buffer_copy_int(A, ((data_integer *)B)->value);
+ } else {
+ fprintf(stderr, "operand must be string");
+ ctx->ok = 0;
+ }
+ }
+ if (B) B->fn->free(B);
+ B = NULL;
+}
+
+include ::= INCLUDE stringop(A). {
+ if (ctx->ok) {
+ if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(A);
+ A = NULL;
+}
+
+include_shell ::= INCLUDE_SHELL stringop(A). {
+ if (ctx->ok) {
+ if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
+ ctx->ok = 0;
+ }
+ }
+ buffer_free(A);
+ A = NULL;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/connections-glue.c b/data/lighttpd/lighttpd-1.4.53/src/connections-glue.c
new file mode 100644
index 000000000..8b4f97121
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/connections-glue.c
@@ -0,0 +1,506 @@
+#include "first.h"
+
+#include "sys-socket.h"
+#include "base.h"
+#include "connections.h"
+#include "fdevent.h"
+#include "http_header.h"
+#include "log.h"
+#include "response.h"
+
+#include <errno.h>
+#include <string.h>
+
+const char *connection_get_state(connection_state_t state) {
+ switch (state) {
+ case CON_STATE_CONNECT: return "connect";
+ case CON_STATE_READ: return "read";
+ case CON_STATE_READ_POST: return "readpost";
+ case CON_STATE_WRITE: return "write";
+ case CON_STATE_CLOSE: return "close";
+ case CON_STATE_ERROR: return "error";
+ case CON_STATE_HANDLE_REQUEST: return "handle-req";
+ case CON_STATE_REQUEST_START: return "req-start";
+ case CON_STATE_REQUEST_END: return "req-end";
+ case CON_STATE_RESPONSE_START: return "resp-start";
+ case CON_STATE_RESPONSE_END: return "resp-end";
+ default: return "(unknown)";
+ }
+}
+
+const char *connection_get_short_state(connection_state_t state) {
+ switch (state) {
+ case CON_STATE_CONNECT: return ".";
+ case CON_STATE_READ: return "r";
+ case CON_STATE_READ_POST: return "R";
+ case CON_STATE_WRITE: return "W";
+ case CON_STATE_CLOSE: return "C";
+ case CON_STATE_ERROR: return "E";
+ case CON_STATE_HANDLE_REQUEST: return "h";
+ case CON_STATE_REQUEST_START: return "q";
+ case CON_STATE_REQUEST_END: return "Q";
+ case CON_STATE_RESPONSE_START: return "s";
+ case CON_STATE_RESPONSE_END: return "S";
+ default: return "x";
+ }
+}
+
+int connection_set_state(server *srv, connection *con, connection_state_t state) {
+ UNUSED(srv);
+
+ con->state = state;
+
+ return 0;
+}
+
+static int connection_handle_read_post_cq_compact(chunkqueue *cq) {
+ /* combine first mem chunk with next non-empty mem chunk
+ * (loop if next chunk is empty) */
+ chunk *c;
+ while (NULL != (c = cq->first) && NULL != c->next) {
+ buffer *mem = c->next->mem;
+ off_t offset = c->next->offset;
+ size_t blen = buffer_string_length(mem) - (size_t)offset;
+ force_assert(c->type == MEM_CHUNK);
+ force_assert(c->next->type == MEM_CHUNK);
+ buffer_append_string_len(c->mem, mem->ptr+offset, blen);
+ c->next->offset = c->offset;
+ c->next->mem = c->mem;
+ c->mem = mem;
+ c->offset = offset + (off_t)blen;
+ chunkqueue_remove_finished_chunks(cq);
+ if (0 != blen) return 1;
+ }
+ return 0;
+}
+
+static int connection_handle_read_post_chunked_crlf(chunkqueue *cq) {
+ /* caller might check chunkqueue_length(cq) >= 2 before calling here
+ * to limit return value to either 1 for good or -1 for error */
+ chunk *c;
+ buffer *b;
+ char *p;
+ size_t len;
+
+ /* caller must have called chunkqueue_remove_finished_chunks(cq), so if
+ * chunkqueue is not empty, it contains chunk with at least one char */
+ if (chunkqueue_is_empty(cq)) return 0;
+
+ c = cq->first;
+ b = c->mem;
+ p = b->ptr+c->offset;
+ if (p[0] != '\r') return -1; /* error */
+ if (p[1] == '\n') return 1;
+ len = buffer_string_length(b) - (size_t)c->offset;
+ if (1 != len) return -1; /* error */
+
+ while (NULL != (c = c->next)) {
+ b = c->mem;
+ len = buffer_string_length(b) - (size_t)c->offset;
+ if (0 == len) continue;
+ p = b->ptr+c->offset;
+ return (p[0] == '\n') ? 1 : -1; /* error if not '\n' */
+ }
+ return 0;
+}
+
+handler_t connection_handle_read_post_error(server *srv, connection *con, int http_status) {
+ UNUSED(srv);
+
+ con->keep_alive = 0;
+
+ /*(do not change status if response headers already set and possibly sent)*/
+ if (0 != con->bytes_header) return HANDLER_ERROR;
+
+ http_response_body_clear(con, 0);
+ con->http_status = http_status;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+}
+
+static handler_t connection_handle_read_post_chunked(server *srv, connection *con, chunkqueue *cq, chunkqueue *dst_cq) {
+
+ /* con->conf.max_request_size is in kBytes */
+ const off_t max_request_size = (off_t)con->conf.max_request_size << 10;
+ off_t te_chunked = con->request.te_chunked;
+ do {
+ off_t len = cq->bytes_in - cq->bytes_out;
+
+ while (0 == te_chunked) {
+ char *p;
+ chunk *c = cq->first;
+ if (NULL == c) break;
+ force_assert(c->type == MEM_CHUNK);
+ p = strchr(c->mem->ptr+c->offset, '\n');
+ if (NULL != p) { /* found HTTP chunked header line */
+ off_t hsz = p + 1 - (c->mem->ptr+c->offset);
+ unsigned char *s = (unsigned char *)c->mem->ptr+c->offset;
+ for (unsigned char u;(u=(unsigned char)hex2int(*s))!=0xFF;++s) {
+ if (te_chunked > (off_t)(1uLL<<(8*sizeof(off_t)-5))-1) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "chunked data size too large -> 400");
+ /* 400 Bad Request */
+ return connection_handle_read_post_error(srv, con, 400);
+ }
+ te_chunked <<= 4;
+ te_chunked |= u;
+ }
+ while (*s == ' ' || *s == '\t') ++s;
+ if (*s != '\r' && *s != ';') {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "chunked header invalid chars -> 400");
+ /* 400 Bad Request */
+ return connection_handle_read_post_error(srv, con, 400);
+ }
+
+ if (hsz >= 1024) {
+ /* prevent theoretical integer overflow
+ * casting to (size_t) and adding 2 (for "\r\n") */
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "chunked header line too long -> 400");
+ /* 400 Bad Request */
+ return connection_handle_read_post_error(srv, con, 400);
+ }
+
+ if (0 == te_chunked) {
+ /* do not consume final chunked header until
+ * (optional) trailers received along with
+ * request-ending blank line "\r\n" */
+ if (p[0] == '\r' && p[1] == '\n') {
+ /*(common case with no trailers; final \r\n received)*/
+ hsz += 2;
+ }
+ else {
+ /* trailers or final CRLF crosses into next cq chunk */
+ hsz -= 2;
+ do {
+ c = cq->first;
+ p = strstr(c->mem->ptr+c->offset+hsz, "\r\n\r\n");
+ } while (NULL == p
+ && connection_handle_read_post_cq_compact(cq));
+ if (NULL == p) {
+ /*(effectively doubles max request field size
+ * potentially received by backend, if in the future
+ * these trailers are added to request headers)*/
+ if ((off_t)buffer_string_length(c->mem) - c->offset
+ < srv->srvconf.max_request_field_size) {
+ break;
+ }
+ else {
+ /* ignore excessively long trailers;
+ * disable keep-alive on connection */
+ con->keep_alive = 0;
+ }
+ }
+ hsz = p + 4 - (c->mem->ptr+c->offset);
+ /* trailers currently ignored, but could be processed
+ * here if 0 == con->conf.stream_request_body, taking
+ * care to reject any fields forbidden in trailers,
+ * making trailers available to CGI and other backends*/
+ }
+ chunkqueue_mark_written(cq, (size_t)hsz);
+ con->request.content_length = dst_cq->bytes_in;
+ break; /* done reading HTTP chunked request body */
+ }
+
+ /* consume HTTP chunked header */
+ chunkqueue_mark_written(cq, (size_t)hsz);
+ len = cq->bytes_in - cq->bytes_out;
+
+ if (0 !=max_request_size
+ && (max_request_size < te_chunked
+ || max_request_size - te_chunked < dst_cq->bytes_in)) {
+ log_error_write(srv, __FILE__, __LINE__, "sos",
+ "request-size too long:",
+ dst_cq->bytes_in + te_chunked, "-> 413");
+ /* 413 Payload Too Large */
+ return connection_handle_read_post_error(srv, con, 413);
+ }
+
+ te_chunked += 2; /*(for trailing "\r\n" after chunked data)*/
+
+ break; /* read HTTP chunked header */
+ }
+
+ /*(likely better ways to handle chunked header crossing chunkqueue
+ * chunks, but this situation is not expected to occur frequently)*/
+ if ((off_t)buffer_string_length(c->mem) - c->offset >= 1024) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "chunked header line too long -> 400");
+ /* 400 Bad Request */
+ return connection_handle_read_post_error(srv, con, 400);
+ }
+ else if (!connection_handle_read_post_cq_compact(cq)) {
+ break;
+ }
+ }
+ if (0 == te_chunked) break;
+
+ if (te_chunked > 2) {
+ if (len > te_chunked-2) len = te_chunked-2;
+ if (dst_cq->bytes_in + te_chunked <= 64*1024) {
+ /* avoid buffering request bodies <= 64k on disk */
+ chunkqueue_steal(dst_cq, cq, len);
+ }
+ else if (0 != chunkqueue_steal_with_tempfiles(srv,dst_cq,cq,len)) {
+ /* 500 Internal Server Error */
+ return connection_handle_read_post_error(srv, con, 500);
+ }
+ te_chunked -= len;
+ len = cq->bytes_in - cq->bytes_out;
+ }
+
+ if (len < te_chunked) break;
+
+ if (2 == te_chunked) {
+ if (-1 == connection_handle_read_post_chunked_crlf(cq)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "chunked data missing end CRLF -> 400");
+ /* 400 Bad Request */
+ return connection_handle_read_post_error(srv, con, 400);
+ }
+ chunkqueue_mark_written(cq, 2);/*consume \r\n at end of chunk data*/
+ te_chunked -= 2;
+ }
+
+ } while (!chunkqueue_is_empty(cq));
+
+ con->request.te_chunked = te_chunked;
+ return HANDLER_GO_ON;
+}
+
+static handler_t connection_handle_read_body_unknown(server *srv, connection *con, chunkqueue *cq, chunkqueue *dst_cq) {
+ /* con->conf.max_request_size is in kBytes */
+ const off_t max_request_size = (off_t)con->conf.max_request_size << 10;
+ chunkqueue_append_chunkqueue(dst_cq, cq);
+ if (0 != max_request_size && dst_cq->bytes_in > max_request_size) {
+ log_error_write(srv, __FILE__, __LINE__, "sos",
+ "request-size too long:", dst_cq->bytes_in, "-> 413");
+ /* 413 Payload Too Large */
+ return connection_handle_read_post_error(srv, con, 413);
+ }
+ return HANDLER_GO_ON;
+}
+
+static off_t connection_write_throttle(server *srv, connection *con, off_t max_bytes) {
+ UNUSED(srv);
+ if (con->conf.global_kbytes_per_second) {
+ off_t limit = con->conf.global_kbytes_per_second * 1024 - *(con->conf.global_bytes_per_second_cnt_ptr);
+ if (limit <= 0) {
+ /* we reached the global traffic limit */
+ con->traffic_limit_reached = 1;
+
+ return 0;
+ } else {
+ if (max_bytes > limit) max_bytes = limit;
+ }
+ }
+
+ if (con->conf.kbytes_per_second) {
+ off_t limit = con->conf.kbytes_per_second * 1024 - con->bytes_written_cur_second;
+ if (limit <= 0) {
+ /* we reached the traffic limit */
+ con->traffic_limit_reached = 1;
+
+ return 0;
+ } else {
+ if (max_bytes > limit) max_bytes = limit;
+ }
+ }
+
+ return max_bytes;
+}
+
+int connection_write_chunkqueue(server *srv, connection *con, chunkqueue *cq, off_t max_bytes) {
+ int ret = -1;
+ off_t written = 0;
+ #ifdef TCP_CORK
+ int corked = 0;
+ #endif
+
+ max_bytes = connection_write_throttle(srv, con, max_bytes);
+ if (0 == max_bytes) return 1;
+
+ written = cq->bytes_out;
+
+ #ifdef TCP_CORK
+ /* Linux: put a cork into socket as we want to combine write() calls
+ * but only if we really have multiple chunks including non-MEM_CHUNK,
+ * and only if TCP socket
+ */
+ if (cq->first && cq->first->next) {
+ const int sa_family = sock_addr_get_family(&con->srv_socket->addr);
+ if (sa_family == AF_INET || sa_family == AF_INET6) {
+ chunk *c = cq->first;
+ while (c->type == MEM_CHUNK && NULL != (c = c->next)) ;
+ if (NULL != c) {
+ corked = 1;
+ (void)setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+ }
+ }
+ }
+ #endif
+
+ ret = con->network_write(srv, con, cq, max_bytes);
+ if (ret >= 0) {
+ chunkqueue_remove_finished_chunks(cq);
+ ret = chunkqueue_is_empty(cq) ? 0 : 1;
+ }
+
+ #ifdef TCP_CORK
+ if (corked) {
+ corked = 0;
+ (void)setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+ }
+ #endif
+
+ written = cq->bytes_out - written;
+ con->bytes_written += written;
+ con->bytes_written_cur_second += written;
+ *(con->conf.global_bytes_per_second_cnt_ptr) += written;
+
+ return ret;
+}
+
+static int connection_write_100_continue(server *srv, connection *con) {
+ /* Make best effort to send all or none of "HTTP/1.1 100 Continue" */
+ /* (Note: also choosing not to update con->write_request_ts
+ * which differs from connections.c:connection_handle_write()) */
+ static const char http_100_continue[] = "HTTP/1.1 100 Continue\r\n\r\n";
+ chunkqueue *cq;
+ off_t written;
+ int rc;
+
+ off_t max_bytes =
+ connection_write_throttle(srv, con, sizeof(http_100_continue)-1);
+ if (max_bytes < (off_t)sizeof(http_100_continue)-1) {
+ return 1; /* success; skip sending if throttled to partial */
+ }
+
+ cq = con->write_queue;
+ written = cq->bytes_out;
+
+ chunkqueue_append_mem(cq,http_100_continue,sizeof(http_100_continue)-1);
+ rc = con->network_write(srv, con, cq, sizeof(http_100_continue)-1);
+
+ written = cq->bytes_out - written;
+ con->bytes_written += written;
+ con->bytes_written_cur_second += written;
+ *(con->conf.global_bytes_per_second_cnt_ptr) += written;
+
+ if (rc < 0) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ return 0; /* error */
+ }
+
+ if (written == sizeof(http_100_continue)-1) {
+ chunkqueue_remove_finished_chunks(cq);
+ } else if (0 == written) {
+ /* skip sending 100 Continue if send would block */
+ chunkqueue_mark_written(cq, sizeof(http_100_continue)-1);
+ con->is_writable = 0;
+ }
+ /* else partial write (unlikely), which can cause corrupt
+ * response if response is later cleared, e.g. sending errdoc.
+ * However, situation of partial write can occur here only on
+ * keep-alive request where client has sent pipelined request,
+ * and more than 0 chars were written, but fewer than 25 chars */
+
+ return 1; /* success; sent all or none of "HTTP/1.1 100 Continue" */
+}
+
+handler_t connection_handle_read_post_state(server *srv, connection *con) {
+ chunkqueue *cq = con->read_queue;
+ chunkqueue *dst_cq = con->request_content_queue;
+
+ int is_closed = 0;
+
+ if (con->is_readable) {
+ con->read_idle_ts = srv->cur_ts;
+
+ switch(con->network_read(srv, con, con->read_queue, MAX_READ_LIMIT)) {
+ case -1:
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ return HANDLER_ERROR;
+ case -2:
+ is_closed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ chunkqueue_remove_finished_chunks(cq);
+
+ /* Check for Expect: 100-continue in request headers
+ * if no request body received yet */
+ if (chunkqueue_is_empty(cq) && 0 == dst_cq->bytes_in
+ && con->request.http_version != HTTP_VERSION_1_0
+ && chunkqueue_is_empty(con->write_queue) && con->is_writable) {
+ buffer *vb = http_header_request_get(con, HTTP_HEADER_EXPECT, CONST_STR_LEN("Expect"));
+ if (NULL != vb && 0 == buffer_caseless_compare(CONST_BUF_LEN(vb), CONST_STR_LEN("100-continue"))) {
+ http_header_request_unset(con, HTTP_HEADER_EXPECT, CONST_STR_LEN("Expect"));
+ if (!connection_write_100_continue(srv, con)) {
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ if (con->request.content_length < 0) {
+ /*(-1: Transfer-Encoding: chunked, -2: unspecified length)*/
+ handler_t rc = (-1 == con->request.content_length)
+ ? connection_handle_read_post_chunked(srv, con, cq, dst_cq)
+ : connection_handle_read_body_unknown(srv, con, cq, dst_cq);
+ if (HANDLER_GO_ON != rc) return rc;
+ }
+ else if (con->request.content_length <= 64*1024) {
+ /* don't buffer request bodies <= 64k on disk */
+ chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
+ }
+ else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
+ /* writing to temp file failed */
+ return connection_handle_read_post_error(srv, con, 500); /* Internal Server Error */
+ }
+
+ chunkqueue_remove_finished_chunks(cq);
+
+ if (dst_cq->bytes_in == (off_t)con->request.content_length) {
+ /* Content is ready */
+ con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
+ if (con->state == CON_STATE_READ_POST) {
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+ }
+ return HANDLER_GO_ON;
+ } else if (is_closed) {
+ #if 0
+ return connection_handle_read_post_error(srv, con, 400); /* Bad Request */
+ #endif
+ return HANDLER_ERROR;
+ } else {
+ con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
+ return (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)
+ ? HANDLER_GO_ON
+ : HANDLER_WAIT_FOR_EVENT;
+ }
+}
+
+void connection_response_reset(server *srv, connection *con) {
+ UNUSED(srv);
+
+ con->mode = DIRECT;
+ con->http_status = 0;
+ con->is_writable = 1;
+ con->file_finished = 0;
+ con->file_started = 0;
+ con->response.keep_alive = 0;
+ if (con->physical.path) { /*(skip for mod_fastcgi authorizer)*/
+ buffer_clear(con->physical.doc_root);
+ buffer_reset(con->physical.path);
+ buffer_clear(con->physical.basedir);
+ buffer_reset(con->physical.rel_path);
+ buffer_clear(con->physical.etag);
+ }
+ con->response.htags = 0;
+ array_reset_data_strings(con->response.headers);
+ http_response_body_clear(con, 0);
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/connections.c b/data/lighttpd/lighttpd-1.4.53/src/connections.c
new file mode 100644
index 000000000..fa6df0ee6
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/connections.c
@@ -0,0 +1,1409 @@
+#include "first.h"
+
+#include "base.h"
+#include "buffer.h"
+#include "log.h"
+#include "connections.h"
+#include "fdevent.h"
+#include "http_header.h"
+
+#include "configfile.h"
+#include "request.h"
+#include "response.h"
+#include "network.h"
+#include "http_chunk.h"
+#include "stat_cache.h"
+#include "joblist.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include "sys-socket.h"
+
+typedef struct {
+ PLUGIN_DATA;
+} plugin_data;
+
+static connection *connections_get_new_connection(server *srv) {
+ connections *conns = srv->conns;
+ size_t i;
+
+ if (conns->size == conns->used) {
+ conns->size += srv->max_conns >= 128 ? 128 : srv->max_conns > 16 ? 16 : srv->max_conns;
+ conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
+ force_assert(NULL != conns->ptr);
+
+ for (i = conns->used; i < conns->size; i++) {
+ conns->ptr[i] = connection_init(srv);
+ connection_reset(srv, conns->ptr[i]);
+ }
+ }
+
+ conns->ptr[conns->used]->ndx = conns->used;
+ return conns->ptr[conns->used++];
+}
+
+static int connection_del(server *srv, connection *con) {
+ size_t i;
+ connections *conns = srv->conns;
+ connection *temp;
+
+ if (con == NULL) return -1;
+
+ if (-1 == con->ndx) return -1;
+
+ buffer_clear(con->uri.authority);
+ buffer_reset(con->uri.path);
+ buffer_reset(con->uri.query);
+ buffer_reset(con->request.orig_uri);
+
+ i = con->ndx;
+
+ /* not last element */
+
+ if (i != conns->used - 1) {
+ temp = conns->ptr[i];
+ conns->ptr[i] = conns->ptr[conns->used - 1];
+ conns->ptr[conns->used - 1] = temp;
+
+ conns->ptr[i]->ndx = i;
+ conns->ptr[conns->used - 1]->ndx = -1;
+ }
+
+ conns->used--;
+
+ con->ndx = -1;
+#if 0
+ fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
+ for (i = 0; i < conns->used; i++) {
+ fprintf(stderr, "%d ", conns->ptr[i]->fd);
+ }
+ fprintf(stderr, "\n");
+#endif
+ return 0;
+}
+
+static int connection_close(server *srv, connection *con) {
+ if (con->fd < 0) con->fd = -con->fd;
+
+ plugins_call_handle_connection_close(srv, con);
+
+ fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
+ fdevent_unregister(srv->ev, con->fd);
+#ifdef __WIN32
+ if (closesocket(con->fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "(warning) close:", con->fd, strerror(errno));
+ }
+#else
+ if (close(con->fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "(warning) close:", con->fd, strerror(errno));
+ }
+#endif
+ else {
+ srv->cur_fds--;
+ }
+
+ if (srv->srvconf.log_state_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "connection closed for fd", con->fd);
+ }
+ con->fd = -1;
+
+ /* plugins should have cleaned themselves up */
+ for (size_t i = 0; i < srv->plugins.used; ++i) {
+ plugin *p = ((plugin **)(srv->plugins.ptr))[i];
+ plugin_data *pd = p->data;
+ if (!pd || NULL == con->plugin_ctx[pd->id]) continue;
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "missing cleanup in", p->name);
+ con->plugin_ctx[pd->id] = NULL;
+ }
+
+ connection_del(srv, con);
+ connection_set_state(srv, con, CON_STATE_CONNECT);
+
+ return 0;
+}
+
+static void connection_read_for_eos(server *srv, connection *con) {
+ /* we have to do the linger_on_close stuff regardless
+ * of con->keep_alive; even non-keepalive sockets may
+ * still have unread data, and closing before reading
+ * it will make the client not see all our output.
+ */
+ ssize_t len;
+ const int type = con->dst_addr.plain.sa_family;
+ char buf[16384];
+ do {
+ len = fdevent_socket_read_discard(con->fd, buf, sizeof(buf),
+ type, SOCK_STREAM);
+ } while (len > 0 || (len < 0 && errno == EINTR));
+
+ if (len < 0 && errno == EAGAIN) return;
+ #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+ if (len < 0 && errno == EWOULDBLOCK) return;
+ #endif
+
+ /* 0 == len || (len < 0 && (errno is a non-recoverable error)) */
+ con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
+}
+
+static void connection_handle_close_state(server *srv, connection *con) {
+ connection_read_for_eos(srv, con);
+
+ if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) {
+ connection_close(srv, con);
+ }
+}
+
+static void connection_handle_shutdown(server *srv, connection *con) {
+ plugins_call_handle_connection_shut_wr(srv, con);
+
+ srv->con_closed++;
+ connection_reset(srv, con);
+
+ /* close the connection */
+ if (con->fd >= 0 && 0 == shutdown(con->fd, SHUT_WR)) {
+ con->close_timeout_ts = srv->cur_ts;
+ connection_set_state(srv, con, CON_STATE_CLOSE);
+
+ if (srv->srvconf.log_state_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "shutdown for fd", con->fd);
+ }
+ } else {
+ connection_close(srv, con);
+ }
+}
+
+static void connection_handle_response_end_state(server *srv, connection *con) {
+ /* log the request */
+ /* (even if error, connection dropped, still write to access log if http_status) */
+ if (con->http_status) {
+ plugins_call_handle_request_done(srv, con);
+ }
+
+ if (con->state != CON_STATE_ERROR) srv->con_written++;
+
+ if (con->request.content_length != con->request_content_queue->bytes_in
+ || con->state == CON_STATE_ERROR) {
+ /* request body is present and has not been read completely */
+ con->keep_alive = 0;
+ }
+
+ if (con->keep_alive) {
+ connection_reset(srv, con);
+#if 0
+ con->request_start = srv->cur_ts;
+ con->read_idle_ts = srv->cur_ts;
+#endif
+ connection_set_state(srv, con, CON_STATE_REQUEST_START);
+ } else {
+ connection_handle_shutdown(srv, con);
+ }
+}
+
+static void connection_handle_errdoc_init(connection *con) {
+ /* modules that produce headers required with error response should
+ * typically also produce an error document. Make an exception for
+ * mod_auth WWW-Authenticate response header. */
+ buffer *www_auth = NULL;
+ if (401 == con->http_status) {
+ buffer *vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"));
+ if (NULL != vb) www_auth = buffer_init_buffer(vb);
+ }
+
+ buffer_reset(con->physical.path);
+ con->response.htags = 0;
+ array_reset_data_strings(con->response.headers);
+ http_response_body_clear(con, 0);
+
+ if (NULL != www_auth) {
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(www_auth));
+ buffer_free(www_auth);
+ }
+}
+
+static int connection_handle_write_prepare(server *srv, connection *con) {
+ if (con->mode == DIRECT) {
+ /* static files */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_POST:
+ case HTTP_METHOD_HEAD:
+ break;
+ case HTTP_METHOD_OPTIONS:
+ /*
+ * 400 is coming from the request-parser BEFORE uri.path is set
+ * 403 is from the response handler when noone else catched it
+ *
+ * */
+ if ((!con->http_status || con->http_status == 200) && !buffer_string_is_empty(con->uri.path) &&
+ con->uri.path->ptr[0] != '*') {
+ http_response_body_clear(con, 0);
+ http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ }
+ break;
+ default:
+ if (0 == con->http_status) {
+ con->http_status = 501;
+ }
+ break;
+ }
+ }
+
+ if (con->http_status == 0) {
+ con->http_status = 403;
+ }
+
+ switch(con->http_status) {
+ case 204: /* class: header only */
+ case 205:
+ case 304:
+ /* disable chunked encoding again as we have no body */
+ http_response_body_clear(con, 1);
+ con->file_finished = 1;
+ break;
+ default: /* class: header + body */
+ /* only custom body for 4xx and 5xx */
+ if (con->http_status < 400 || con->http_status >= 600) break;
+
+ if (con->mode != DIRECT && (!con->conf.error_intercept || con->error_handler_saved_status)) break;
+ if (con->mode == DIRECT && con->error_handler_saved_status >= 65535) break;
+
+ con->file_finished = 0;
+
+ connection_handle_errdoc_init(con);
+
+ /* try to send static errorfile */
+ if (!buffer_string_is_empty(con->conf.errorfile_prefix)) {
+ stat_cache_entry *sce = NULL;
+
+ buffer_copy_buffer(con->physical.path, con->conf.errorfile_prefix);
+ buffer_append_int(con->physical.path, con->http_status);
+ buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
+
+ if (0 == http_chunk_append_file(srv, con, con->physical.path)) {
+ con->file_finished = 1;
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ stat_cache_content_type_get(srv, con, con->physical.path, sce);
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ }
+ }
+ }
+
+ if (!con->file_finished) {
+ buffer *b = srv->tmp_buf;
+
+ buffer_reset(con->physical.path);
+
+ con->file_finished = 1;
+
+ /* build default error-page */
+ buffer_copy_string_len(b, CONST_STR_LEN(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+ " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
+ " <head>\n"
+ " <title>"));
+ http_status_append(b, con->http_status);
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "</title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <h1>"));
+ http_status_append(b, con->http_status);
+
+ buffer_append_string_len(b, CONST_STR_LEN("</h1>\n"
+ " </body>\n"
+ "</html>\n"
+ ));
+
+ (void)http_chunk_append_mem(srv, con, CONST_BUF_LEN(b));
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ }
+ break;
+ }
+
+ /* Allow filter plugins to change response headers before they are written. */
+ switch(plugins_call_handle_response_start(srv, con)) {
+ case HANDLER_GO_ON:
+ case HANDLER_FINISHED:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "s", "response_start plugin failed");
+ return -1;
+ }
+
+ if (con->file_finished) {
+ /* we have all the content and chunked encoding is not used, set a content-length */
+
+ if (!(con->response.htags & (HTTP_HEADER_CONTENT_LENGTH|HTTP_HEADER_TRANSFER_ENCODING))) {
+ off_t qlen = chunkqueue_length(con->write_queue);
+
+ /**
+ * The Content-Length header only can be sent if we have content:
+ * - HEAD doesn't have a content-body (but have a content-length)
+ * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
+ *
+ * Otherwise generate a Content-Length header as chunked encoding is not
+ * available
+ */
+ if ((con->http_status >= 100 && con->http_status < 200) ||
+ con->http_status == 204 ||
+ con->http_status == 304) {
+ /* no Content-Body, no Content-Length */
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) {
+ /* qlen = 0 is important for Redirects (301, ...) as they MAY have
+ * a content. Browsers are waiting for a Content otherwise
+ */
+ buffer_copy_int(srv->tmp_buf, qlen);
+ http_header_response_set(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
+ }
+ }
+ } else {
+ /**
+ * the file isn't finished yet, but we have all headers
+ *
+ * to get keep-alive we either need:
+ * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
+ * - Transfer-Encoding: chunked (HTTP/1.1)
+ * - Upgrade: ... (lighttpd then acts as transparent proxy)
+ */
+
+ if (!(con->response.htags & (HTTP_HEADER_CONTENT_LENGTH|HTTP_HEADER_TRANSFER_ENCODING|HTTP_HEADER_UPGRADE))) {
+ if (con->request.http_method == HTTP_METHOD_CONNECT
+ && con->http_status == 200) {
+ /*(no transfer-encoding if successful CONNECT)*/
+ } else if (con->request.http_version == HTTP_VERSION_1_1) {
+ off_t qlen = chunkqueue_length(con->write_queue);
+ con->response.send_chunked = 1;
+ if (qlen) {
+ /* create initial Transfer-Encoding: chunked segment */
+ buffer * const b = chunkqueue_prepend_buffer_open(con->write_queue);
+ buffer_append_uint_hex(b, (uintmax_t)qlen);
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ chunkqueue_prepend_buffer_commit(con->write_queue);
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("\r\n"));
+ }
+ http_header_response_append(con, HTTP_HEADER_TRANSFER_ENCODING, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
+ } else {
+ con->keep_alive = 0;
+ }
+ }
+
+ /**
+ * if the backend sent a Connection: close, follow the wish
+ *
+ * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
+ * will close the connection. That's fine. We can always decide the close
+ * the connection
+ *
+ * FIXME: to be nice we should remove the Connection: ...
+ */
+ if (con->response.htags & HTTP_HEADER_CONNECTION) {
+ /* a subrequest disable keep-alive although the client wanted it */
+ if (con->keep_alive && !con->response.keep_alive) {
+ con->keep_alive = 0;
+ }
+ }
+ }
+
+ if (con->request.http_method == HTTP_METHOD_HEAD) {
+ /**
+ * a HEAD request has the same as a GET
+ * without the content
+ */
+ http_response_body_clear(con, 1);
+ con->file_finished = 1;
+ }
+
+ http_response_write_header(srv, con);
+
+ return 0;
+}
+
+static int connection_handle_write(server *srv, connection *con) {
+ switch(connection_write_chunkqueue(srv, con, con->write_queue, MAX_WRITE_LIMIT)) {
+ case 0:
+ con->write_request_ts = srv->cur_ts;
+ if (con->file_finished) {
+ connection_set_state(srv, con, CON_STATE_RESPONSE_END);
+ }
+ break;
+ case -1: /* error on our side */
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "connection closed: write failed on fd", con->fd);
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ break;
+ case -2: /* remote close */
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ break;
+ case 1:
+ con->write_request_ts = srv->cur_ts;
+ con->is_writable = 0;
+
+ /* not finished yet -> WRITE */
+ break;
+ }
+
+ return 0;
+}
+
+
+
+connection *connection_init(server *srv) {
+ connection *con;
+
+ UNUSED(srv);
+
+ con = calloc(1, sizeof(*con));
+ force_assert(NULL != con);
+
+ con->fd = 0;
+ con->ndx = -1;
+ con->fde_ndx = -1;
+ con->bytes_written = 0;
+ con->bytes_read = 0;
+ con->bytes_header = 0;
+ con->loops_per_request = 0;
+
+#define CLEAN(x) \
+ con->x = buffer_init();
+
+ CLEAN(request.uri);
+ CLEAN(request.request_line);
+ CLEAN(request.request);
+ CLEAN(request.pathinfo);
+
+ CLEAN(request.orig_uri);
+
+ CLEAN(uri.scheme);
+ CLEAN(uri.authority);
+ CLEAN(uri.path);
+ CLEAN(uri.path_raw);
+ CLEAN(uri.query);
+
+ CLEAN(physical.doc_root);
+ CLEAN(physical.path);
+ CLEAN(physical.basedir);
+ CLEAN(physical.rel_path);
+ CLEAN(physical.etag);
+ CLEAN(parse_request);
+
+ CLEAN(server_name);
+ CLEAN(proto);
+ CLEAN(dst_addr_buf);
+
+#undef CLEAN
+ con->write_queue = chunkqueue_init();
+ con->read_queue = chunkqueue_init();
+ con->request_content_queue = chunkqueue_init();
+
+ con->request.headers = array_init();
+ con->response.headers = array_init();
+ con->environment = array_init();
+
+ /* init plugin specific connection structures */
+
+ con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
+ force_assert(NULL != con->plugin_ctx);
+
+ con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
+ force_assert(NULL != con->cond_cache);
+ config_setup_connection(srv, con);
+
+ return con;
+}
+
+void connections_free(server *srv) {
+ connections *conns = srv->conns;
+ size_t i;
+
+ if (NULL == conns) return;
+
+ for (i = 0; i < conns->size; i++) {
+ connection *con = conns->ptr[i];
+
+ connection_reset(srv, con);
+
+ chunkqueue_free(con->write_queue);
+ chunkqueue_free(con->read_queue);
+ chunkqueue_free(con->request_content_queue);
+ array_free(con->request.headers);
+ array_free(con->response.headers);
+ array_free(con->environment);
+
+#define CLEAN(x) \
+ buffer_free(con->x);
+
+ CLEAN(request.uri);
+ CLEAN(request.request_line);
+ CLEAN(request.request);
+ CLEAN(request.pathinfo);
+
+ CLEAN(request.orig_uri);
+
+ CLEAN(uri.scheme);
+ CLEAN(uri.authority);
+ CLEAN(uri.path);
+ CLEAN(uri.path_raw);
+ CLEAN(uri.query);
+
+ CLEAN(physical.doc_root);
+ CLEAN(physical.path);
+ CLEAN(physical.basedir);
+ CLEAN(physical.etag);
+ CLEAN(physical.rel_path);
+ CLEAN(parse_request);
+
+ CLEAN(server_name);
+ CLEAN(proto);
+ CLEAN(dst_addr_buf);
+#undef CLEAN
+ free(con->plugin_ctx);
+ free(con->cond_cache);
+
+ free(con);
+ }
+
+ free(conns->ptr);
+ free(conns);
+ srv->conns = NULL;
+}
+
+
+int connection_reset(server *srv, connection *con) {
+ plugins_call_connection_reset(srv, con);
+
+ connection_response_reset(srv, con);
+ con->is_readable = 1;
+
+ con->bytes_written = 0;
+ con->bytes_written_cur_second = 0;
+ con->bytes_read = 0;
+ con->bytes_header = 0;
+ con->loops_per_request = 0;
+
+ con->request.http_method = HTTP_METHOD_UNSET;
+ con->request.http_version = HTTP_VERSION_UNSET;
+
+#define CLEAN(x) \
+ buffer_reset(con->x);
+
+ CLEAN(request.uri);
+ CLEAN(request.request_line);
+ CLEAN(request.pathinfo);
+ CLEAN(request.request);
+
+ /* CLEAN(request.orig_uri); */
+
+ /* CLEAN(uri.path); */
+ CLEAN(uri.path_raw);
+ /* CLEAN(uri.query); */
+
+ CLEAN(parse_request);
+
+#undef CLEAN
+
+ buffer_clear(con->uri.scheme);
+ /*buffer_clear(con->proto);*//* set to default in connection_accepted() */
+ /*buffer_clear(con->uri.authority);*/
+ buffer_clear(con->server_name);
+
+ con->request.http_host = NULL;
+ con->request.content_length = 0;
+ con->request.te_chunked = 0;
+ con->request.htags = 0;
+
+ array_reset_data_strings(con->request.headers);
+ array_reset_data_strings(con->environment);
+
+ chunkqueue_reset(con->request_content_queue);
+
+ /* The cond_cache gets reset in response.c */
+ /* config_cond_cache_reset(srv, con); */
+
+ con->header_len = 0;
+ con->async_callback = 0;
+ con->error_handler_saved_status = 0;
+ /*con->error_handler_saved_method = HTTP_METHOD_UNSET;*/
+ /*(error_handler_saved_method value is not valid unless error_handler_saved_status is set)*/
+
+ config_setup_connection(srv, con);
+
+ return 0;
+}
+
+static void connection_read_header(server *srv, connection *con) {
+ chunk *c, *last_chunk;
+ off_t last_offset;
+ chunkqueue *cq = con->read_queue;
+
+ chunkqueue_remove_finished_chunks(cq);
+
+ /* we might have got several packets at once
+ */
+
+ /* if there is a \r\n\r\n in the chunkqueue
+ *
+ * scan the chunk-queue twice
+ * 1. to find the \r\n\r\n
+ * 2. to copy the header-packet
+ *
+ */
+
+ last_chunk = NULL;
+ last_offset = 0;
+
+ for (c = cq->first; c; c = c->next) {
+ size_t i;
+ size_t len = buffer_string_length(c->mem) - c->offset;
+ const char *b = c->mem->ptr + c->offset;
+
+ for (i = 0; i < len; ++i) {
+ char ch = b[i];
+
+ if ('\r' == ch) {
+ /* chec if \n\r\n follows */
+ size_t j = i+1;
+ chunk *cc = c;
+ const char header_end[] = "\r\n\r\n";
+ int header_end_match_pos = 1;
+
+ for ( ; cc; cc = cc->next, j = 0 ) {
+ size_t bblen = buffer_string_length(cc->mem) - cc->offset;
+ const char *bb = cc->mem->ptr + cc->offset;
+
+ for ( ; j < bblen; j++) {
+ ch = bb[j];
+
+ if (ch == header_end[header_end_match_pos]) {
+ header_end_match_pos++;
+ if (4 == header_end_match_pos) {
+ last_chunk = cc;
+ last_offset = j+1;
+ goto found_header_end;
+ }
+ } else {
+ goto reset_search;
+ }
+ }
+ }
+ } else if ('\n' == ch) {
+ /* check if \n follows */
+ if (i+1 < len) {
+ if (b[i+1] == '\n') {
+ last_chunk = c;
+ last_offset = i+2;
+ break;
+ } /* else goto reset_search; */
+ } else {
+ for (chunk *cc = c->next; cc; cc = cc->next) {
+ size_t bblen = buffer_string_length(cc->mem) - cc->offset;
+ const char *bb = cc->mem->ptr + cc->offset;
+ if (0 == bblen) continue;
+ if (bb[0] == '\n') {
+ last_chunk = cc;
+ last_offset = 1;
+ goto found_header_end;
+ } else {
+ goto reset_search;
+ }
+ }
+ }
+ }
+reset_search: ;
+ }
+ }
+found_header_end:
+
+ /* found */
+ if (last_chunk) {
+ buffer_reset(con->request.request);
+
+ for (c = cq->first; c; c = c->next) {
+ size_t len = buffer_string_length(c->mem) - c->offset;
+
+ if (c == last_chunk) {
+ len = last_offset;
+ }
+
+ buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, len);
+ c->offset += len;
+ cq->bytes_out += len;
+
+ if (c == last_chunk) break;
+ }
+
+ connection_set_state(srv, con, CON_STATE_REQUEST_END);
+ }
+
+ if ((last_chunk ? buffer_string_length(con->request.request) : (size_t)chunkqueue_length(cq))
+ > srv->srvconf.max_request_field_size) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 431");
+ con->http_status = 431; /* Request Header Fields Too Large */
+ con->keep_alive = 0;
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+ }
+
+ chunkqueue_remove_finished_chunks(cq);
+}
+
+/**
+ * handle request header read
+ *
+ * we get called by the state-engine and by the fdevent-handler
+ */
+static int connection_handle_read_state(server *srv, connection *con) {
+ int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
+
+ if (con->request_count > 1 && 0 == con->bytes_read) {
+
+ /* update request_start timestamp when first byte of
+ * next request is received on a keep-alive connection */
+ con->request_start = srv->cur_ts;
+ if (con->conf.high_precision_timestamps)
+ log_clock_gettime_realtime(&con->request_start_hp);
+
+ if (!chunkqueue_is_empty(con->read_queue)) {
+ /*(if partially read next request and unable to read() any bytes below,
+ * then will unnecessarily scan again here before subsequent read())*/
+ connection_read_header(srv, con);
+ if (con->state != CON_STATE_READ) {
+ con->read_idle_ts = srv->cur_ts;
+ return 0;
+ }
+ }
+ }
+
+ if (con->is_readable) {
+ con->read_idle_ts = srv->cur_ts;
+
+ switch (con->network_read(srv, con, con->read_queue, MAX_READ_LIMIT)) {
+ case -1:
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ return -1;
+ case -2:
+ is_closed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connection_read_header(srv, con);
+
+ if (con->state == CON_STATE_READ && is_closed) {
+ /* the connection got closed and we didn't got enough data to leave CON_STATE_READ;
+ * the only way is to leave here */
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ }
+
+ return 0;
+}
+
+static handler_t connection_handle_fdevent(server *srv, void *context, int revents) {
+ connection *con = context;
+
+ joblist_append(srv, con);
+
+ if (con->srv_socket->is_ssl) {
+ /* ssl may read and write for both reads and writes */
+ if (revents & (FDEVENT_IN | FDEVENT_OUT)) {
+ con->is_readable = 1;
+ con->is_writable = 1;
+ }
+ } else {
+ if (revents & FDEVENT_IN) {
+ con->is_readable = 1;
+ }
+ if (revents & FDEVENT_OUT) {
+ con->is_writable = 1;
+ /* we don't need the event twice */
+ }
+ }
+
+
+ if (con->state == CON_STATE_READ) {
+ connection_handle_read_state(srv, con);
+ }
+
+ if (con->state == CON_STATE_WRITE &&
+ !chunkqueue_is_empty(con->write_queue) &&
+ con->is_writable) {
+
+ if (-1 == connection_handle_write(srv, con)) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+
+ log_error_write(srv, __FILE__, __LINE__, "ds",
+ con->fd,
+ "handle write failed.");
+ }
+ }
+
+ if (con->state == CON_STATE_CLOSE) {
+ /* flush the read buffers */
+ connection_read_for_eos(srv, con);
+ }
+
+
+ /* attempt (above) to read data in kernel socket buffers
+ * prior to handling FDEVENT_HUP and FDEVENT_ERR */
+
+ if ((revents & ~(FDEVENT_IN | FDEVENT_OUT)) && con->state != CON_STATE_ERROR) {
+ if (con->state == CON_STATE_CLOSE) {
+ con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
+ } else if (revents & FDEVENT_HUP) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ } else if (revents & FDEVENT_RDHUP) {
+ int events = fdevent_event_get_interest(srv->ev, con->fd);
+ events &= ~(FDEVENT_IN|FDEVENT_RDHUP);
+ con->conf.stream_request_body &= ~(FDEVENT_STREAM_REQUEST_BUFMIN|FDEVENT_STREAM_REQUEST_POLLIN);
+ con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLRDHUP;
+ con->is_readable = 1; /*(can read 0 for end-of-stream)*/
+ con->keep_alive = 0;
+ if (con->request.content_length < -1) { /*(transparent proxy mode; no more data to read)*/
+ con->request.content_length = con->request_content_queue->bytes_in;
+ }
+ if (sock_addr_get_family(&con->dst_addr) == AF_UNIX) {
+ /* future: will getpeername() on AF_UNIX properly check if still connected? */
+ fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, events);
+ } else if (fdevent_is_tcp_half_closed(con->fd)) {
+ /* Success of fdevent_is_tcp_half_closed() after FDEVENT_RDHUP indicates TCP FIN received,
+ * but does not distinguish between client shutdown(fd, SHUT_WR) and client close(fd).
+ * Remove FDEVENT_RDHUP so that we do not spin on the ready event.
+ * However, a later TCP RST will not be detected until next write to socket.
+ * future: might getpeername() to check for TCP RST on half-closed sockets
+ * (without FDEVENT_RDHUP interest) when checking for write timeouts
+ * once a second in server.c, though getpeername() on Windows might not indicate this */
+ con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_TCP_FIN;
+ fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, events);
+ } else {
+ /* Failure of fdevent_is_tcp_half_closed() indicates TCP RST
+ * (or unable to tell (unsupported OS), though should not
+ * be setting FDEVENT_RDHUP in that case) */
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ }
+ } else if (revents & FDEVENT_ERR) { /* error, connection reset */
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "connection closed: poll() -> ???", revents);
+ }
+ }
+
+ return HANDLER_FINISHED;
+}
+
+
+connection *connection_accept(server *srv, server_socket *srv_socket) {
+ int cnt;
+ sock_addr cnt_addr;
+ size_t cnt_len = sizeof(cnt_addr); /*(size_t intentional; not socklen_t)*/
+
+ /**
+ * check if we can still open a new connections
+ *
+ * see #1216
+ */
+
+ if (srv->conns->used >= srv->max_conns) {
+ return NULL;
+ }
+
+ cnt = fdevent_accept_listenfd(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len);
+ if (-1 == cnt) {
+ switch (errno) {
+ case EAGAIN:
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EINTR:
+ /* we were stopped _before_ we had a connection */
+ case ECONNABORTED: /* this is a FreeBSD thingy */
+ /* we were stopped _after_ we had a connection */
+ break;
+ case EMFILE:
+ /* out of fds */
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
+ }
+ return NULL;
+ } else {
+ if (sock_addr_get_family(&cnt_addr) != AF_UNIX) {
+ network_accept_tcp_nagle_disable(cnt);
+ }
+ return connection_accepted(srv, srv_socket, &cnt_addr, cnt);
+ }
+}
+
+
+/* 0: everything ok, -1: error, -2: con closed */
+static int connection_read_cq(server *srv, connection *con, chunkqueue *cq, off_t max_bytes) {
+ ssize_t len;
+ char *mem = NULL;
+ size_t mem_len = 0;
+ force_assert(cq == con->read_queue); /*(code transform assumption; minimize diff)*/
+ force_assert(max_bytes == MAX_READ_LIMIT); /*(code transform assumption; minimize diff)*/
+
+ /* check avail data to read and obtain memory into which to read
+ * fill previous chunk if it has sufficient space
+ * (use mem_len=0 to obtain large buffer at least half of chunk_buf_sz)
+ */
+ {
+ int frd;
+ if (0 == fdevent_ioctl_fionread(con->fd, S_IFSOCK, &frd)) {
+ mem_len = (frd < MAX_READ_LIMIT) ? (size_t)frd : MAX_READ_LIMIT;
+ }
+ }
+ mem = chunkqueue_get_memory(con->read_queue, &mem_len);
+
+#if defined(__WIN32)
+ len = recv(con->fd, mem, mem_len, 0);
+#else
+ len = read(con->fd, mem, mem_len);
+#endif /* __WIN32 */
+
+ chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
+
+ if (len < 0) {
+ con->is_readable = 0;
+
+#if defined(__WIN32)
+ {
+ int lastError = WSAGetLastError();
+ switch (lastError) {
+ case EAGAIN:
+ return 0;
+ case EINTR:
+ /* we have been interrupted before we could read */
+ con->is_readable = 1;
+ return 0;
+ case ECONNRESET:
+ /* suppress logging for this error, expected for keep-alive */
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - recv failed: ", lastError);
+ break;
+ }
+ }
+#else /* __WIN32 */
+ switch (errno) {
+ case EAGAIN:
+ return 0;
+ case EINTR:
+ /* we have been interrupted before we could read */
+ con->is_readable = 1;
+ return 0;
+ case ECONNRESET:
+ /* suppress logging for this error, expected for keep-alive */
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
+ break;
+ }
+#endif /* __WIN32 */
+
+ connection_set_state(srv, con, CON_STATE_ERROR);
+
+ return -1;
+ } else if (len == 0) {
+ con->is_readable = 0;
+ /* the other end close the connection -> KEEP-ALIVE */
+
+ /* pipelining */
+
+ return -2;
+ } else if (len != (ssize_t) mem_len) {
+ /* we got less then expected, wait for the next fd-event */
+
+ con->is_readable = 0;
+ }
+
+ con->bytes_read += len;
+ return 0;
+}
+
+
+static int connection_write_cq(server *srv, connection *con, chunkqueue *cq, off_t max_bytes) {
+ return srv->network_backend_write(srv, con->fd, cq, max_bytes);
+}
+
+
+connection *connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt) {
+ connection *con;
+
+ srv->cur_fds++;
+
+ /* ok, we have the connection, register it */
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "appected()", cnt);
+#endif
+ srv->con_opened++;
+
+ con = connections_get_new_connection(srv);
+
+ con->fd = cnt;
+ con->fde_ndx = -1;
+ fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
+ con->network_read = connection_read_cq;
+ con->network_write = connection_write_cq;
+
+ connection_set_state(srv, con, CON_STATE_REQUEST_START);
+
+ con->connection_start = srv->cur_ts;
+ con->dst_addr = *cnt_addr;
+ buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
+ con->srv_socket = srv_socket;
+
+ config_cond_cache_reset(srv, con);
+ con->conditional_is_valid[COMP_SERVER_SOCKET] = 1;
+ con->conditional_is_valid[COMP_HTTP_REMOTE_IP] = 1;
+
+ buffer_copy_string_len(con->proto, CONST_STR_LEN("http"));
+ if (HANDLER_GO_ON != plugins_call_handle_connection_accept(srv, con)) {
+ connection_reset(srv, con);
+ connection_close(srv, con);
+ return NULL;
+ }
+ if (con->http_status < 0) connection_set_state(srv, con, CON_STATE_WRITE);
+ return con;
+}
+
+
+int connection_state_machine(server *srv, connection *con) {
+ int done = 0, r;
+
+ if (srv->srvconf.log_state_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "state at start",
+ con->fd,
+ connection_get_state(con->state));
+ }
+
+ while (done == 0) {
+ size_t ostate = con->state;
+
+ if (srv->srvconf.log_state_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "state for fd", con->fd, connection_get_state(con->state));
+ }
+
+ switch (con->state) {
+ case CON_STATE_REQUEST_START: /* transient */
+ con->request_start = srv->cur_ts;
+ con->read_idle_ts = srv->cur_ts;
+ if (con->conf.high_precision_timestamps)
+ log_clock_gettime_realtime(&con->request_start_hp);
+
+ con->request_count++;
+ con->loops_per_request = 0;
+
+ connection_set_state(srv, con, CON_STATE_READ);
+
+ break;
+ case CON_STATE_REQUEST_END: /* transient */
+ buffer_clear(con->uri.authority);
+ buffer_reset(con->uri.path);
+ buffer_reset(con->uri.query);
+ buffer_reset(con->request.orig_uri);
+
+ if (http_request_parse(srv, con)) {
+ /* we have to read some data from the POST request */
+
+ connection_set_state(srv, con, CON_STATE_READ_POST);
+
+ break;
+ }
+
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+
+ break;
+ case CON_STATE_READ_POST:
+ case CON_STATE_HANDLE_REQUEST:
+ /*
+ * the request is parsed
+ *
+ * decided what to do with the request
+ * -
+ *
+ *
+ */
+
+ switch (r = http_response_prepare(srv, con)) {
+ case HANDLER_WAIT_FOR_EVENT:
+ if (!con->file_finished && (!con->file_started || 0 == con->conf.stream_response_body)) {
+ break; /* come back here */
+ }
+ /* response headers received from backend; fall through to start response */
+ /* fall through */
+ case HANDLER_FINISHED:
+ if (con->http_status == 0) con->http_status = 200;
+ if (con->error_handler_saved_status > 0) {
+ con->request.http_method = con->error_handler_saved_method;
+ }
+ if (con->mode == DIRECT || con->conf.error_intercept) {
+ if (con->error_handler_saved_status) {
+ const int subreq_status = con->http_status;
+ if (con->error_handler_saved_status > 0) {
+ con->http_status = con->error_handler_saved_status;
+ } else if (con->http_status == 404 || con->http_status == 403) {
+ /* error-handler-404 is a 404 */
+ con->http_status = -con->error_handler_saved_status;
+ } else {
+ /* error-handler-404 is back and has generated content */
+ /* if Status: was set, take it otherwise use 200 */
+ }
+ if (200 <= subreq_status && subreq_status <= 299) {
+ /*(flag value to indicate that error handler succeeded)
+ *(for (con->mode == DIRECT))*/
+ con->error_handler_saved_status = 65535; /* >= 1000 */
+ }
+ } else if (con->http_status >= 400) {
+ buffer *error_handler = NULL;
+ if (!buffer_string_is_empty(con->conf.error_handler)) {
+ error_handler = con->conf.error_handler;
+ } else if ((con->http_status == 404 || con->http_status == 403)
+ && !buffer_string_is_empty(con->conf.error_handler_404)) {
+ error_handler = con->conf.error_handler_404;
+ }
+
+ if (error_handler) {
+ /* call error-handler */
+
+ /* set REDIRECT_STATUS to save current HTTP status code
+ * for access by dynamic handlers
+ * https://redmine.lighttpd.net/issues/1828 */
+ buffer_copy_int(srv->tmp_buf, con->http_status);
+ http_header_env_set(con, CONST_STR_LEN("REDIRECT_STATUS"), CONST_BUF_LEN(srv->tmp_buf));
+
+ if (error_handler == con->conf.error_handler) {
+ plugins_call_connection_reset(srv, con);
+
+ if (con->request.content_length) {
+ if (con->request.content_length != con->request_content_queue->bytes_in) {
+ con->keep_alive = 0;
+ }
+ con->request.content_length = 0;
+ chunkqueue_reset(con->request_content_queue);
+ }
+
+ con->is_writable = 1;
+ con->file_finished = 0;
+ con->file_started = 0;
+ con->response.keep_alive = 0;
+
+ con->error_handler_saved_status = con->http_status;
+ con->error_handler_saved_method = con->request.http_method;
+
+ con->request.http_method = HTTP_METHOD_GET;
+ } else { /*(preserve behavior for server.error-handler-404)*/
+ con->error_handler_saved_status = -con->http_status; /*(negative to flag old behavior)*/
+ }
+
+ buffer_copy_buffer(con->request.uri, error_handler);
+ connection_handle_errdoc_init(con);
+ con->http_status = 0; /*(after connection_handle_errdoc_init())*/
+
+ done = -1;
+ break;
+ }
+ }
+ }
+
+ /* we have something to send, go on */
+ connection_set_state(srv, con, CON_STATE_RESPONSE_START);
+ break;
+ case HANDLER_WAIT_FOR_FD:
+ srv->want_fds++;
+
+ fdwaitqueue_append(srv, con);
+
+ break;
+ case HANDLER_COMEBACK:
+ done = -1;
+ break;
+ case HANDLER_ERROR:
+ /* something went wrong */
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
+ break;
+ }
+
+ if (con->state == CON_STATE_HANDLE_REQUEST && ostate == CON_STATE_READ_POST) {
+ ostate = CON_STATE_HANDLE_REQUEST;
+ }
+ break;
+ case CON_STATE_RESPONSE_START:
+ /*
+ * the decision is done
+ * - create the HTTP-Response-Header
+ *
+ */
+
+ if (-1 == connection_handle_write_prepare(srv, con)) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+
+ break;
+ }
+
+ connection_set_state(srv, con, CON_STATE_WRITE);
+ break;
+ case CON_STATE_RESPONSE_END: /* transient */
+ case CON_STATE_ERROR: /* transient */
+ connection_handle_response_end_state(srv, con);
+ break;
+ case CON_STATE_CONNECT:
+ chunkqueue_reset(con->read_queue);
+
+ con->request_count = 0;
+
+ break;
+ case CON_STATE_CLOSE:
+ connection_handle_close_state(srv, con);
+ break;
+ case CON_STATE_READ:
+ connection_handle_read_state(srv, con);
+ break;
+ case CON_STATE_WRITE:
+ do {
+ /* only try to write if we have something in the queue */
+ if (!chunkqueue_is_empty(con->write_queue)) {
+ if (con->is_writable) {
+ if (-1 == connection_handle_write(srv, con)) {
+ log_error_write(srv, __FILE__, __LINE__, "ds",
+ con->fd,
+ "handle write failed.");
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ break;
+ }
+ if (con->state != CON_STATE_WRITE) break;
+ }
+ } else if (con->file_finished) {
+ connection_set_state(srv, con, CON_STATE_RESPONSE_END);
+ break;
+ }
+
+ if (con->mode != DIRECT && !con->file_finished) {
+ switch(r = plugins_call_handle_subrequest(srv, con)) {
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_FINISHED:
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_WAIT_FOR_FD:
+ srv->want_fds++;
+ fdwaitqueue_append(srv, con);
+ break;
+ case HANDLER_COMEBACK:
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sdd", "unexpected subrequest handler ret-value: ", con->fd, r);
+ /* fall through */
+ case HANDLER_ERROR:
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ break;
+ }
+ }
+ } while (con->state == CON_STATE_WRITE && (!chunkqueue_is_empty(con->write_queue) ? con->is_writable : con->file_finished));
+
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
+ "unknown state:", con->fd, con->state);
+
+ break;
+ }
+
+ if (done == -1) {
+ done = 0;
+ } else if (ostate == con->state) {
+ done = 1;
+ }
+ }
+
+ if (srv->srvconf.log_state_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "state at exit:",
+ con->fd,
+ connection_get_state(con->state));
+ }
+
+ r = 0;
+ switch(con->state) {
+ case CON_STATE_READ:
+ r = FDEVENT_IN | FDEVENT_RDHUP;
+ break;
+ case CON_STATE_WRITE:
+ /* request write-fdevent only if we really need it
+ * - if we have data to write
+ * - if the socket is not writable yet
+ */
+ if (!chunkqueue_is_empty(con->write_queue) &&
+ (con->is_writable == 0) &&
+ (con->traffic_limit_reached == 0)) {
+ r |= FDEVENT_OUT;
+ }
+ /* fall through */
+ case CON_STATE_READ_POST:
+ if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN) {
+ r |= FDEVENT_IN | FDEVENT_RDHUP;
+ }
+ break;
+ case CON_STATE_CLOSE:
+ r = FDEVENT_IN;
+ break;
+ default:
+ break;
+ }
+ if (con->fd >= 0) {
+ const int events = fdevent_event_get_interest(srv->ev, con->fd);
+ if (con->is_readable < 0) {
+ con->is_readable = 0;
+ r |= FDEVENT_IN;
+ }
+ if (con->is_writable < 0) {
+ con->is_writable = 0;
+ r |= FDEVENT_OUT;
+ }
+ if (events & FDEVENT_RDHUP) {
+ r |= FDEVENT_RDHUP;
+ }
+ if (r != events) {
+ /* update timestamps when enabling interest in events */
+ if ((r & FDEVENT_IN) && !(events & FDEVENT_IN)) {
+ con->read_idle_ts = srv->cur_ts;
+ }
+ if ((r & FDEVENT_OUT) && !(events & FDEVENT_OUT)) {
+ con->write_request_ts = srv->cur_ts;
+ }
+ fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, r);
+ }
+ }
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/connections.h b/data/lighttpd/lighttpd-1.4.53/src/connections.h
new file mode 100644
index 000000000..f498e5562
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/connections.h
@@ -0,0 +1,23 @@
+#ifndef _CONNECTIONS_H_
+#define _CONNECTIONS_H_
+#include "first.h"
+
+#include "base.h"
+
+connection *connection_init(server *srv);
+int connection_reset(server *srv, connection *con);
+void connections_free(server *srv);
+
+connection * connection_accept(server *srv, server_socket *srv_sock);
+connection * connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt);
+
+int connection_set_state(server *srv, connection *con, connection_state_t state);
+const char * connection_get_state(connection_state_t state);
+const char * connection_get_short_state(connection_state_t state);
+int connection_state_machine(server *srv, connection *con);
+handler_t connection_handle_read_post_state(server *srv, connection *con);
+handler_t connection_handle_read_post_error(server *srv, connection *con, int http_status);
+int connection_write_chunkqueue(server *srv, connection *con, chunkqueue *c, off_t max_bytes);
+void connection_response_reset(server *srv, connection *con);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/crc32.c b/data/lighttpd/lighttpd-1.4.53/src/crc32.c
new file mode 100644
index 000000000..e22f1795b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/crc32.c
@@ -0,0 +1,84 @@
+#include "first.h"
+
+#include "crc32.h"
+
+#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
+
+static const unsigned int crc_c[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+
+uint32_t generate_crc32c(const char *buffer, size_t length) {
+ size_t i;
+ uint32_t crc32 = ~0L;
+
+ for (i = 0; i < length; i++){
+ CRC32C(crc32, (unsigned char)buffer[i]);
+ }
+ return ~crc32;
+}
+
diff --git a/data/lighttpd/lighttpd-1.4.53/src/crc32.h b/data/lighttpd/lighttpd-1.4.53/src/crc32.h
new file mode 100644
index 000000000..7df1718a5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/crc32.h
@@ -0,0 +1,7 @@
+#ifndef __crc32cr_table_h__
+#define __crc32cr_table_h__
+#include "first.h"
+
+uint32_t generate_crc32c(const char *string, size_t length);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/data_array.c b/data/lighttpd/lighttpd-1.4.53/src/data_array.c
new file mode 100644
index 000000000..69b5d0309
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/data_array.c
@@ -0,0 +1,70 @@
+#include "first.h"
+
+#include "array.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+static data_unset *data_array_copy(const data_unset *s) {
+ data_array *src = (data_array *)s;
+ data_array *ds = data_array_init();
+
+ buffer_copy_buffer(ds->key, src->key);
+ array_free(ds->value);
+ ds->value = array_init_array(src->value);
+ ds->is_index_key = src->is_index_key;
+ return (data_unset *)ds;
+}
+
+static void data_array_free(data_unset *d) {
+ data_array *ds = (data_array *)d;
+
+ buffer_free(ds->key);
+ array_free(ds->value);
+
+ free(d);
+}
+
+static void data_array_reset(data_unset *d) {
+ data_array *ds = (data_array *)d;
+
+ /* reused array elements */
+ buffer_reset(ds->key);
+ array_reset(ds->value);
+}
+
+static int data_array_insert_dup(data_unset *dst, data_unset *src) {
+ UNUSED(dst);
+
+ src->fn->free(src);
+
+ return 0;
+}
+
+static void data_array_print(const data_unset *d, int depth) {
+ data_array *ds = (data_array *)d;
+
+ array_print(ds->value, depth);
+}
+
+data_array *data_array_init(void) {
+ static const struct data_methods fn = {
+ data_array_reset,
+ data_array_copy,
+ data_array_free,
+ data_array_insert_dup,
+ data_array_print,
+ };
+ data_array *ds;
+
+ ds = calloc(1, sizeof(*ds));
+ force_assert(NULL != ds);
+
+ ds->key = buffer_init();
+ ds->value = array_init();
+
+ ds->type = TYPE_ARRAY;
+ ds->fn = &fn;
+
+ return ds;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/data_config.c b/data/lighttpd/lighttpd-1.4.53/src/data_config.c
new file mode 100644
index 000000000..764dc6002
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/data_config.c
@@ -0,0 +1,221 @@
+#include "first.h"
+
+#include "base.h" /* (cond_cache_t) */
+#include "array.h"
+#include "configfile.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_PCRE_H
+#include <pcre.h>
+#endif
+
+static data_unset *data_config_copy(const data_unset *s) {
+ data_config *src = (data_config *)s;
+ data_config *ds = data_config_init();
+
+ ds->comp = src->comp;
+ buffer_copy_buffer(ds->key, src->key);
+ buffer_copy_buffer(ds->comp_tag, src->comp_tag);
+ buffer_copy_buffer(ds->comp_key, src->comp_key);
+ array_free(ds->value);
+ ds->value = array_init_array(src->value);
+ return (data_unset *)ds;
+}
+
+static void data_config_free(data_unset *d) {
+ data_config *ds = (data_config *)d;
+
+ buffer_free(ds->key);
+ buffer_free(ds->op);
+ buffer_free(ds->comp_tag);
+ buffer_free(ds->comp_key);
+
+ array_free(ds->value);
+ vector_config_weak_clear(&ds->children);
+
+ if (ds->string) buffer_free(ds->string);
+#ifdef HAVE_PCRE_H
+ if (ds->regex) pcre_free(ds->regex);
+ if (ds->regex_study) pcre_free(ds->regex_study);
+#endif
+
+ free(d);
+}
+
+static void data_config_reset(data_unset *d) {
+ data_config *ds = (data_config *)d;
+
+ /* reused array elements */
+ buffer_clear(ds->key);
+ buffer_clear(ds->comp_tag);
+ buffer_clear(ds->comp_key);
+ array_reset(ds->value);
+}
+
+static int data_config_insert_dup(data_unset *dst, data_unset *src) {
+ UNUSED(dst);
+
+ src->fn->free(src);
+
+ return 0;
+}
+
+static void data_config_print(const data_unset *d, int depth) {
+ data_config *ds = (data_config *)d;
+ array *a = (array *)ds->value;
+ size_t i;
+ size_t maxlen;
+
+ if (0 == ds->context_ndx) {
+ fprintf(stdout, "config {\n");
+ }
+ else {
+ if (ds->cond != CONFIG_COND_ELSE) {
+ fprintf(stdout, "$%s %s \"%s\" {\n",
+ ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
+ } else {
+ fprintf(stdout, "{\n");
+ }
+ array_print_indent(depth + 1);
+ fprintf(stdout, "# block %d\n", ds->context_ndx);
+ }
+ depth ++;
+
+ maxlen = array_get_max_key_length(a);
+ for (i = 0; i < a->used; i ++) {
+ data_unset *du = a->data[i];
+ size_t len = buffer_string_length(du->key);
+ size_t j;
+
+ array_print_indent(depth);
+ fprintf(stdout, "%s", du->key->ptr);
+ for (j = maxlen - len; j > 0; j --) {
+ fprintf(stdout, " ");
+ }
+ fprintf(stdout, " = ");
+ du->fn->print(du, depth);
+ fprintf(stdout, "\n");
+ }
+
+ fprintf(stdout, "\n");
+ for (i = 0; i < ds->children.used; i ++) {
+ data_config *dc = ds->children.data[i];
+
+ /* only the 1st block of chaining */
+ if (NULL == dc->prev) {
+ fprintf(stdout, "\n");
+ array_print_indent(depth);
+ dc->fn->print((data_unset *) dc, depth);
+ fprintf(stdout, "\n");
+ }
+ }
+
+ depth --;
+ array_print_indent(depth);
+ fprintf(stdout, "}");
+ if (0 != ds->context_ndx) {
+ if (ds->cond != CONFIG_COND_ELSE) {
+ fprintf(stdout, " # end of $%s %s \"%s\"",
+ ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
+ } else {
+ fprintf(stdout, " # end of else");
+ }
+ }
+
+ if (ds->next) {
+ fprintf(stdout, "\n");
+ array_print_indent(depth);
+ fprintf(stdout, "else ");
+ ds->next->fn->print((data_unset *)ds->next, depth);
+ }
+}
+
+data_config *data_config_init(void) {
+ static const struct data_methods fn = {
+ data_config_reset,
+ data_config_copy,
+ data_config_free,
+ data_config_insert_dup,
+ data_config_print,
+ };
+ data_config *ds;
+
+ ds = calloc(1, sizeof(*ds));
+
+ ds->key = buffer_init();
+ ds->op = buffer_init();
+ ds->comp_tag = buffer_init();
+ ds->comp_key = buffer_init();
+ ds->value = array_init();
+ vector_config_weak_init(&ds->children);
+
+ ds->type = TYPE_CONFIG;
+ ds->fn = &fn;
+
+ return ds;
+}
+
+int data_config_pcre_compile(data_config *dc) {
+#ifdef HAVE_PCRE_H
+ /* (use fprintf() on error, as this is called from configparser.y) */
+ const char *errptr;
+ int erroff, captures;
+
+ if (dc->regex) pcre_free(dc->regex);
+ if (dc->regex_study) pcre_free(dc->regex_study);
+
+ dc->regex = pcre_compile(dc->string->ptr, 0, &errptr, &erroff, NULL);
+ if (NULL == dc->regex) {
+ fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
+ dc->string->ptr, errptr, erroff);
+ return 0;
+ }
+
+ dc->regex_study = pcre_study(dc->regex, 0, &errptr);
+ if (NULL == dc->regex_study && errptr != NULL) {
+ fprintf(stderr, "studying regex failed: %s -> %s\n",
+ dc->string->ptr, errptr);
+ return 0;
+ }
+
+ erroff = pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT,
+ &captures);
+ if (0 != erroff) {
+ fprintf(stderr, "getting capture count for regex failed: %s\n",
+ dc->string->ptr);
+ return 0;
+ } else if (captures > 9) {
+ fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
+ dc->string->ptr);
+ return 0;
+ }
+ return 1;
+#else
+ fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
+ "(perhaps just a missing pcre-devel package ?) \n",
+ dc->comp_key->ptr, dc->comp_tag->ptr);
+ return 0;
+#endif
+}
+
+int data_config_pcre_exec(data_config *dc, cond_cache_t *cache, buffer *b) {
+#ifdef HAVE_PCRE_H
+ #ifndef elementsof
+ #define elementsof(x) (sizeof(x) / sizeof(x[0]))
+ #endif
+ cache->patterncount =
+ pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(b), 0, 0,
+ cache->matches, elementsof(cache->matches));
+ if (cache->patterncount > 0)
+ cache->comp_value = b; /* holds pointer to b (!) for pattern subst */
+ return cache->patterncount;
+#else
+ UNUSED(dc);
+ UNUSED(cache);
+ UNUSED(b);
+ return 0;
+#endif
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/data_integer.c b/data/lighttpd/lighttpd-1.4.53/src/data_integer.c
new file mode 100644
index 000000000..020acdc26
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/data_integer.c
@@ -0,0 +1,71 @@
+#include "first.h"
+
+#include "array.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static data_unset *data_integer_copy(const data_unset *s) {
+ data_integer *src = (data_integer *)s;
+ data_integer *ds = data_integer_init();
+
+ buffer_copy_buffer(ds->key, src->key);
+ ds->is_index_key = src->is_index_key;
+ ds->value = src->value;
+ return (data_unset *)ds;
+}
+
+static void data_integer_free(data_unset *d) {
+ data_integer *ds = (data_integer *)d;
+
+ buffer_free(ds->key);
+
+ free(d);
+}
+
+static void data_integer_reset(data_unset *d) {
+ data_integer *ds = (data_integer *)d;
+
+ /* reused integer elements */
+ buffer_clear(ds->key);
+ ds->value = 0;
+}
+
+static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
+ UNUSED(dst);
+
+ src->fn->free(src);
+
+ return 0;
+}
+
+static void data_integer_print(const data_unset *d, int depth) {
+ data_integer *ds = (data_integer *)d;
+ UNUSED(depth);
+
+ fprintf(stdout, "%d", ds->value);
+}
+
+
+data_integer *data_integer_init(void) {
+ static const struct data_methods fn = {
+ data_integer_reset,
+ data_integer_copy,
+ data_integer_free,
+ data_integer_insert_dup,
+ data_integer_print,
+ };
+ data_integer *ds;
+
+ ds = calloc(1, sizeof(*ds));
+ force_assert(NULL != ds);
+
+ ds->key = buffer_init();
+ ds->value = 0;
+
+ ds->type = TYPE_INTEGER;
+ ds->fn = &fn;
+
+ return ds;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/data_string.c b/data/lighttpd/lighttpd-1.4.53/src/data_string.c
new file mode 100644
index 000000000..14f58de05
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/data_string.c
@@ -0,0 +1,98 @@
+#include "first.h"
+
+#include "array.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static data_unset *data_string_copy(const data_unset *s) {
+ data_string *src = (data_string *)s;
+ data_string *ds = data_string_init();
+
+ buffer_copy_buffer(ds->key, src->key);
+ buffer_copy_buffer(ds->value, src->value);
+ ds->is_index_key = src->is_index_key;
+ return (data_unset *)ds;
+}
+
+static void data_string_free(data_unset *d) {
+ data_string *ds = (data_string *)d;
+
+ buffer_free(ds->key);
+ buffer_free(ds->value);
+
+ free(d);
+}
+
+static void data_string_reset(data_unset *d) {
+ data_string *ds = (data_string *)d;
+
+ /* reused array elements */
+ buffer_reset(ds->key);
+ buffer_reset(ds->value);
+}
+
+static int data_string_insert_dup(data_unset *dst, data_unset *src) {
+ data_string *ds_dst = (data_string *)dst;
+ data_string *ds_src = (data_string *)src;
+
+ if (!buffer_is_empty(ds_dst->value)) {
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(", "));
+ buffer_append_string_buffer(ds_dst->value, ds_src->value);
+ } else {
+ buffer_copy_buffer(ds_dst->value, ds_src->value);
+ }
+
+ src->fn->free(src);
+
+ return 0;
+}
+
+static void data_string_print(const data_unset *d, int depth) {
+ data_string *ds = (data_string *)d;
+ size_t i, len;
+ UNUSED(depth);
+
+ /* empty and uninitialized strings */
+ if (buffer_string_is_empty(ds->value)) {
+ fputs("\"\"", stdout);
+ return;
+ }
+
+ /* print out the string as is, except prepend " with backslash */
+ putc('"', stdout);
+ len = buffer_string_length(ds->value);
+ for (i = 0; i < len; i++) {
+ unsigned char c = ds->value->ptr[i];
+ if (c == '"') {
+ fputs("\\\"", stdout);
+ } else {
+ putc(c, stdout);
+ }
+ }
+ putc('"', stdout);
+}
+
+
+data_string *data_string_init(void) {
+ static const struct data_methods fn = {
+ data_string_reset,
+ data_string_copy,
+ data_string_free,
+ data_string_insert_dup,
+ data_string_print,
+ };
+ data_string *ds;
+
+ ds = calloc(1, sizeof(*ds));
+ force_assert(NULL != ds);
+
+ ds->key = buffer_init();
+ ds->value = buffer_init();
+
+ ds->type = TYPE_STRING;
+ ds->fn = &fn;
+
+ return ds;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/etag.c b/data/lighttpd/lighttpd-1.4.53/src/etag.c
new file mode 100644
index 000000000..7aab2bbb7
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/etag.c
@@ -0,0 +1,180 @@
+#include "first.h"
+
+#include "buffer.h"
+#include "etag.h"
+
+#include <sys/stat.h>
+#include <string.h>
+
+int etag_is_equal(buffer *etag, const char *line, int weak_ok) {
+ enum {
+ START = 0,
+ CHECK,
+ CHECK_QUOTED,
+ SKIP,
+ SKIP_QUOTED,
+ TAIL
+ } state = START;
+
+ const char *current;
+ const char *tok_start;
+ const char *tok = NULL;
+ int matched;
+
+ if ('*' == line[0] && '\0' == line[1]) {
+ return 1;
+ }
+
+ if (!etag || buffer_string_is_empty(etag)) return 0;
+ tok_start = etag->ptr;
+
+ if ('W' == tok_start[0]) {
+ if (!weak_ok || '/' != tok_start[1]) return 0; /* bad etag */
+ tok_start = tok_start + 2;
+ }
+
+ if ('"' != tok_start[0]) return 0; /* bad etag */
+ /* we start comparing after the first '"' */
+ ++tok_start;
+
+ for (current = line; *current; ++current) {
+ switch (state) {
+ case START:
+ /* wait for etag to start; ignore whitespace and ',' */
+ switch (*current) {
+ case 'W':
+ /* weak etag always starts with 'W/"' */
+ if ('/' != *++current) return 0; /* bad etag list */
+ if ('"' != *++current) return 0; /* bad etag list */
+ if (!weak_ok) {
+ state = SKIP;
+ } else {
+ state = CHECK;
+ tok = tok_start;
+ }
+ break;
+ case '"':
+ /* strong etag starts with '"' */
+ state = CHECK;
+ tok = tok_start;
+ break;
+ case ' ':
+ case ',':
+ case '\t':
+ case '\r':
+ case '\n':
+ break;
+ default:
+ return 0; /* bad etag list */
+ }
+ break;
+ case CHECK:
+ /* compare etags (after the beginning '"')
+ * quoted-pairs must match too (i.e. quoted in both strings):
+ * > (RFC 2616:) both validators MUST be identical in every way
+ */
+ matched = *tok && *tok == *current;
+ ++tok;
+ switch (*current) {
+ case '\\':
+ state = matched ? CHECK_QUOTED : SKIP_QUOTED;
+ break;
+ case '"':
+ if (*tok) {
+ /* bad etag - string should end after '"' */
+ return 0;
+ }
+ if (matched) {
+ /* matching etag: strings were equal */
+ return 1;
+ }
+
+ state = TAIL;
+ break;
+ default:
+ if (!matched) {
+ /* strings not matching, skip remainder of etag */
+ state = SKIP;
+ }
+ break;
+ }
+ break;
+ case CHECK_QUOTED:
+ if (!*tok || *tok != *current) {
+ /* strings not matching, skip remainder of etag */
+ state = SKIP;
+ break;
+ }
+ ++tok;
+ state = CHECK;
+ break;
+ case SKIP:
+ /* wait for final (not quoted) '"' */
+ switch (*current) {
+ case '\\':
+ state = SKIP_QUOTED;
+ break;
+ case '"':
+ state = TAIL;
+ break;
+ }
+ break;
+ case SKIP_QUOTED:
+ state = SKIP;
+ break;
+ case TAIL:
+ /* search for ',', ignore white space */
+ switch (*current) {
+ case ',':
+ state = START;
+ break;
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ break;
+ default:
+ return 0; /* bad etag list */
+ }
+ break;
+ }
+ }
+ /* no matching etag found */
+ return 0;
+}
+
+int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
+ if (0 == flags) return 0;
+
+ buffer_clear(etag);
+
+ if (flags & ETAG_USE_INODE) {
+ buffer_append_int(etag, st->st_ino);
+ buffer_append_string_len(etag, CONST_STR_LEN("-"));
+ }
+
+ if (flags & ETAG_USE_SIZE) {
+ buffer_append_int(etag, st->st_size);
+ buffer_append_string_len(etag, CONST_STR_LEN("-"));
+ }
+
+ if (flags & ETAG_USE_MTIME) {
+ buffer_append_int(etag, st->st_mtime);
+ }
+
+ return 0;
+}
+
+int etag_mutate(buffer *mut, buffer *etag) {
+ size_t i, len;
+ uint32_t h;
+
+ len = buffer_string_length(etag);
+ for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
+
+ buffer_copy_string_len(mut, CONST_STR_LEN("\""));
+ buffer_append_int(mut, h);
+ buffer_append_string_len(mut, CONST_STR_LEN("\""));
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/etag.h b/data/lighttpd/lighttpd-1.4.53/src/etag.h
new file mode 100644
index 000000000..cf0e38a98
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/etag.h
@@ -0,0 +1,16 @@
+#ifndef ETAG_H
+#define ETAG_H
+#include "first.h"
+
+#include "buffer.h"
+
+struct stat; /* declaration */
+
+typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t;
+
+int etag_is_equal(buffer *etag, const char *matches, int weak_ok);
+int etag_create(buffer *etag, struct stat *st, etag_flags_t flags);
+int etag_mutate(buffer *mut, buffer *etag);
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fastcgi.h b/data/lighttpd/lighttpd-1.4.53/src/fastcgi.h
new file mode 100644
index 000000000..629279e32
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fastcgi.h
@@ -0,0 +1,139 @@
+/*
+ * fastcgi.h --
+ *
+ * Defines for the FastCGI protocol.
+ *
+ *
+ * Copyright (c) 1995-1996 Open Market, Inc.
+ *
+ * See the file "LICENSE.TERMS" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * $Id: fastcgi.h,v 1.1.1.1 2003/10/18 09:54:10 weigon Exp $
+ *
+ * License: Open Market License (OML)
+ * https://fedoraproject.org/wiki/Licensing/Open_Market_License (LICENSE.TERMS)
+ */
+
+#ifndef _FASTCGI_H
+#define _FASTCGI_H
+
+/*
+ * Listening socket file number
+ */
+#define FCGI_LISTENSOCK_FILENO 0
+
+typedef struct {
+ unsigned char version;
+ unsigned char type;
+ unsigned char requestIdB1;
+ unsigned char requestIdB0;
+ unsigned char contentLengthB1;
+ unsigned char contentLengthB0;
+ unsigned char paddingLength;
+ unsigned char reserved;
+} FCGI_Header;
+
+#define FCGI_MAX_LENGTH 0xffff
+
+/*
+ * Number of bytes in a FCGI_Header. Future versions of the protocol
+ * will not reduce this number.
+ */
+#define FCGI_HEADER_LEN 8
+
+/*
+ * Value for version component of FCGI_Header
+ */
+#define FCGI_VERSION_1 1
+
+/*
+ * Values for type component of FCGI_Header
+ */
+#define FCGI_BEGIN_REQUEST 1
+#define FCGI_ABORT_REQUEST 2
+#define FCGI_END_REQUEST 3
+#define FCGI_PARAMS 4
+#define FCGI_STDIN 5
+#define FCGI_STDOUT 6
+#define FCGI_STDERR 7
+#define FCGI_DATA 8
+#define FCGI_GET_VALUES 9
+#define FCGI_GET_VALUES_RESULT 10
+#define FCGI_UNKNOWN_TYPE 11
+#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
+
+/*
+ * Value for requestId component of FCGI_Header
+ */
+#define FCGI_NULL_REQUEST_ID 0
+
+
+typedef struct {
+ unsigned char roleB1;
+ unsigned char roleB0;
+ unsigned char flags;
+ unsigned char reserved[5];
+} FCGI_BeginRequestBody;
+
+typedef struct {
+ FCGI_Header header;
+ FCGI_BeginRequestBody body;
+} FCGI_BeginRequestRecord;
+
+/*
+ * Mask for flags component of FCGI_BeginRequestBody
+ */
+#define FCGI_KEEP_CONN 1
+
+/*
+ * Values for role component of FCGI_BeginRequestBody
+ */
+#define FCGI_RESPONDER 1
+#define FCGI_AUTHORIZER 2
+#define FCGI_FILTER 3
+
+
+typedef struct {
+ unsigned char appStatusB3;
+ unsigned char appStatusB2;
+ unsigned char appStatusB1;
+ unsigned char appStatusB0;
+ unsigned char protocolStatus;
+ unsigned char reserved[3];
+} FCGI_EndRequestBody;
+
+typedef struct {
+ FCGI_Header header;
+ FCGI_EndRequestBody body;
+} FCGI_EndRequestRecord;
+
+/*
+ * Values for protocolStatus component of FCGI_EndRequestBody
+ */
+#define FCGI_REQUEST_COMPLETE 0
+#define FCGI_CANT_MPX_CONN 1
+#define FCGI_OVERLOADED 2
+#define FCGI_UNKNOWN_ROLE 3
+
+
+/*
+ * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
+ */
+#define FCGI_MAX_CONNS "FCGI_MAX_CONNS"
+#define FCGI_MAX_REQS "FCGI_MAX_REQS"
+#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
+
+
+typedef struct {
+ unsigned char type;
+ unsigned char reserved[7];
+} FCGI_UnknownTypeBody;
+
+typedef struct {
+ FCGI_Header header;
+ FCGI_UnknownTypeBody body;
+} FCGI_UnknownTypeRecord;
+
+#endif /* _FASTCGI_H */
+
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent.c
new file mode 100644
index 000000000..e1c2459da
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent.c
@@ -0,0 +1,1033 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "base.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "sys-socket.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+
+#ifdef SOCK_CLOEXEC
+static int use_sock_cloexec;
+#endif
+#ifdef SOCK_NONBLOCK
+static int use_sock_nonblock;
+#endif
+
+int fdevent_config(server *srv) {
+ static const struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
+ {
+ /* - epoll is most reliable
+ * - select works everywhere
+ */
+#ifdef FDEVENT_USE_LINUX_EPOLL
+ { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
+ { FDEVENT_HANDLER_LINUX_SYSEPOLL, "epoll" },
+#endif
+#ifdef FDEVENT_USE_SOLARIS_PORT
+ { FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" },
+#endif
+#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
+ { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
+#endif
+#ifdef FDEVENT_USE_FREEBSD_KQUEUE
+ { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
+ { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
+#endif
+#ifdef FDEVENT_USE_POLL
+ { FDEVENT_HANDLER_POLL, "poll" },
+#endif
+#ifdef FDEVENT_USE_SELECT
+ { FDEVENT_HANDLER_SELECT, "select" },
+#endif
+#ifdef FDEVENT_USE_LIBEV
+ { FDEVENT_HANDLER_LIBEV, "libev" },
+#endif
+ { FDEVENT_HANDLER_UNSET, NULL }
+ };
+
+ if (buffer_string_is_empty(srv->srvconf.event_handler)) {
+ /* choose a good default
+ *
+ * the event_handler list is sorted by 'goodness'
+ * taking the first available should be the best solution
+ */
+ srv->event_handler = event_handlers[0].et;
+
+ if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "sorry, there is no event handler for this system");
+
+ return -1;
+ }
+
+ buffer_copy_string(srv->srvconf.event_handler, event_handlers[0].name);
+ } else {
+ /*
+ * User override
+ */
+
+ for (size_t i = 0; event_handlers[i].name; i++) {
+ if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
+ srv->event_handler = event_handlers[i].et;
+ break;
+ }
+ }
+
+ if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "the selected event-handler in unknown or not supported:",
+ srv->srvconf.event_handler );
+
+ return -1;
+ }
+ }
+
+ #ifdef FDEVENT_USE_SELECT
+ if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
+ /* select limits itself
+ *
+ * as it is a hard limit and will lead to a segfault we add some safety
+ * */
+ srv->max_fds = FD_SETSIZE - 200;
+ }
+ else
+ #endif
+ {
+ srv->max_fds = 4096;
+ }
+
+ return 0;
+}
+
+const char * fdevent_show_event_handlers(void) {
+ return
+ "\nEvent Handlers:\n\n"
+#ifdef FDEVENT_USE_SELECT
+ "\t+ select (generic)\n"
+#else
+ "\t- select (generic)\n"
+#endif
+#ifdef FDEVENT_USE_POLL
+ "\t+ poll (Unix)\n"
+#else
+ "\t- poll (Unix)\n"
+#endif
+#ifdef FDEVENT_USE_LINUX_EPOLL
+ "\t+ epoll (Linux)\n"
+#else
+ "\t- epoll (Linux)\n"
+#endif
+#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
+ "\t+ /dev/poll (Solaris)\n"
+#else
+ "\t- /dev/poll (Solaris)\n"
+#endif
+#ifdef FDEVENT_USE_SOLARIS_PORT
+ "\t+ eventports (Solaris)\n"
+#else
+ "\t- eventports (Solaris)\n"
+#endif
+#ifdef FDEVENT_USE_FREEBSD_KQUEUE
+ "\t+ kqueue (FreeBSD)\n"
+#else
+ "\t- kqueue (FreeBSD)\n"
+#endif
+#ifdef FDEVENT_USE_LIBEV
+ "\t+ libev (generic)\n"
+#else
+ "\t- libev (generic)\n"
+#endif
+ ;
+}
+
+fdevents *fdevent_init(server *srv) {
+ fdevents *ev;
+ int type = srv->event_handler;
+ size_t maxfds;
+
+ #ifdef SOCK_CLOEXEC
+ /* Test if SOCK_CLOEXEC is supported by kernel.
+ * Linux kernels < 2.6.27 might return EINVAL if SOCK_CLOEXEC used
+ * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=529929
+ * http://www.linksysinfo.org/index.php?threads/lighttpd-no-longer-starts-toastman-1-28-0510-7.73132/
+ * Test if SOCK_NONBLOCK is ignored by kernel on sockets.
+ * (reported on Android running a custom ROM)
+ * https://redmine.lighttpd.net/issues/2883
+ */
+ int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ if (fd >= 0) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ use_sock_nonblock = (-1 != flags && (flags & O_NONBLOCK));
+ use_sock_cloexec = 1;
+ close(fd);
+ }
+ #endif
+
+ #ifdef FDEVENT_USE_SELECT
+ if (type == FDEVENT_HANDLER_SELECT) {
+ if (srv->max_fds > (int)FD_SETSIZE - 200) {
+ srv->max_fds = (int)FD_SETSIZE - 200;
+ }
+ }
+ #endif
+ maxfds = srv->max_fds + 1; /*(+1 for event-handler fd)*/
+
+ ev = calloc(1, sizeof(*ev));
+ force_assert(NULL != ev);
+ ev->srv = srv;
+ ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
+ if (NULL == ev->fdarray) {
+ log_error_write(srv, __FILE__, __LINE__, "SDS",
+ "server.max-fds too large? (", maxfds-1, ")");
+ free(ev);
+ return NULL;
+ }
+ ev->maxfds = maxfds;
+
+ switch(type) {
+ case FDEVENT_HANDLER_POLL:
+ if (0 != fdevent_poll_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler poll failed");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_SELECT:
+ if (0 != fdevent_select_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler select failed");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_LINUX_SYSEPOLL:
+ if (0 != fdevent_linux_sysepoll_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
+ if (0 != fdevent_solaris_devpoll_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_SOLARIS_PORT:
+ if (0 != fdevent_solaris_port_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler solaris-eventports failed, try to set server.event-handler = \"poll\" or \"select\"");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_FREEBSD_KQUEUE:
+ if (0 != fdevent_freebsd_kqueue_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_LIBEV:
+ if (0 != fdevent_libev_init(ev)) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler libev failed, try to set server.event-handler = \"poll\" or \"select\"");
+ goto error;
+ }
+ return ev;
+ case FDEVENT_HANDLER_UNSET:
+ default:
+ break;
+ }
+
+error:
+ free(ev->fdarray);
+ free(ev);
+
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"");
+ return NULL;
+}
+
+void fdevent_free(fdevents *ev) {
+ size_t i;
+ if (!ev) return;
+
+ if (ev->free) ev->free(ev);
+
+ for (i = 0; i < ev->maxfds; i++) {
+ /* (fdevent_sched_run() should already have been run,
+ * but take reasonable precautions anyway) */
+ if (ev->fdarray[i])
+ free((fdnode *)((uintptr_t)ev->fdarray[i] & ~0x3));
+ }
+
+ free(ev->fdarray);
+ free(ev);
+}
+
+int fdevent_reset(fdevents *ev) {
+ if (ev->reset) return ev->reset(ev);
+
+ return 0;
+}
+
+static fdnode *fdnode_init(void) {
+ fdnode *fdn;
+
+ fdn = calloc(1, sizeof(*fdn));
+ force_assert(NULL != fdn);
+ fdn->fd = -1;
+ return fdn;
+}
+
+static void fdnode_free(fdnode *fdn) {
+ free(fdn);
+}
+
+int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
+ fdnode *fdn;
+
+ fdn = fdnode_init();
+ fdn->handler = handler;
+ fdn->fd = fd;
+ fdn->ctx = ctx;
+ fdn->handler_ctx = NULL;
+ fdn->events = 0;
+
+ ev->fdarray[fd] = fdn;
+
+ return 0;
+}
+
+int fdevent_unregister(fdevents *ev, int fd) {
+ fdnode *fdn;
+
+ if (!ev) return 0;
+ fdn = ev->fdarray[fd];
+ if ((uintptr_t)fdn & 0x3) return 0; /*(should not happen)*/
+
+ fdnode_free(fdn);
+
+ ev->fdarray[fd] = NULL;
+
+ return 0;
+}
+
+void fdevent_sched_close(fdevents *ev, int fd, int issock) {
+ fdnode *fdn;
+ if (!ev) return;
+ fdn = ev->fdarray[fd];
+ if ((uintptr_t)fdn & 0x3) return;
+ ev->fdarray[fd] = (fdnode *)((uintptr_t)fdn | (issock ? 0x1 : 0x2));
+ fdn->ctx = ev->pendclose;
+ ev->pendclose = fdn;
+}
+
+void fdevent_sched_run(server *srv, fdevents *ev) {
+ for (fdnode *fdn = ev->pendclose; fdn; ) {
+ int fd, rc;
+ fdnode *fdn_tmp;
+ #ifdef _WIN32
+ rc = (uintptr_t)fdn & 0x3;
+ #endif
+ fdn = (fdnode *)((uintptr_t)fdn & ~0x3);
+ fd = fdn->fd;
+ #ifdef _WIN32
+ if (rc == 0x1) {
+ rc = closesocket(fd);
+ }
+ else if (rc == 0x2) {
+ rc = close(fd);
+ }
+ #else
+ rc = close(fd);
+ #endif
+
+ if (0 != rc) {
+ log_error_write(srv, __FILE__, __LINE__, "sds", "close failed ", fd, strerror(errno));
+ }
+ else {
+ --srv->cur_fds;
+ }
+
+ fdn_tmp = fdn;
+ fdn = (fdnode *)fdn->ctx; /* next */
+ /*(fdevent_unregister)*/
+ fdnode_free(fdn_tmp);
+ ev->fdarray[fd] = NULL;
+ }
+ ev->pendclose = NULL;
+}
+
+int fdevent_event_get_interest(const fdevents *ev, int fd) {
+ return fd >= 0 ? ev->fdarray[fd]->events : 0;
+}
+
+void fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
+ if (-1 == fd) return;
+ if ((uintptr_t)ev->fdarray[fd] & 0x3) return;
+
+ if (ev->event_del) *fde_ndx = ev->event_del(ev, *fde_ndx, fd);
+ ev->fdarray[fd]->events = 0;
+}
+
+void fdevent_event_set(fdevents *ev, int *fde_ndx, int fd, int events) {
+ if (-1 == fd) return;
+
+ /*(Note: skips registering with kernel if initial events is 0,
+ * so caller should pass non-zero events for initial registration.
+ * If never registered due to never being called with non-zero events,
+ * then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */
+ if (ev->fdarray[fd]->events == events) return;/*(no change; nothing to do)*/
+
+ if (ev->event_set) *fde_ndx = ev->event_set(ev, *fde_ndx, fd, events);
+ ev->fdarray[fd]->events = events;
+}
+
+void fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int event) {
+ int events;
+ if (-1 == fd) return;
+
+ events = ev->fdarray[fd]->events;
+ if ((events & event) == event) return; /*(no change; nothing to do)*/
+
+ events |= event;
+ if (ev->event_set) *fde_ndx = ev->event_set(ev, *fde_ndx, fd, events);
+ ev->fdarray[fd]->events = events;
+}
+
+void fdevent_event_clr(fdevents *ev, int *fde_ndx, int fd, int event) {
+ int events;
+ if (-1 == fd) return;
+
+ events = ev->fdarray[fd]->events;
+ if (!(events & event)) return; /*(no change; nothing to do)*/
+
+ events &= ~event;
+ if (ev->event_set) *fde_ndx = ev->event_set(ev, *fde_ndx, fd, events);
+ ev->fdarray[fd]->events = events;
+}
+
+int fdevent_poll(fdevents *ev, int timeout_ms) {
+ if (ev->poll == NULL) SEGFAULT();
+ return ev->poll(ev, timeout_ms);
+}
+
+int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
+ if (ev->event_get_revent == NULL) SEGFAULT();
+
+ return ev->event_get_revent(ev, ndx);
+}
+
+int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
+ if (ev->event_get_fd == NULL) SEGFAULT();
+
+ return ev->event_get_fd(ev, ndx);
+}
+
+fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
+ if (ev->fdarray[fd] == NULL) SEGFAULT();
+ if ((uintptr_t)ev->fdarray[fd] & 0x3) return NULL;
+ if (ev->fdarray[fd]->fd != fd) SEGFAULT();
+
+ return ev->fdarray[fd]->handler;
+}
+
+void * fdevent_get_context(fdevents *ev, int fd) {
+ if (ev->fdarray[fd] == NULL) SEGFAULT();
+ if ((uintptr_t)ev->fdarray[fd] & 0x3) return NULL;
+ if (ev->fdarray[fd]->fd != fd) SEGFAULT();
+
+ return ev->fdarray[fd]->ctx;
+}
+
+void fdevent_setfd_cloexec(int fd) {
+#ifdef FD_CLOEXEC
+ if (fd < 0) return;
+ force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
+#else
+ UNUSED(fd);
+#endif
+}
+
+void fdevent_clrfd_cloexec(int fd) {
+#ifdef FD_CLOEXEC
+ if (fd >= 0) force_assert(-1 != fcntl(fd, F_SETFD, 0));
+#else
+ UNUSED(fd);
+#endif
+}
+
+int fdevent_fcntl_set_nb(fdevents *ev, int fd) {
+ UNUSED(ev);
+#ifdef O_NONBLOCK
+ return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
+#else
+ UNUSED(fd);
+ return 0;
+#endif
+}
+
+int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd) {
+ fdevent_setfd_cloexec(fd);
+ return fdevent_fcntl_set_nb(ev, fd);
+}
+
+int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd) {
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ if (use_sock_cloexec && use_sock_nonblock)
+ return 0;
+#endif
+ return fdevent_fcntl_set_nb_cloexec(ev, fd);
+}
+
+int fdevent_socket_cloexec(int domain, int type, int protocol) {
+ int fd;
+#ifdef SOCK_CLOEXEC
+ if (use_sock_cloexec)
+ return socket(domain, type | SOCK_CLOEXEC, protocol);
+#endif
+ if (-1 != (fd = socket(domain, type, protocol))) {
+#ifdef FD_CLOEXEC
+ force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
+#endif
+ }
+ return fd;
+}
+
+int fdevent_socket_nb_cloexec(int domain, int type, int protocol) {
+ int fd;
+#ifdef SOCK_CLOEXEC
+ if (use_sock_cloexec && use_sock_nonblock)
+ return socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
+#endif
+ if (-1 != (fd = socket(domain, type, protocol))) {
+#ifdef FD_CLOEXEC
+ force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
+#endif
+#ifdef O_NONBLOCK
+ force_assert(-1 != fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR));
+#endif
+ }
+ return fd;
+}
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+int fdevent_open_cloexec(const char *pathname, int flags, mode_t mode) {
+#ifdef O_CLOEXEC
+ return open(pathname, flags | O_CLOEXEC | O_NOCTTY, mode);
+#else
+ int fd = open(pathname, flags | O_NOCTTY, mode);
+#ifdef FD_CLOEXEC
+ if (fd != -1)
+ force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
+#endif
+ return fd;
+#endif
+}
+
+
+int fdevent_open_devnull(void) {
+ #if defined(_WIN32)
+ return fdevent_open_cloexec("nul", O_RDWR, 0);
+ #else
+ return fdevent_open_cloexec("/dev/null", O_RDWR, 0);
+ #endif
+}
+
+
+int fdevent_open_dirname(char *path) {
+ /*(handle special cases of no dirname or dirname is root directory)*/
+ char * const c = strrchr(path, '/');
+ const char * const dname = (NULL != c ? c == path ? "/" : path : ".");
+ int dfd;
+ int flags = O_RDONLY;
+ #ifdef O_DIRECTORY
+ flags |= O_DIRECTORY;
+ #endif
+ if (NULL != c) *c = '\0';
+ dfd = fdevent_open_cloexec(dname, flags, 0);
+ if (NULL != c) *c = '/';
+ return dfd;
+}
+
+
+int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen) {
+ int fd;
+ socklen_t len = (socklen_t) *addrlen;
+
+ #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ #if defined(__NetBSD__)
+ const int sock_cloexec = 1;
+ fd = paccept(listenfd, addr, &len, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK);
+ #else
+ int sock_cloexec = use_sock_cloexec;
+ if (sock_cloexec) {
+ fd = accept4(listenfd, addr, &len, SOCK_CLOEXEC | SOCK_NONBLOCK);
+ if (fd >= 0) {
+ if (!use_sock_nonblock) {
+ if (0 != fdevent_fcntl_set_nb(NULL, fd)) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ } else if (errno == ENOSYS || errno == ENOTSUP) {
+ fd = accept(listenfd, addr, &len);
+ sock_cloexec = 0;
+ }
+ }
+ else {
+ fd = accept(listenfd, addr, &len);
+ }
+ #endif
+ #else
+ const int sock_cloexec = 0;
+ fd = accept(listenfd, addr, &len);
+ #endif
+
+ if (fd >= 0) {
+ *addrlen = (size_t)len;
+ if (!sock_cloexec && 0 != fdevent_fcntl_set_nb_cloexec(NULL, fd)) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ return fd;
+}
+
+
+int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
+ if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
+
+ return -1;
+}
+
+
+#ifdef __APPLE__
+#include <crt_externs.h>
+#define environ (* _NSGetEnviron())
+#else
+extern char **environ;
+#endif
+char ** fdevent_environ (void) { return environ; }
+
+
+#ifdef FD_CLOEXEC
+static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd) {
+ if (oldfd >= 0) {
+ if (oldfd != newfd) {
+ force_assert(oldfd > STDERR_FILENO);
+ if (newfd != dup2(oldfd, newfd)) return -1;
+ }
+ else {
+ fdevent_clrfd_cloexec(newfd);
+ }
+ }
+ return newfd;
+}
+#else
+static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd, int reuse) {
+ if (oldfd >= 0) {
+ if (oldfd != newfd) {
+ force_assert(oldfd > STDERR_FILENO);
+ if (newfd != dup2(oldfd, newfd)) return -1;
+ if (!reuse) close(oldfd);
+ }
+ }
+ return newfd;
+}
+#endif
+
+
+int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr) {
+ #ifdef FD_CLOEXEC
+ if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO))
+ return -1;
+ if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO))
+ return -1;
+ if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO))
+ return -1;
+ #else
+ if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO,
+ fdin == fdout
+ || fdin == fderr))
+ return -1;
+ if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO,
+ fdout == fderr))
+ return -1;
+ if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO,
+ 0))
+ return -1;
+ #endif
+
+ return 0;
+}
+
+
+#include <stdio.h> /* perror() */
+#include <signal.h> /* signal() */
+
+pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd) {
+ #ifdef HAVE_FORK
+
+ pid_t pid = fork();
+ if (0 != pid) return pid; /* parent (pid > 0) or fork() error (-1 == pid) */
+
+ /* child (0 == pid) */
+
+ if (-1 != dfd) {
+ if (0 != fchdir(dfd))
+ _exit(errno);
+ close(dfd);
+ }
+
+ if (0 != fdevent_set_stdin_stdout_stderr(fdin, fdout, fderr)) _exit(errno);
+ #ifdef FD_CLOEXEC
+ /*(might not be sufficient for open fds, but modern OS have FD_CLOEXEC)*/
+ for (int i = 3; i < 256; ++i) close(i);
+ #endif
+
+ /* reset_signals which may have been ignored (SIG_IGN) */
+ #ifdef SIGTTOU
+ signal(SIGTTOU, SIG_DFL);
+ #endif
+ #ifdef SIGTTIN
+ signal(SIGTTIN, SIG_DFL);
+ #endif
+ #ifdef SIGTSTP
+ signal(SIGTSTP, SIG_DFL);
+ #endif
+ signal(SIGPIPE, SIG_DFL);
+
+ execve(name, argv, envp ? envp : environ);
+
+ if (0 == memcmp(argv[0], "/bin/sh", sizeof("/bin/sh")-1)
+ && argv[1] && 0 == memcmp(argv[1], "-c", sizeof("-c")-1))
+ perror(argv[2]);
+ else
+ perror(argv[0]);
+ _exit(errno);
+
+ #else
+
+ UNUSED(name);
+ UNUSED(argv);
+ UNUSED(envp);
+ UNUSED(fdin);
+ UNUSED(fdout);
+ UNUSED(fderr);
+ UNUSED(dfd);
+ return (pid_t)-1;
+
+ #endif
+}
+
+
+typedef struct fdevent_cmd_pipe {
+ pid_t pid;
+ int fds[2];
+ const char *cmd;
+ time_t start;
+} fdevent_cmd_pipe;
+
+typedef struct fdevent_cmd_pipes {
+ fdevent_cmd_pipe *ptr;
+ size_t used;
+ size_t size;
+} fdevent_cmd_pipes;
+
+static fdevent_cmd_pipes cmd_pipes;
+
+
+static pid_t fdevent_open_logger_pipe_spawn(const char *logger, int rfd) {
+ char *args[4];
+ int devnull = fdevent_open_devnull();
+ pid_t pid;
+
+ if (-1 == devnull) {
+ return -1;
+ }
+
+ *(const char **)&args[0] = "/bin/sh";
+ *(const char **)&args[1] = "-c";
+ *(const char **)&args[2] = logger;
+ args[3] = NULL;
+
+ pid = fdevent_fork_execve(args[0], args, NULL, rfd, devnull, devnull, -1);
+
+ if (pid > 0) {
+ close(devnull);
+ }
+ else {
+ int errnum = errno;
+ close(devnull);
+ errno = errnum;
+ }
+ return pid;
+}
+
+
+static void fdevent_restart_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) {
+ if (fcp->pid > 0) return; /* assert */
+ if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
+ /* restart child process using existing pipe fds */
+ fcp->start = ts;
+ fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd, fcp->fds[0]);
+ }
+}
+
+
+void fdevent_restart_logger_pipes(time_t ts) {
+ for (size_t i = 0; i < cmd_pipes.used; ++i) {
+ fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i;
+ if (fcp->pid > 0) continue;
+ fdevent_restart_logger_pipe(fcp, ts);
+ }
+}
+
+
+int fdevent_waitpid_logger_pipe_pid(pid_t pid, time_t ts) {
+ for (size_t i = 0; i < cmd_pipes.used; ++i) {
+ fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i;
+ if (pid != fcp->pid) continue;
+ fcp->pid = -1;
+ fdevent_restart_logger_pipe(fcp, ts);
+ return 1;
+ }
+ return 0;
+}
+
+
+void fdevent_clr_logger_pipe_pids(void) {
+ for (size_t i = 0; i < cmd_pipes.used; ++i) {
+ fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
+ fcp->pid = -1;
+ }
+}
+
+
+int fdevent_reaped_logger_pipe(pid_t pid) {
+ for (size_t i = 0; i < cmd_pipes.used; ++i) {
+ fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
+ if (fcp->pid == pid) {
+ time_t ts = time(NULL);
+ if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
+ fcp->start = ts;
+ fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd,fcp->fds[0]);
+ return 1;
+ }
+ else {
+ fcp->pid = -1;
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+void fdevent_close_logger_pipes(void) {
+ for (size_t i = 0; i < cmd_pipes.used; ++i) {
+ fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
+ close(fcp->fds[0]);
+ if (fcp->fds[1] != STDERR_FILENO) close(fcp->fds[1]);
+ }
+ free(cmd_pipes.ptr);
+ cmd_pipes.ptr = NULL;
+ cmd_pipes.used = 0;
+ cmd_pipes.size = 0;
+}
+
+
+void fdevent_breakagelog_logger_pipe(int fd) {
+ for (size_t i = 0; i < cmd_pipes.used; ++i) {
+ fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
+ if (fcp->fds[1] != fd) continue;
+ fcp->fds[1] = STDERR_FILENO;
+ break;
+ }
+}
+
+
+static void fdevent_init_logger_pipe(const char *cmd, int fds[2], pid_t pid) {
+ fdevent_cmd_pipe *fcp;
+ if (cmd_pipes.used == cmd_pipes.size) {
+ cmd_pipes.size += 4;
+ cmd_pipes.ptr =
+ realloc(cmd_pipes.ptr, cmd_pipes.size * sizeof(fdevent_cmd_pipe));
+ force_assert(cmd_pipes.ptr);
+ }
+ fcp = cmd_pipes.ptr + cmd_pipes.used++;
+ fcp->cmd = cmd; /* note: cmd must persist in memory (or else copy here) */
+ fcp->fds[0] = fds[0];
+ fcp->fds[1] = fds[1];
+ fcp->pid = pid;
+ fcp->start = time(NULL);
+}
+
+
+static int fdevent_open_logger_pipe(const char *logger) {
+ int fds[2];
+ pid_t pid;
+ if (pipe(fds)) {
+ return -1;
+ }
+ fdevent_setfd_cloexec(fds[0]);
+ fdevent_setfd_cloexec(fds[1]);
+ /*(nonblocking write() from lighttpd)*/
+ if (0 != fdevent_fcntl_set_nb(NULL, fds[1])) { /*(ignore)*/ }
+
+ pid = fdevent_open_logger_pipe_spawn(logger, fds[0]);
+
+ if (pid > 0) {
+ fdevent_init_logger_pipe(logger, fds, pid);
+ return fds[1];
+ }
+ else {
+ int errnum = errno;
+ close(fds[0]);
+ close(fds[1]);
+ errno = errnum;
+ return -1;
+ }
+}
+
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
+
+int fdevent_open_logger(const char *logger) {
+ if (logger[0] != '|') {
+ int flags = O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE;
+ return fdevent_open_cloexec(logger, flags, 0644);
+ }
+ else {
+ return fdevent_open_logger_pipe(logger+1); /*(skip the '|')*/
+ }
+}
+
+int fdevent_cycle_logger(const char *logger, int *curfd) {
+ if (logger[0] != '|') {
+ int fd = fdevent_open_logger(logger);
+ if (-1 == fd) return -1; /*(error; leave *curfd as-is)*/
+ if (-1 != *curfd) close(*curfd);
+ *curfd = fd;
+ }
+ return *curfd;
+}
+
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+
+ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type) {
+ #if defined(MSG_TRUNC) && defined(__linux__)
+ if ((family == AF_INET || family == AF_INET6) && so_type == SOCK_STREAM) {
+ ssize_t len = recv(fd, buf, sz, MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL);
+ if (len >= 0 || errno != EINVAL) return len;
+ }
+ #else
+ UNUSED(family);
+ UNUSED(so_type);
+ #endif
+ return read(fd, buf, sz);
+}
+
+
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h> /* FIONREAD (for illumos (OpenIndiana)) */
+#endif
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+int fdevent_ioctl_fionread (int fd, int fdfmt, int *toread) {
+ #ifdef _WIN32
+ if (fdfmt != S_IFSOCK) { errno = ENOTSOCK; return -1; }
+ return ioctlsocket(fd, FIONREAD, toread);
+ #else
+ #ifdef __CYGWIN__
+ /*(cygwin supports FIONREAD on pipes, not sockets)*/
+ if (fdfmt != S_IFIFO) { errno = EOPNOTSUPP; return -1; }
+ #else
+ UNUSED(fdfmt);
+ #endif
+ return ioctl(fd, FIONREAD, toread);
+ #endif
+}
+
+
+int fdevent_connect_status(int fd) {
+ /* try to finish the connect() */
+ /*(should be called after connect() only when fd is writable (POLLOUT))*/
+ int opt;
+ socklen_t len = sizeof(opt);
+ return (0 == getsockopt(fd,SOL_SOCKET,SO_ERROR,&opt,&len)) ? opt : errno;
+}
+
+
+#include <netinet/tcp.h>
+#if (defined(__APPLE__) && defined(__MACH__)) \
+ || defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__DragonFly__)
+#include <netinet/tcp_fsm.h>
+#endif
+
+/* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */
+int fdevent_is_tcp_half_closed(int fd) {
+ #ifdef TCP_CONNECTION_INFO /* Darwin */
+ struct tcp_connection_info tcpi;
+ socklen_t tlen = sizeof(tcpi);
+ return (0 == getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tlen)
+ && tcpi.tcpi_state == TCPS_CLOSE_WAIT);
+ #elif defined(TCP_INFO) && defined(TCPS_CLOSE_WAIT)
+ /* FreeBSD, NetBSD (not present in OpenBSD or DragonFlyBSD) */
+ struct tcp_info tcpi;
+ socklen_t tlen = sizeof(tcpi);
+ return (0 == getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tlen)
+ && tcpi.tcpi_state == TCPS_CLOSE_WAIT);
+ #elif defined(TCP_INFO) && defined(__linux__)
+ /* Linux (TCP_CLOSE_WAIT is enum, so can not #ifdef TCP_CLOSE_WAIT) */
+ struct tcp_info tcpi;
+ socklen_t tlen = sizeof(tcpi);/*SOL_TCP == IPPROTO_TCP*/
+ return (0 == getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &tlen)
+ && tcpi.tcpi_state == TCP_CLOSE_WAIT);
+ #else
+ UNUSED(fd);
+ /*(0 != getpeername() error might indicate TCP RST, but success
+ * would not differentiate between half-close and full-close)*/
+ return 0; /* false (not half-closed) or TCP state unknown */
+ #endif
+}
+
+
+int fdevent_set_tcp_nodelay (const int fd, const int opt)
+{
+ return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+}
+
+
+int fdevent_set_so_reuseaddr (const int fd, const int opt)
+{
+ return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent.h b/data/lighttpd/lighttpd-1.4.53/src/fdevent.h
new file mode 100644
index 000000000..ced9602a7
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent.h
@@ -0,0 +1,97 @@
+#ifndef _FDEVENT_H_
+#define _FDEVENT_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+struct fdevents; /* declaration */
+typedef struct fdevents fdevents;
+
+typedef handler_t (*fdevent_handler)(struct server *srv, void *ctx, int revents);
+
+/* these are the POLL* values from <bits/poll.h> (linux poll)
+ */
+
+#define FDEVENT_IN BV(0)
+#define FDEVENT_PRI BV(1)
+#define FDEVENT_OUT BV(2)
+#define FDEVENT_ERR BV(3)
+#define FDEVENT_HUP BV(4)
+#define FDEVENT_NVAL BV(5)
+#define FDEVENT_RDHUP BV(13)
+
+#define FDEVENT_STREAM_REQUEST BV(0)
+#define FDEVENT_STREAM_REQUEST_BUFMIN BV(1)
+#define FDEVENT_STREAM_REQUEST_POLLRDHUP BV(12)
+#define FDEVENT_STREAM_REQUEST_TCP_FIN BV(13)
+#define FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR BV(14)
+#define FDEVENT_STREAM_REQUEST_POLLIN BV(15)
+
+#define FDEVENT_STREAM_RESPONSE BV(0)
+#define FDEVENT_STREAM_RESPONSE_BUFMIN BV(1)
+#define FDEVENT_STREAM_RESPONSE_POLLRDHUP BV(15)
+
+int fdevent_config(server *srv);
+const char * fdevent_show_event_handlers(void);
+fdevents *fdevent_init(struct server *srv);
+int fdevent_reset(fdevents *ev); /* "init" after fork() */
+void fdevent_free(fdevents *ev);
+
+int fdevent_event_get_interest(const fdevents *ev, int fd);
+void fdevent_event_set(fdevents *ev, int *fde_ndx, int fd, int events); /* events can be FDEVENT_IN, FDEVENT_OUT or FDEVENT_IN | FDEVENT_OUT */
+void fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int event); /* events can be FDEVENT_IN or FDEVENT_OUT */
+void fdevent_event_clr(fdevents *ev, int *fde_ndx, int fd, int event); /* events can be FDEVENT_IN or FDEVENT_OUT */
+void fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
+int fdevent_event_get_revent(fdevents *ev, size_t ndx);
+int fdevent_event_get_fd(fdevents *ev, size_t ndx);
+fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
+void * fdevent_get_context(fdevents *ev, int fd);
+
+int fdevent_event_next_fdndx(fdevents *ev, int ndx);
+
+int fdevent_poll(fdevents *ev, int timeout_ms);
+
+int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
+int fdevent_unregister(fdevents *ev, int fd);
+void fdevent_sched_close(fdevents *ev, int fd, int issock);
+void fdevent_sched_run(struct server *srv, fdevents *ev);
+
+void fdevent_setfd_cloexec(int fd);
+void fdevent_clrfd_cloexec(int fd);
+int fdevent_fcntl_set_nb(fdevents *ev, int fd);
+int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd);
+int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd);
+int fdevent_socket_cloexec(int domain, int type, int protocol);
+int fdevent_socket_nb_cloexec(int domain, int type, int protocol);
+int fdevent_open_cloexec(const char *pathname, int flags, mode_t mode);
+
+struct sockaddr;
+int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen);
+
+char ** fdevent_environ(void);
+int fdevent_open_devnull(void);
+int fdevent_open_dirname(char *path);
+int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr);
+pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd);
+int fdevent_open_logger(const char *logger);
+int fdevent_cycle_logger(const char *logger, int *curfd);
+int fdevent_reaped_logger_pipe(pid_t pid);
+int fdevent_waitpid_logger_pipe_pid(pid_t pid, time_t ts);
+void fdevent_restart_logger_pipes(time_t ts);
+void fdevent_close_logger_pipes(void);
+void fdevent_breakagelog_logger_pipe(int fd);
+void fdevent_clr_logger_pipe_pids(void);
+
+ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type);
+
+int fdevent_ioctl_fionread (int fd, int fdfmt, int *toread);
+
+int fdevent_connect_status(int fd);
+
+/* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */
+int fdevent_is_tcp_half_closed(int fd);
+int fdevent_set_tcp_nodelay (const int fd, const int opt);
+
+int fdevent_set_so_reuseaddr (const int fd, const int opt);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_freebsd_kqueue.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_freebsd_kqueue.c
new file mode 100644
index 000000000..a1344c603
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_freebsd_kqueue.c
@@ -0,0 +1,232 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef FDEVENT_USE_FREEBSD_KQUEUE
+# include <sys/event.h>
+# include <sys/time.h>
+
+static void fdevent_freebsd_kqueue_free(fdevents *ev) {
+ close(ev->kq_fd);
+ free(ev->kq_results);
+}
+
+static int fdevent_freebsd_kqueue_event_del(fdevents *ev, int fde_ndx, int fd) {
+ int ret, n = 0;
+ struct kevent kev[2];
+ struct timespec ts;
+ int oevents;
+
+ if (fde_ndx < 0) return -1;
+
+ oevents = ev->fdarray[fd]->events;
+
+ if (oevents & FDEVENT_IN) {
+ EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+ if (oevents & FDEVENT_OUT) {
+ EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+
+ if (0 == n) return -1;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ ret = kevent(ev->kq_fd,
+ kev, n,
+ NULL, 0,
+ &ts);
+
+ if (ret == -1) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SS",
+ "kqueue event delete failed: ", strerror(errno));
+
+ return -1;
+ }
+
+ return -1;
+}
+
+static int fdevent_freebsd_kqueue_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ int ret, n = 0;
+ struct kevent kev[2];
+ struct timespec ts;
+ int oevents = ev->fdarray[fd]->events;
+ int addevents = events & ~oevents;
+ int delevents = ~events & oevents;
+
+ UNUSED(fde_ndx);
+
+ if (events == oevents) return fd;
+
+ if (addevents & FDEVENT_IN) {
+ EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ n++;
+ } else if (delevents & FDEVENT_IN) {
+ EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+ if (addevents & FDEVENT_OUT) {
+ EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ n++;
+ } else if (delevents & FDEVENT_OUT) {
+ EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+
+ if (0 == n) return fd;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ ret = kevent(ev->kq_fd,
+ kev, n,
+ NULL, 0,
+ &ts);
+
+ if (ret == -1) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SS",
+ "kqueue event set failed: ", strerror(errno));
+
+ return -1;
+ }
+
+ return fd;
+}
+
+static int fdevent_freebsd_kqueue_poll(fdevents *ev, int timeout_ms) {
+ int ret;
+ struct timespec ts;
+
+ ts.tv_sec = timeout_ms / 1000;
+ ts.tv_nsec = (timeout_ms % 1000) * 1000000;
+
+ ret = kevent(ev->kq_fd,
+ NULL, 0,
+ ev->kq_results, ev->maxfds,
+ &ts);
+
+ if (ret == -1) {
+ switch(errno) {
+ case EINTR:
+ /* we got interrupted, perhaps just a SIGCHLD of a CGI script */
+ return 0;
+ default:
+ log_error_write(ev->srv, __FILE__, __LINE__, "SS",
+ "kqueue failed polling: ", strerror(errno));
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int fdevent_freebsd_kqueue_event_get_revent(fdevents *ev, size_t ndx) {
+ int events = 0, e;
+
+ int filt = e = ev->kq_results[ndx].filter;
+
+ if (e == EVFILT_READ) {
+ events |= FDEVENT_IN;
+ } else if (e == EVFILT_WRITE) {
+ events |= FDEVENT_OUT;
+ }
+
+ e = ev->kq_results[ndx].flags;
+
+ if (e & EV_EOF) {
+ if (filt == EVFILT_READ) {
+ events |= FDEVENT_RDHUP;
+ } else {
+ events |= FDEVENT_HUP;
+ }
+ }
+
+ if (e & EV_ERROR) {
+ events |= FDEVENT_ERR;
+ }
+
+ return events;
+}
+
+static int fdevent_freebsd_kqueue_event_get_fd(fdevents *ev, size_t ndx) {
+ return ev->kq_results[ndx].ident;
+}
+
+static int fdevent_freebsd_kqueue_event_next_fdndx(fdevents *ev, int ndx) {
+ UNUSED(ev);
+
+ return (ndx < 0) ? 0 : ndx + 1;
+}
+
+static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
+ if (-1 == (ev->kq_fd = kqueue())) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "kqueue failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int fdevent_freebsd_kqueue_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE;
+#define SET(x) \
+ ev->x = fdevent_freebsd_kqueue_##x;
+
+ SET(free);
+ SET(poll);
+ SET(reset);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ ev->kq_fd = -1;
+
+ ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
+ force_assert(NULL != ev->kq_results);
+
+ /* check that kqueue works */
+
+ if (-1 == (ev->kq_fd = kqueue())) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "kqueue failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ close(ev->kq_fd);
+ ev->kq_fd = -1;
+
+ return 0;
+}
+#else
+int fdevent_freebsd_kqueue_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "kqueue not available, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_impl.h b/data/lighttpd/lighttpd-1.4.53/src/fdevent_impl.h
new file mode 100644
index 000000000..70e8d94f3
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_impl.h
@@ -0,0 +1,154 @@
+#ifndef INCLUDED_FDEVENT_IMPL_H
+#define INCLUDED_FDEVENT_IMPL_H
+#include "first.h"
+
+/* select event-system */
+
+#if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
+# define FDEVENT_USE_LINUX_EPOLL
+struct epoll_event; /* declaration */
+#endif
+
+/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
+ * under /usr/include/sys/ */
+#if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
+# define FDEVENT_USE_POLL
+struct pollfd; /* declaration */
+#endif
+
+#if defined HAVE_SELECT
+# ifdef __WIN32
+# include <winsock2.h>
+# endif
+# define FDEVENT_USE_SELECT
+# ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# endif
+#endif
+
+#if defined HAVE_SYS_DEVPOLL_H && defined(__sun)
+# define FDEVENT_USE_SOLARIS_DEVPOLL
+struct pollfd; /* declaration */
+#endif
+
+#if defined HAVE_PORT_H && defined HAVE_PORT_CREATE && defined(__sun)
+# define FDEVENT_USE_SOLARIS_PORT
+# include <port.h>
+#endif
+
+#if defined HAVE_SYS_EVENT_H && defined HAVE_KQUEUE
+# define FDEVENT_USE_FREEBSD_KQUEUE
+struct kevent; /* declaration */
+#endif
+
+#if defined HAVE_LIBEV
+# define FDEVENT_USE_LIBEV
+struct ev_loop; /* declaration */
+#endif
+
+#include "base_decls.h"
+#include "fdevent.h" /* (*fdevent_handler) */
+
+typedef enum {
+ FDEVENT_HANDLER_UNSET,
+ FDEVENT_HANDLER_SELECT,
+ FDEVENT_HANDLER_POLL,
+ FDEVENT_HANDLER_LINUX_SYSEPOLL,
+ FDEVENT_HANDLER_SOLARIS_DEVPOLL,
+ FDEVENT_HANDLER_SOLARIS_PORT,
+ FDEVENT_HANDLER_FREEBSD_KQUEUE,
+ FDEVENT_HANDLER_LIBEV
+} fdevent_handler_t;
+
+typedef struct _fdnode {
+ fdevent_handler handler;
+ void *ctx;
+ void *handler_ctx;
+ int fd;
+ int events;
+} fdnode;
+
+/**
+ * array of unused fd's
+ *
+ */
+
+#ifdef FDEVENT_USE_POLL
+typedef struct {
+ int *ptr;
+
+ size_t used;
+ size_t size;
+} buffer_int;
+#endif
+
+struct fdevents {
+ struct server *srv;
+ fdevent_handler_t type;
+
+ fdnode **fdarray;
+ fdnode *pendclose;
+ size_t maxfds;
+
+ #ifdef FDEVENT_USE_LINUX_EPOLL
+ int epoll_fd;
+ struct epoll_event *epoll_events;
+ #endif
+ #ifdef FDEVENT_USE_POLL
+ struct pollfd *pollfds;
+
+ size_t size;
+ size_t used;
+
+ buffer_int unused;
+ #endif
+ #ifdef FDEVENT_USE_SELECT
+ fd_set select_read;
+ fd_set select_write;
+ fd_set select_error;
+
+ fd_set select_set_read;
+ fd_set select_set_write;
+ fd_set select_set_error;
+
+ int select_max_fd;
+ #endif
+ #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
+ int devpoll_fd;
+ struct pollfd *devpollfds;
+ #endif
+ #ifdef FDEVENT_USE_SOLARIS_PORT
+ port_event_t *port_events;
+ #endif
+ #ifdef FDEVENT_USE_FREEBSD_KQUEUE
+ int kq_fd;
+ struct kevent *kq_results;
+ #endif
+ #ifdef FDEVENT_USE_SOLARIS_PORT
+ int port_fd;
+ #endif
+ #ifdef FDEVENT_USE_LIBEV
+ struct ev_loop *libev_loop;
+ #endif
+ int (*reset)(struct fdevents *ev);
+ void (*free)(struct fdevents *ev);
+
+ int (*event_set)(struct fdevents *ev, int fde_ndx, int fd, int events);
+ int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
+ int (*event_get_revent)(struct fdevents *ev, size_t ndx);
+ int (*event_get_fd)(struct fdevents *ev, size_t ndx);
+
+ int (*event_next_fdndx)(struct fdevents *ev, int ndx);
+
+ int (*poll)(struct fdevents *ev, int timeout_ms);
+};
+
+int fdevent_select_init(struct fdevents *ev);
+int fdevent_poll_init(struct fdevents *ev);
+int fdevent_linux_sysepoll_init(struct fdevents *ev);
+int fdevent_solaris_devpoll_init(struct fdevents *ev);
+int fdevent_solaris_port_init(struct fdevents *ev);
+int fdevent_freebsd_kqueue_init(struct fdevents *ev);
+int fdevent_libev_init(struct fdevents *ev);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_libev.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_libev.c
new file mode 100644
index 000000000..bc24359e6
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_libev.c
@@ -0,0 +1,177 @@
+#include "first.h"
+
+#include <stdlib.h>
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#ifdef FDEVENT_USE_LIBEV
+
+# include <ev.h>
+
+static void io_watcher_cb(struct ev_loop *loop, ev_io *w, int revents) {
+ fdevents *ev = w->data;
+ fdevent_handler handler = fdevent_get_handler(ev, w->fd);
+ void *context = fdevent_get_context(ev, w->fd);
+ int r = 0;
+ UNUSED(loop);
+ if (NULL == handler) return;
+
+ if (revents & EV_READ) r |= FDEVENT_IN;
+ if (revents & EV_WRITE) r |= FDEVENT_OUT;
+ if (revents & EV_ERROR) r |= FDEVENT_ERR;
+
+ switch (r = (*handler)(ev->srv, context, r)) {
+ case HANDLER_FINISHED:
+ case HANDLER_GO_ON:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_WAIT_FOR_FD:
+ break;
+ case HANDLER_ERROR:
+ /* should never happen */
+ SEGFAULT();
+ break;
+ default:
+ log_error_write(ev->srv, __FILE__, __LINE__, "d", r);
+ break;
+ }
+}
+
+static void fdevent_libev_free(fdevents *ev) {
+ UNUSED(ev);
+}
+
+static int fdevent_libev_event_del(fdevents *ev, int fde_ndx, int fd) {
+ fdnode *fdn;
+ ev_io *watcher;
+
+ if (-1 == fde_ndx) return -1;
+
+ fdn = ev->fdarray[fd];
+ watcher = fdn->handler_ctx;
+
+ if (!watcher) return -1;
+
+ ev_io_stop(ev->libev_loop, watcher);
+ free(watcher);
+ fdn->handler_ctx = NULL;
+
+ return -1;
+}
+
+static int fdevent_libev_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ fdnode *fdn = ev->fdarray[fd];
+ ev_io *watcher = fdn->handler_ctx;
+ int ev_events = 0;
+ UNUSED(fde_ndx);
+
+ if (events & FDEVENT_IN) ev_events |= EV_READ;
+ if (events & FDEVENT_OUT) ev_events |= EV_WRITE;
+
+ if (!watcher) {
+ fdn->handler_ctx = watcher = calloc(1, sizeof(ev_io));
+ force_assert(watcher);
+
+ ev_io_init(watcher, io_watcher_cb, fd, ev_events);
+ watcher->data = ev;
+ ev_io_start(ev->libev_loop, watcher);
+ } else {
+ if ((watcher->events & (EV_READ | EV_WRITE)) != ev_events) {
+ ev_io_stop(ev->libev_loop, watcher);
+ ev_io_set(watcher, watcher->fd, ev_events);
+ ev_io_start(ev->libev_loop, watcher);
+ }
+ }
+
+ return fd;
+}
+
+static void timeout_watcher_cb(struct ev_loop *loop, ev_timer *w, int revents) {
+ UNUSED(loop);
+ UNUSED(w);
+ UNUSED(revents);
+}
+
+static ev_timer timeout_watcher;
+
+static int fdevent_libev_poll(fdevents *ev, int timeout_ms) {
+ timeout_watcher.repeat = (timeout_ms > 0) ? timeout_ms/1000.0 : 0.001;
+
+ ev_timer_again(ev->libev_loop, &timeout_watcher);
+ ev_run(ev->libev_loop, EVRUN_ONCE);
+
+ return 0;
+}
+
+static int fdevent_libev_event_get_revent(fdevents *ev, size_t ndx) {
+ UNUSED(ev);
+ UNUSED(ndx);
+
+ return 0;
+}
+
+static int fdevent_libev_event_get_fd(fdevents *ev, size_t ndx) {
+ UNUSED(ev);
+ UNUSED(ndx);
+
+ return -1;
+}
+
+static int fdevent_libev_event_next_fdndx(fdevents *ev, int ndx) {
+ UNUSED(ev);
+ UNUSED(ndx);
+
+ return -1;
+}
+
+static int fdevent_libev_reset(fdevents *ev) {
+ UNUSED(ev);
+
+ ev_default_fork();
+
+ return 0;
+}
+
+int fdevent_libev_init(fdevents *ev) {
+ struct ev_timer * const timer = &timeout_watcher;
+ memset(timer, 0, sizeof(*timer));
+
+ ev->type = FDEVENT_HANDLER_LIBEV;
+#define SET(x) \
+ ev->x = fdevent_libev_##x;
+
+ SET(free);
+ SET(poll);
+ SET(reset);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ if (NULL == (ev->libev_loop = ev_default_loop(0))) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "ev_default_loop failed , try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ ev_timer_init(timer, timeout_watcher_cb, 0.0, 1.0);
+
+ return 0;
+}
+
+#else
+int fdevent_libev_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "libev not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_linux_sysepoll.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_linux_sysepoll.c
new file mode 100644
index 000000000..453132df9
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_linux_sysepoll.c
@@ -0,0 +1,166 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef FDEVENT_USE_LINUX_EPOLL
+
+# include <sys/epoll.h>
+
+#ifndef EPOLLRDHUP
+#define EPOLLRDHUP 0
+#endif
+
+static void fdevent_linux_sysepoll_free(fdevents *ev) {
+ close(ev->epoll_fd);
+ free(ev->epoll_events);
+}
+
+static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
+ struct epoll_event ep;
+
+ if (fde_ndx < 0) return -1;
+
+ memset(&ep, 0, sizeof(ep));
+
+ ep.data.fd = fd;
+ ep.data.ptr = NULL;
+
+ if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "epoll_ctl failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+
+ return -1;
+}
+
+static int fdevent_linux_sysepoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ struct epoll_event ep;
+ int add = 0;
+
+ if (fde_ndx == -1) add = 1;
+
+ memset(&ep, 0, sizeof(ep));
+
+ ep.events = 0;
+
+ if (events & FDEVENT_IN) ep.events |= EPOLLIN;
+ if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
+ if (events & FDEVENT_RDHUP) ep.events |= EPOLLRDHUP;
+
+ /**
+ *
+ * with EPOLLET we don't get a FDEVENT_HUP
+ * if the close is delay after everything has
+ * sent.
+ *
+ */
+
+ ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
+
+ ep.data.ptr = NULL;
+ ep.data.fd = fd;
+
+ if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "epoll_ctl failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+ return fd;
+}
+
+static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
+ return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
+}
+
+static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
+ int events = 0, e;
+
+ e = ev->epoll_events[ndx].events;
+ if (e & EPOLLIN) events |= FDEVENT_IN;
+ if (e & EPOLLOUT) events |= FDEVENT_OUT;
+ if (e & EPOLLERR) events |= FDEVENT_ERR;
+ if (e & EPOLLHUP) events |= FDEVENT_HUP;
+ if (e & EPOLLPRI) events |= FDEVENT_PRI;
+ if (e & EPOLLRDHUP) events |= FDEVENT_RDHUP;
+
+ return events;
+}
+
+static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
+# if 0
+ log_error_write(ev->srv, __FILE__, __LINE__, "SD, D",
+ "fdevent_linux_sysepoll_event_get_fd: ", (int) ndx, ev->epoll_events[ndx].data.fd);
+# endif
+
+ return ev->epoll_events[ndx].data.fd;
+}
+
+static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
+ size_t i;
+
+ UNUSED(ev);
+
+ i = (ndx < 0) ? 0 : ndx + 1;
+
+ return i;
+}
+
+int fdevent_linux_sysepoll_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
+#define SET(x) \
+ ev->x = fdevent_linux_sysepoll_##x;
+
+ SET(free);
+ SET(poll);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "epoll_create failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ fdevent_setfd_cloexec(ev->epoll_fd);
+
+ ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));
+ force_assert(NULL != ev->epoll_events);
+
+ return 0;
+}
+
+#else
+int fdevent_linux_sysepoll_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_poll.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_poll.c
new file mode 100644
index 000000000..76e941396
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_poll.c
@@ -0,0 +1,211 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef FDEVENT_USE_POLL
+
+# ifdef HAVE_POLL_H
+# include <poll.h>
+# else
+# include <sys/poll.h>
+# endif
+
+#ifndef POLLRDHUP
+#define POLLRDHUP 0
+#endif
+
+static void fdevent_poll_free(fdevents *ev) {
+ free(ev->pollfds);
+ if (ev->unused.ptr) free(ev->unused.ptr);
+}
+
+static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
+ if (fde_ndx < 0) return -1;
+
+ if ((size_t)fde_ndx >= ev->used) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SdD",
+ "del! out of range ", fde_ndx, (int) ev->used);
+ SEGFAULT();
+ }
+
+ if (ev->pollfds[fde_ndx].fd == fd) {
+ size_t k = fde_ndx;
+
+ ev->pollfds[k].fd = -1;
+ /* ev->pollfds[k].events = 0; */
+ /* ev->pollfds[k].revents = 0; */
+
+ if (ev->unused.size == 0) {
+ ev->unused.size = 16;
+ ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
+ force_assert(NULL != ev->unused.ptr);
+ } else if (ev->unused.size == ev->unused.used) {
+ ev->unused.size += 16;
+ ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
+ force_assert(NULL != ev->unused.ptr);
+ }
+
+ ev->unused.ptr[ev->unused.used++] = k;
+ } else {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SdD",
+ "del! ", ev->pollfds[fde_ndx].fd, fd);
+
+ SEGFAULT();
+ }
+
+ return -1;
+}
+
+#if 0
+static int fdevent_poll_event_compress(fdevents *ev) {
+ size_t j;
+
+ if (ev->used == 0) return 0;
+ if (ev->unused.used != 0) return 0;
+
+ for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
+
+ return 0;
+}
+#endif
+
+static int fdevent_poll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ int pevents = 0;
+ if (events & FDEVENT_IN) pevents |= POLLIN;
+ if (events & FDEVENT_OUT) pevents |= POLLOUT;
+ if (events & FDEVENT_RDHUP) pevents |= POLLRDHUP;
+
+ /* known index */
+
+ if (fde_ndx != -1) {
+ if (ev->pollfds[fde_ndx].fd == fd) {
+ ev->pollfds[fde_ndx].events = pevents;
+
+ return fde_ndx;
+ }
+ log_error_write(ev->srv, __FILE__, __LINE__, "SdD",
+ "set: ", fde_ndx, ev->pollfds[fde_ndx].fd);
+ SEGFAULT();
+ }
+
+ if (ev->unused.used > 0) {
+ int k = ev->unused.ptr[--ev->unused.used];
+
+ ev->pollfds[k].fd = fd;
+ ev->pollfds[k].events = pevents;
+
+ return k;
+ } else {
+ if (ev->size == 0) {
+ ev->size = 16;
+ ev->pollfds = malloc(sizeof(*ev->pollfds) * ev->size);
+ force_assert(NULL != ev->pollfds);
+ } else if (ev->size == ev->used) {
+ ev->size += 16;
+ ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
+ force_assert(NULL != ev->pollfds);
+ }
+
+ ev->pollfds[ev->used].fd = fd;
+ ev->pollfds[ev->used].events = pevents;
+
+ return ev->used++;
+ }
+}
+
+static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
+#if 0
+ fdevent_poll_event_compress(ev);
+#endif
+ return poll(ev->pollfds, ev->used, timeout_ms);
+}
+
+static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
+ int r, poll_r;
+
+ if (ndx >= ev->used) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "sii",
+ "dying because: event: ", (int) ndx, (int) ev->used);
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+ if (ev->pollfds[ndx].revents & POLLNVAL) {
+ /* should never happen */
+ SEGFAULT();
+ }
+
+ r = 0;
+ poll_r = ev->pollfds[ndx].revents;
+
+ /* map POLL* to FDEVEN_*; they are probably the same, but still. */
+
+ if (poll_r & POLLIN) r |= FDEVENT_IN;
+ if (poll_r & POLLOUT) r |= FDEVENT_OUT;
+ if (poll_r & POLLERR) r |= FDEVENT_ERR;
+ if (poll_r & POLLHUP) r |= FDEVENT_HUP;
+ if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
+ if (poll_r & POLLPRI) r |= FDEVENT_PRI;
+ if (poll_r & POLLRDHUP) r |= FDEVENT_RDHUP;
+
+ return r;
+}
+
+static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
+ return ev->pollfds[ndx].fd;
+}
+
+static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
+ size_t i;
+
+ i = (ndx < 0) ? 0 : ndx + 1;
+ for (; i < ev->used; i++) {
+ if (ev->pollfds[i].revents) return i;
+ }
+
+ return -1;
+}
+
+int fdevent_poll_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_POLL;
+#define SET(x) \
+ ev->x = fdevent_poll_##x;
+
+ SET(free);
+ SET(poll);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ return 0;
+}
+
+
+
+
+#else
+int fdevent_poll_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__,
+ "s", "poll is not supported, try to set server.event-handler = \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_select.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_select.c
new file mode 100644
index 000000000..2b4f85f47
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_select.c
@@ -0,0 +1,133 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef FDEVENT_USE_SELECT
+
+static int fdevent_select_reset(fdevents *ev) {
+ FD_ZERO(&(ev->select_set_read));
+ FD_ZERO(&(ev->select_set_write));
+ FD_ZERO(&(ev->select_set_error));
+ ev->select_max_fd = -1;
+
+ return 0;
+}
+
+static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
+ if (fde_ndx < 0) return -1;
+
+ FD_CLR(fd, &(ev->select_set_read));
+ FD_CLR(fd, &(ev->select_set_write));
+ FD_CLR(fd, &(ev->select_set_error));
+
+ return -1;
+}
+
+static int fdevent_select_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ UNUSED(fde_ndx);
+
+ /* we should be protected by max-fds, but you never know */
+ force_assert(fd < ((int)FD_SETSIZE));
+
+ if (events & FDEVENT_IN) {
+ FD_SET(fd, &(ev->select_set_read));
+ } else {
+ FD_CLR(fd, &(ev->select_set_read));
+ }
+ if (events & FDEVENT_OUT) {
+ FD_SET(fd, &(ev->select_set_write));
+ } else {
+ FD_CLR(fd, &(ev->select_set_write));
+ }
+ FD_SET(fd, &(ev->select_set_error));
+
+ if (fd > ev->select_max_fd) ev->select_max_fd = fd;
+
+ return fd;
+}
+
+static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
+ struct timeval tv;
+
+ tv.tv_sec = timeout_ms / 1000;
+ tv.tv_usec = (timeout_ms % 1000) * 1000;
+
+ ev->select_read = ev->select_set_read;
+ ev->select_write = ev->select_set_write;
+ ev->select_error = ev->select_set_error;
+
+ return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
+}
+
+static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
+ int revents = 0;
+
+ if (FD_ISSET(ndx, &(ev->select_read))) {
+ revents |= FDEVENT_IN;
+ }
+ if (FD_ISSET(ndx, &(ev->select_write))) {
+ revents |= FDEVENT_OUT;
+ }
+ if (FD_ISSET(ndx, &(ev->select_error))) {
+ revents |= FDEVENT_ERR;
+ }
+
+ return revents;
+}
+
+static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
+ UNUSED(ev);
+
+ return ndx;
+}
+
+static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
+ int i;
+
+ i = (ndx < 0) ? 0 : ndx + 1;
+
+ for (; i < ev->select_max_fd + 1; i++) {
+ if (FD_ISSET(i, &(ev->select_read))) return i;
+ if (FD_ISSET(i, &(ev->select_write))) return i;
+ if (FD_ISSET(i, &(ev->select_error))) return i;
+ }
+
+ return -1;
+}
+
+int fdevent_select_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_SELECT;
+#define SET(x) \
+ ev->x = fdevent_select_##x;
+
+ SET(reset);
+ SET(poll);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ return 0;
+}
+
+#else
+int fdevent_select_init(fdevents *ev) {
+ UNUSED(ev);
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_devpoll.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_devpoll.c
new file mode 100644
index 000000000..1eb8f756b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_devpoll.c
@@ -0,0 +1,172 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
+
+# include <sys/devpoll.h>
+# include <sys/ioctl.h>
+
+static void fdevent_solaris_devpoll_free(fdevents *ev) {
+ free(ev->devpollfds);
+ close(ev->devpoll_fd);
+}
+
+/* return -1 is fine here */
+
+static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
+ struct pollfd pfd;
+
+ if (fde_ndx < 0) return -1;
+
+ pfd.fd = fd;
+ pfd.events = POLLREMOVE;
+ pfd.revents = 0;
+
+ if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "S(D, S)",
+ "(del) write failed: ", fd, strerror(errno));
+
+ return -1;
+ }
+
+ return -1;
+}
+
+static int fdevent_solaris_devpoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ struct pollfd pfd;
+ int add = 0;
+
+ int pevents = 0;
+ if (events & FDEVENT_IN) pevents |= POLLIN;
+ if (events & FDEVENT_OUT) pevents |= POLLOUT;
+
+ if (fde_ndx == -1) add = 1;
+
+ pfd.fd = fd;
+ pfd.events = pevents;
+ pfd.revents = 0;
+
+ if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "S(D, S)",
+ "(set) write failed: ", fd, strerror(errno));
+
+ return -1;
+ }
+
+ return fd;
+}
+
+static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
+ struct dvpoll dopoll;
+ int ret;
+
+ dopoll.dp_timeout = timeout_ms;
+ dopoll.dp_nfds = ev->maxfds - 1;
+ dopoll.dp_fds = ev->devpollfds;
+
+ ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
+
+ return ret;
+}
+
+static int fdevent_solaris_devpoll_event_get_revent(fdevents *ev, size_t ndx) {
+ int r, poll_r;
+
+ r = 0;
+ poll_r = ev->devpollfds[ndx].revents;
+
+ /* map POLL* to FDEVEN_*; they are probably the same, but still. */
+
+ if (poll_r & POLLIN) r |= FDEVENT_IN;
+ if (poll_r & POLLOUT) r |= FDEVENT_OUT;
+ if (poll_r & POLLERR) r |= FDEVENT_ERR;
+ if (poll_r & POLLHUP) r |= FDEVENT_HUP;
+ if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
+ if (poll_r & POLLPRI) r |= FDEVENT_PRI;
+
+ return r;
+}
+
+static int fdevent_solaris_devpoll_event_get_fd(fdevents *ev, size_t ndx) {
+ return ev->devpollfds[ndx].fd;
+}
+
+static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
+ size_t i;
+
+ UNUSED(ev);
+
+ i = (last_ndx < 0) ? 0 : last_ndx + 1;
+
+ return i;
+}
+
+int fdevent_solaris_devpoll_reset(fdevents *ev) {
+ /* a forked process does only inherit the filedescriptor,
+ * but every operation on the device will lead to a EACCES */
+ if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "opening /dev/poll failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ fdevent_setfd_cloexec(ev->devpoll_fd);
+ return 0;
+}
+int fdevent_solaris_devpoll_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
+#define SET(x) \
+ ev->x = fdevent_solaris_devpoll_##x;
+
+ SET(free);
+ SET(poll);
+ SET(reset);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
+ force_assert(NULL != ev->devpollfds);
+
+ if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "opening /dev/poll failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ /* we just wanted to check if it works */
+ close(ev->devpoll_fd);
+
+ ev->devpoll_fd = -1;
+
+ return 0;
+}
+
+#else
+int fdevent_solaris_devpoll_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_port.c b/data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_port.c
new file mode 100644
index 000000000..ddfbb51b2
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/fdevent_solaris_port.c
@@ -0,0 +1,175 @@
+#include "first.h"
+
+#include "fdevent_impl.h"
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef FDEVENT_USE_SOLARIS_PORT
+
+#include <sys/poll.h>
+static const int SOLARIS_PORT_POLL_READ = POLLIN;
+static const int SOLARIS_PORT_POLL_WRITE = POLLOUT;
+static const int SOLARIS_PORT_POLL_READ_WRITE = POLLIN & POLLOUT;
+
+static int fdevent_solaris_port_event_del(fdevents *ev, int fde_ndx, int fd) {
+ if (fde_ndx < 0) return -1;
+
+ if (0 != port_dissociate(ev->port_fd, PORT_SOURCE_FD, fd)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_dissociate failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static int fdevent_solaris_port_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ const int* user_data = NULL;
+
+ if ((events & FDEVENT_IN) && (events & FDEVENT_OUT)) {
+ user_data = &SOLARIS_PORT_POLL_READ_WRITE;
+ } else if (events & FDEVENT_IN) {
+ user_data = &SOLARIS_PORT_POLL_READ;
+ } else if (events & FDEVENT_OUT) {
+ user_data = &SOLARIS_PORT_POLL_WRITE;
+ }
+
+ if (0 != port_associate(ev->port_fd, PORT_SOURCE_FD, fd, *user_data, (void*) user_data)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_associate failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+ return fd;
+}
+
+static int fdevent_solaris_port_event_get_revent(fdevents *ev, size_t ndx) {
+ int events = 0, e;
+
+ e = ev->port_events[ndx].portev_events;
+ if (e & POLLIN) events |= FDEVENT_IN;
+ if (e & POLLOUT) events |= FDEVENT_OUT;
+ if (e & POLLERR) events |= FDEVENT_ERR;
+ if (e & POLLHUP) events |= FDEVENT_HUP;
+ if (e & POLLPRI) events |= FDEVENT_PRI;
+ if (e & POLLNVAL) events |= FDEVENT_NVAL;
+
+ return e;
+}
+
+static int fdevent_solaris_port_event_get_fd(fdevents *ev, size_t ndx) {
+ return ev->port_events[ndx].portev_object;
+}
+
+static int fdevent_solaris_port_event_next_fdndx(fdevents *ev, int ndx) {
+ size_t i;
+
+ UNUSED(ev);
+
+ i = (ndx < 0) ? 0 : ndx + 1;
+
+ return i;
+}
+
+static void fdevent_solaris_port_free(fdevents *ev) {
+ close(ev->port_fd);
+ free(ev->port_events);
+}
+
+/* if there is any error it will return the return values of port_getn, otherwise it will return number of events **/
+static int fdevent_solaris_port_poll(fdevents *ev, int timeout_ms) {
+ int i = 0;
+ int ret;
+ unsigned int available_events, wait_for_events = 0;
+ const int *user_data;
+
+ struct timespec timeout;
+
+ timeout.tv_sec = timeout_ms/1000L;
+ timeout.tv_nsec = (timeout_ms % 1000L) * 1000000L;
+
+ /* get the number of file descriptors with events */
+ if ((ret = port_getn(ev->port_fd, ev->port_events, 0, &wait_for_events, &timeout)) < 0) return ret;
+
+ /* wait for at least one event */
+ if (0 == wait_for_events) wait_for_events = 1;
+
+ available_events = wait_for_events;
+
+ /* get the events of the file descriptors */
+ if ((ret = port_getn(ev->port_fd, ev->port_events, ev->maxfds, &available_events, &timeout)) < 0) {
+ /* if errno == ETIME and available_event == wait_for_events we didn't get any events */
+ /* for other errors we didn't get any events either */
+ if (!(errno == ETIME && wait_for_events != available_events)) return ret;
+ }
+
+ for (i = 0; i < available_events; ++i) {
+ user_data = (const int *) ev->port_events[i].portev_user;
+
+ if ((ret = port_associate(ev->port_fd, PORT_SOURCE_FD, ev->port_events[i].portev_object,
+ *user_data, (void*) user_data)) < 0) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_associate failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+ }
+
+ return available_events;
+}
+
+int fdevent_solaris_port_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_SOLARIS_PORT;
+#define SET(x) \
+ ev->x = fdevent_solaris_port_##x;
+
+ SET(free);
+ SET(poll);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ if ((ev->port_fd = port_create()) < 0) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_create() failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ ev->port_events = malloc(ev->maxfds * sizeof(*ev->port_events));
+ force_assert(NULL != ev->port_events);
+
+ return 0;
+}
+
+#else
+int fdevent_solaris_port_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "solaris-eventports not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/first.h b/data/lighttpd/lighttpd-1.4.53/src/first.h
new file mode 100644
index 000000000..38c259296
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/first.h
@@ -0,0 +1,97 @@
+#ifndef LI_FIRST_H
+#define LI_FIRST_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+#endif
+
+#ifndef __STDC_WANT_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1
+#endif
+
+#ifdef __COVERITY__
+#define _Float128 long double
+#define _Float64x long double
+#define _Float64 double
+#define _Float32x double
+#define _Float32 float
+#endif
+
+
+#include <sys/types.h>
+#include <stddef.h>
+
+#if defined HAVE_STDINT_H
+# include <stdint.h>
+#elif defined HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+
+/* solaris and NetBSD 1.3.x again */
+#if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
+# define uint32_t u_int32_t
+#endif
+
+
+#include <limits.h>
+
+#ifndef SIZE_MAX
+# ifdef SIZE_T_MAX
+# define SIZE_MAX SIZE_T_MAX
+# else
+# define SIZE_MAX (~(size_t)0u)
+# endif
+#endif
+
+#ifndef SSIZE_MAX
+# define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1))
+#endif
+
+
+#define UNUSED(x) ( (void)(x) )
+
+
+#ifndef __has_attribute /* clang */
+#define __has_attribute(x) 0
+#endif
+
+#ifdef __GNUC__
+#ifndef __GNUC_PREREQ
+# ifdef __GNUC_PREREQ__
+# define __GNUC_PREREQ __GNUC_PREREQ__
+# elif defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+# define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+#else
+#define __GNUC_PREREQ(maj,min) 0
+#endif
+
+#ifndef __attribute_cold__
+#if __has_attribute(cold) \
+ || __GNUC_PREREQ(4,3)
+#define __attribute_cold__ __attribute__((__cold__))
+#else
+#define __attribute_cold__
+#endif
+#endif
+
+#ifndef __attribute_noreturn__
+#if __has_attribute(noreturn) \
+ || __GNUC_PREREQ(2,5)
+#define __attribute_noreturn__ __attribute__((__noreturn__))
+#else
+#define __attribute_noreturn__
+#endif
+#endif
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/gw_backend.c b/data/lighttpd/lighttpd-1.4.53/src/gw_backend.c
new file mode 100644
index 000000000..62183febb
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/gw_backend.c
@@ -0,0 +1,2604 @@
+#include "first.h"
+
+#include "gw_backend.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sys-socket.h"
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base.h"
+#include "array.h"
+#include "buffer.h"
+#include "crc32.h"
+#include "fdevent.h"
+#include "log.h"
+#include "sock_addr.h"
+
+
+
+
+#include "status_counter.h"
+
+static int * gw_status_get_counter(server *srv, gw_host *host, gw_proc *proc, const char *tag, size_t len) {
+ buffer *b = srv->tmp_buf;
+ buffer_copy_string_len(b, CONST_STR_LEN("gw.backend."));
+ buffer_append_string_buffer(b, host->id);
+ if (proc) {
+ buffer_append_string_len(b, CONST_STR_LEN("."));
+ buffer_append_int(b, proc->id);
+ }
+ buffer_append_string_len(b, tag, len);
+ return status_counter_get_counter(srv, CONST_BUF_LEN(b));
+}
+
+static void gw_proc_tag_inc(server *srv, gw_host *host, gw_proc *proc, const char *tag, size_t len) {
+ ++(*gw_status_get_counter(srv, host, proc, tag, len));
+}
+
+static void gw_proc_load_inc(server *srv, gw_host *host, gw_proc *proc) {
+ *gw_status_get_counter(srv,host,proc,CONST_STR_LEN(".load")) = ++proc->load;
+
+ status_counter_inc(srv, CONST_STR_LEN("gw.active-requests"));
+}
+
+static void gw_proc_load_dec(server *srv, gw_host *host, gw_proc *proc) {
+ *gw_status_get_counter(srv,host,proc,CONST_STR_LEN(".load")) = --proc->load;
+
+ status_counter_dec(srv, CONST_STR_LEN("gw.active-requests"));
+}
+
+static void gw_host_assign(server *srv, gw_host *host) {
+ *gw_status_get_counter(srv,host,NULL,CONST_STR_LEN(".load")) = ++host->load;
+}
+
+static void gw_host_reset(server *srv, gw_host *host) {
+ *gw_status_get_counter(srv,host,NULL,CONST_STR_LEN(".load")) = --host->load;
+}
+
+static int gw_status_init(server *srv, gw_host *host, gw_proc *proc) {
+ *gw_status_get_counter(srv, host, proc, CONST_STR_LEN(".disabled")) = 0;
+ *gw_status_get_counter(srv, host, proc, CONST_STR_LEN(".died")) = 0;
+ *gw_status_get_counter(srv, host, proc, CONST_STR_LEN(".overloaded")) = 0;
+ *gw_status_get_counter(srv, host, proc, CONST_STR_LEN(".connected")) = 0;
+ *gw_status_get_counter(srv, host, proc, CONST_STR_LEN(".load")) = 0;
+
+ *gw_status_get_counter(srv, host, NULL, CONST_STR_LEN(".load")) = 0;
+
+ return 0;
+}
+
+
+
+
+static void gw_proc_set_state(gw_host *host, gw_proc *proc, int state) {
+ if ((int)proc->state == state) return;
+ if (proc->state == PROC_STATE_RUNNING) {
+ --host->active_procs;
+ } else if (state == PROC_STATE_RUNNING) {
+ ++host->active_procs;
+ }
+ proc->state = state;
+}
+
+
+static gw_proc *gw_proc_init(void) {
+ gw_proc *f = calloc(1, sizeof(*f));
+ force_assert(f);
+
+ f->unixsocket = buffer_init();
+ f->connection_name = buffer_init();
+
+ f->prev = NULL;
+ f->next = NULL;
+ f->state = PROC_STATE_DIED;
+
+ return f;
+}
+
+static void gw_proc_free(gw_proc *f) {
+ if (!f) return;
+
+ gw_proc_free(f->next);
+
+ buffer_free(f->unixsocket);
+ buffer_free(f->connection_name);
+ free(f->saddr);
+
+ free(f);
+}
+
+static gw_host *gw_host_init(void) {
+ gw_host *f = calloc(1, sizeof(*f));
+ force_assert(f);
+
+ f->id = buffer_init();
+ f->host = buffer_init();
+ f->unixsocket = buffer_init();
+ f->docroot = buffer_init();
+ f->bin_path = buffer_init();
+ f->bin_env = array_init();
+ f->bin_env_copy = array_init();
+ f->strip_request_uri = buffer_init();
+ f->xsendfile_docroot = array_init();
+
+ return f;
+}
+
+static void gw_host_free(gw_host *h) {
+ if (!h) return;
+ if (h->refcount) {
+ --h->refcount;
+ return;
+ }
+
+ buffer_free(h->id);
+ buffer_free(h->host);
+ buffer_free(h->unixsocket);
+ buffer_free(h->docroot);
+ buffer_free(h->bin_path);
+ buffer_free(h->strip_request_uri);
+ array_free(h->bin_env);
+ array_free(h->bin_env_copy);
+ array_free(h->xsendfile_docroot);
+
+ gw_proc_free(h->first);
+ gw_proc_free(h->unused_procs);
+
+ for (size_t i = 0; i < h->args.used; ++i) free(h->args.ptr[i]);
+ free(h->args.ptr);
+ free(h);
+}
+
+static gw_exts *gw_extensions_init(void) {
+ gw_exts *f = calloc(1, sizeof(*f));
+ force_assert(f);
+ return f;
+}
+
+static void gw_extensions_free(gw_exts *f) {
+ if (!f) return;
+ for (size_t i = 0; i < f->used; ++i) {
+ gw_extension *fe = f->exts[i];
+ for (size_t j = 0; j < fe->used; ++j) {
+ gw_host_free(fe->hosts[j]);
+ }
+ buffer_free(fe->key);
+ free(fe->hosts);
+ free(fe);
+ }
+ free(f->exts);
+ free(f);
+}
+
+static int gw_extension_insert(gw_exts *ext, buffer *key, gw_host *fh) {
+ gw_extension *fe = NULL;
+ for (size_t i = 0; i < ext->used; ++i) {
+ if (buffer_is_equal(key, ext->exts[i]->key)) {
+ fe = ext->exts[i];
+ break;
+ }
+ }
+
+ if (NULL == fe) {
+ fe = calloc(1, sizeof(*fe));
+ force_assert(fe);
+ fe->key = buffer_init();
+ fe->last_used_ndx = -1;
+ buffer_copy_buffer(fe->key, key);
+
+ if (ext->size == 0) {
+ ext->size = 8;
+ ext->exts = malloc(ext->size * sizeof(*(ext->exts)));
+ force_assert(ext->exts);
+ } else if (ext->used == ext->size) {
+ ext->size += 8;
+ ext->exts = realloc(ext->exts, ext->size * sizeof(*(ext->exts)));
+ force_assert(ext->exts);
+ }
+ ext->exts[ext->used++] = fe;
+ fe->size = 4;
+ fe->hosts = malloc(fe->size * sizeof(*(fe->hosts)));
+ force_assert(fe->hosts);
+ } else if (fe->size == fe->used) {
+ fe->size += 4;
+ fe->hosts = realloc(fe->hosts, fe->size * sizeof(*(fe->hosts)));
+ force_assert(fe->hosts);
+ }
+
+ fe->hosts[fe->used++] = fh;
+ return 0;
+}
+
+static void gw_proc_connect_success(server *srv, gw_host *host, gw_proc *proc, int debug) {
+ gw_proc_tag_inc(srv, host, proc, CONST_STR_LEN(".connected"));
+ proc->last_used = srv->cur_ts;
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
+ "got proc:",
+ "pid:", proc->pid,
+ "socket:", proc->connection_name,
+ "load:", proc->load);
+ }
+}
+
+static void gw_proc_connect_error(server *srv, gw_host *host, gw_proc *proc, pid_t pid, int errnum, int debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
+ "establishing connection failed:", strerror(errnum),
+ "socket:", proc->connection_name);
+
+ if (!proc->is_local) {
+ proc->disabled_until = srv->cur_ts + host->disable_time;
+ gw_proc_set_state(host, proc, PROC_STATE_OVERLOADED);
+ }
+ else if (proc->pid == pid && proc->state == PROC_STATE_RUNNING) {
+ /* several requests from lighttpd might reference the same proc
+ *
+ * Only one of them should mark the proc
+ * and all other ones should just take a new one.
+ *
+ * If a new proc was started with the old struct, this might
+ * otherwise lead to marking a perfectly good proc as dead
+ */
+ log_error_write(srv, __FILE__, __LINE__, "sdssd",
+ "backend error; we'll disable for", host->disable_time,
+ "secs and send the request to another backend instead:",
+ "load:", host->load);
+ if (EAGAIN == errnum) {
+ /* - EAGAIN: cool down the backend; it is overloaded */
+ #ifdef __linux__
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "If this happened on Linux: You have run out of local ports. "
+ "Check the manual, section Performance how to handle this.");
+ #endif
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsd",
+ "This means that you have more incoming requests than your "
+ "FastCGI backend can handle in parallel. It might help to "
+ "spawn more FastCGI backends or PHP children; if not, "
+ "decrease server.max-connections. The load for this FastCGI "
+ "backend", proc->connection_name, "is", proc->load);
+ }
+ proc->disabled_until = srv->cur_ts + host->disable_time;
+ gw_proc_set_state(host, proc, PROC_STATE_OVERLOADED);
+ }
+ else {
+ /* we got a hard error from the backend like
+ * - ECONNREFUSED for tcp-ip sockets
+ * - ENOENT for unix-domain-sockets
+ */
+ #if 0
+ gw_proc_set_state(host, proc, PROC_STATE_DIED_WAIT_FOR_PID);
+ #else /* treat as overloaded (future: unless we send kill() signal)*/
+ proc->disabled_until = srv->cur_ts + host->disable_time;
+ gw_proc_set_state(host, proc, PROC_STATE_OVERLOADED);
+ #endif
+ }
+ }
+
+ if (EAGAIN == errnum) {
+ gw_proc_tag_inc(srv, host, proc, CONST_STR_LEN(".overloaded"));
+ }
+ else {
+ gw_proc_tag_inc(srv, host, proc, CONST_STR_LEN(".died"));
+ }
+}
+
+static void gw_proc_release(server *srv, gw_host *host, gw_proc *proc, int debug) {
+ gw_proc_load_dec(srv, host, proc);
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
+ "released proc:",
+ "pid:", proc->pid,
+ "socket:", proc->connection_name,
+ "load:", proc->load);
+ }
+}
+
+static void gw_proc_check_enable(server *srv, gw_host *host, gw_proc *proc) {
+ if (srv->cur_ts <= proc->disabled_until) return;
+ if (proc->state != PROC_STATE_OVERLOADED) return;
+
+ gw_proc_set_state(host, proc, PROC_STATE_RUNNING);
+
+ log_error_write(srv, __FILE__, __LINE__, "sbbdb",
+ "gw-server re-enabled:", proc->connection_name,
+ host->host, host->port, host->unixsocket);
+}
+
+static void gw_proc_waitpid_log(server *srv, gw_host *host, gw_proc *proc, int status) {
+ UNUSED(host);
+ if (WIFEXITED(status)) {
+ if (proc->state != PROC_STATE_KILLED) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "child exited:",
+ WEXITSTATUS(status), proc->connection_name);
+ }
+ } else if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) != SIGTERM && WTERMSIG(status) != SIGINT
+ && WTERMSIG(status) != host->kill_signal) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signalled:", WTERMSIG(status));
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:", status);
+ }
+}
+
+static int gw_proc_waitpid(server *srv, gw_host *host, gw_proc *proc) {
+ int rc, status;
+
+ if (!proc->is_local) return 0;
+ if (proc->pid <= 0) return 0;
+
+ do {
+ rc = waitpid(proc->pid, &status, WNOHANG);
+ } while (-1 == rc && errno == EINTR);
+ if (0 == rc) return 0; /* child still running */
+
+ /* child terminated */
+ if (-1 == rc) {
+ /* EINVAL or ECHILD no child processes */
+ /* should not happen; someone else has cleaned up for us */
+ log_error_write(srv, __FILE__, __LINE__, "sddss",
+ "pid ", proc->pid, proc->state,
+ "not found:", strerror(errno));
+ }
+ else {
+ gw_proc_waitpid_log(srv, host, proc, status);
+ }
+
+ proc->pid = 0;
+ if (proc->state != PROC_STATE_KILLED)
+ proc->disabled_until = srv->cur_ts;
+ gw_proc_set_state(host, proc, PROC_STATE_DIED);
+ return 1;
+}
+
+static int gw_proc_sockaddr_init(server *srv, gw_host *host, gw_proc *proc) {
+ sock_addr addr;
+ socklen_t addrlen;
+
+ if (!buffer_string_is_empty(proc->unixsocket)) {
+ if (1 != sock_addr_from_str_hints(srv, &addr, &addrlen,
+ proc->unixsocket->ptr, AF_UNIX, 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
+ buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
+ }
+ else {
+ /*(note: name resolution here is *blocking* if IP string not supplied)*/
+ if (1 != sock_addr_from_str_hints(srv, &addr, &addrlen,
+ host->host->ptr, 0, proc->port)) {
+ errno = EINVAL;
+ return -1;
+ }
+ else {
+ /* overwrite host->host buffer with IP addr string so that
+ * any further use of gw_host does not block on DNS lookup */
+ sock_addr_inet_ntop_copy_buffer(host->host, &addr);
+ host->family = sock_addr_get_family(&addr);
+ }
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
+ buffer_append_int(proc->connection_name, proc->port);
+ }
+
+ if (NULL != proc->saddr && proc->saddrlen < addrlen) {
+ free(proc->saddr);
+ proc->saddr = NULL;
+ }
+ if (NULL == proc->saddr) {
+ proc->saddr = (struct sockaddr *)malloc(addrlen);
+ force_assert(proc->saddr);
+ }
+ proc->saddrlen = addrlen;
+ memcpy(proc->saddr, &addr, addrlen);
+ return 0;
+}
+
+static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
+ char *dst;
+
+ if (!key || !val) return -1;
+
+ dst = malloc(key_len + val_len + 3);
+ force_assert(dst);
+ memcpy(dst, key, key_len);
+ dst[key_len] = '=';
+ memcpy(dst + key_len + 1, val, val_len + 1); /* add the \0 from the value */
+
+ for (size_t i = 0; i < env->used; ++i) {
+ if (0 == strncmp(dst, env->ptr[i], key_len + 1)) {
+ free(env->ptr[i]);
+ env->ptr[i] = dst;
+ return 0;
+ }
+ }
+
+ if (env->size == 0) {
+ env->size = 16;
+ env->ptr = malloc(env->size * sizeof(*env->ptr));
+ force_assert(env->ptr);
+ } else if (env->size == env->used + 1) {
+ env->size += 16;
+ env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
+ force_assert(env->ptr);
+ }
+
+ env->ptr[env->used++] = dst;
+
+ return 0;
+}
+
+static int gw_spawn_connection(server *srv, gw_host *host, gw_proc *proc, int debug) {
+ int gw_fd;
+ int status;
+ struct timeval tv = { 0, 10 * 1000 };
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "new proc, socket:", proc->port, proc->unixsocket);
+ }
+
+ gw_fd = fdevent_socket_cloexec(proc->saddr->sa_family, SOCK_STREAM, 0);
+ if (-1 == gw_fd) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "failed:", strerror(errno));
+ return -1;
+ }
+
+ do {
+ status = connect(gw_fd, proc->saddr, proc->saddrlen);
+ } while (-1 == status && errno == EINTR);
+
+ if (-1 == status && errno != ENOENT
+ && !buffer_string_is_empty(proc->unixsocket)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "unlink", proc->unixsocket,
+ "after connect failed:", strerror(errno));
+ unlink(proc->unixsocket->ptr);
+ }
+
+ close(gw_fd);
+
+ if (-1 == status) {
+ /* server is not up, spawn it */
+ char_array env;
+ size_t i;
+ int dfd = -1;
+
+ /* reopen socket */
+ gw_fd = fdevent_socket_cloexec(proc->saddr->sa_family, SOCK_STREAM, 0);
+ if (-1 == gw_fd) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "socket failed:", strerror(errno));
+ return -1;
+ }
+
+ if (fdevent_set_so_reuseaddr(gw_fd, 1) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "socketsockopt failed:", strerror(errno));
+ close(gw_fd);
+ return -1;
+ }
+
+ /* create socket */
+ if (-1 == bind(gw_fd, proc->saddr, proc->saddrlen)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "bind failed for:",
+ proc->connection_name,
+ strerror(errno));
+ close(gw_fd);
+ return -1;
+ }
+
+ if (-1 == listen(gw_fd, host->listen_backlog)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "listen failed:", strerror(errno));
+ close(gw_fd);
+ return -1;
+ }
+
+ {
+ /* create environment */
+ env.ptr = NULL;
+ env.size = 0;
+ env.used = 0;
+
+ /* build clean environment */
+ if (host->bin_env_copy->used) {
+ for (i = 0; i < host->bin_env_copy->used; ++i) {
+ data_string *ds=(data_string *)host->bin_env_copy->data[i];
+ char *ge;
+
+ if (NULL != (ge = getenv(ds->value->ptr))) {
+ env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
+ }
+ }
+ } else {
+ char ** const e = fdevent_environ();
+ for (i = 0; e[i]; ++i) {
+ char *eq;
+
+ if (NULL != (eq = strchr(e[i], '='))) {
+ env_add(&env, e[i], eq - e[i], eq+1, strlen(eq+1));
+ }
+ }
+ }
+
+ /* create environment */
+ for (i = 0; i < host->bin_env->used; ++i) {
+ data_string *ds = (data_string *)host->bin_env->data[i];
+
+ env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
+ }
+
+ for (i = 0; i < env.used; ++i) {
+ /* search for PHP_FCGI_CHILDREN */
+ if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=",
+ sizeof("PHP_FCGI_CHILDREN=")-1)) {
+ break;
+ }
+ }
+
+ /* not found, add a default */
+ if (i == env.used) {
+ env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"),
+ CONST_STR_LEN("1"));
+ }
+
+ env.ptr[env.used] = NULL;
+ }
+
+ dfd = fdevent_open_dirname(host->args.ptr[0]);
+ if (-1 == dfd) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "open dirname failed:", strerror(errno),
+ host->args.ptr[0]);
+ }
+
+ /*(FCGI_LISTENSOCK_FILENO == STDIN_FILENO == 0)*/
+ proc->pid = (dfd >= 0)
+ ? fdevent_fork_execve(host->args.ptr[0], host->args.ptr,
+ env.ptr, gw_fd, -1, -1, dfd)
+ : -1;
+
+ for (i = 0; i < env.used; ++i) free(env.ptr[i]);
+ free(env.ptr);
+ if (-1 != dfd) close(dfd);
+ close(gw_fd);
+
+ if (-1 == proc->pid) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "gw-backend failed to start:", host->bin_path);
+ proc->pid = 0;
+ proc->disabled_until = srv->cur_ts;
+ return -1;
+ }
+
+ /* register process */
+ proc->last_used = srv->cur_ts;
+ proc->is_local = 1;
+
+ /* wait */
+ select(0, NULL, NULL, NULL, &tv);
+
+ if (0 != gw_proc_waitpid(srv, host, proc)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "gw-backend failed to start:", host->bin_path);
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "If you're trying to run your app as a FastCGI backend, make "
+ "sure you're using the FastCGI-enabled version. If this is PHP "
+ "on Gentoo, add 'fastcgi' to the USE flags. If this is PHP, try "
+ "removing the bytecode caches for now and try again.");
+ return -1;
+ }
+ } else {
+ proc->is_local = 0;
+ proc->pid = 0;
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "(debug) socket is already used; won't spawn:",
+ proc->connection_name);
+ }
+ }
+
+ gw_proc_set_state(host, proc, PROC_STATE_RUNNING);
+ return 0;
+}
+
+static void gw_proc_spawn(server *srv, gw_host *host, int debug) {
+ gw_proc *proc;
+ for (proc = host->unused_procs; proc; proc = proc->next) {
+ /* (proc->pid <= 0 indicates PROC_STATE_DIED, not PROC_STATE_KILLED) */
+ if (proc->pid > 0) continue;
+ /* (do not attempt to spawn another proc if a proc just exited) */
+ if (proc->disabled_until >= srv->cur_ts) return;
+ break;
+ }
+ if (proc) {
+ if (proc == host->unused_procs)
+ host->unused_procs = proc->next;
+ else
+ proc->prev->next = proc->next;
+
+ if (proc->next) {
+ proc->next->prev = proc->prev;
+ proc->next = NULL;
+ }
+
+ proc->prev = NULL;
+ } else {
+ proc = gw_proc_init();
+ proc->id = host->max_id++;
+ }
+
+ ++host->num_procs;
+
+ if (buffer_string_is_empty(host->unixsocket)) {
+ proc->port = host->port + proc->id;
+ } else {
+ buffer_copy_buffer(proc->unixsocket, host->unixsocket);
+ buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));
+ buffer_append_int(proc->unixsocket, proc->id);
+ }
+
+ if (0 != gw_proc_sockaddr_init(srv, host, proc)) {
+ /*(should not happen if host->host validated at startup,
+ * and translated from name to IP address at startup)*/
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: spawning backend failed.");
+ --host->num_procs;
+ if (proc->id == host->max_id-1) --host->max_id;
+ gw_proc_free(proc);
+ } else if (gw_spawn_connection(srv, host, proc, debug)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: spawning backend failed.");
+ proc->next = host->unused_procs;
+ if (host->unused_procs)
+ host->unused_procs->prev = proc;
+ host->unused_procs = proc;
+ } else {
+ proc->next = host->first;
+ if (host->first)
+ host->first->prev = proc;
+ host->first = proc;
+ }
+}
+
+static void gw_proc_kill(server *srv, gw_host *host, gw_proc *proc) {
+ UNUSED(srv);
+ if (proc->next) proc->next->prev = proc->prev;
+ if (proc->prev) proc->prev->next = proc->next;
+
+ if (proc->prev == NULL) host->first = proc->next;
+
+ proc->prev = NULL;
+ proc->next = host->unused_procs;
+ proc->disabled_until = 0;
+
+ if (host->unused_procs)
+ host->unused_procs->prev = proc;
+ host->unused_procs = proc;
+
+ kill(proc->pid, host->kill_signal);
+
+ gw_proc_set_state(host, proc, PROC_STATE_KILLED);
+
+ --host->num_procs;
+}
+
+static gw_host * unixsocket_is_dup(gw_plugin_data *p, size_t used, buffer *unixsocket) {
+ for (size_t i = 0; i < used; ++i) {
+ gw_exts *exts = p->config_storage[i]->exts;
+ if (NULL == exts) continue;
+ for (size_t j = 0; j < exts->used; ++j) {
+ gw_extension *ex = exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ gw_host *host = ex->hosts[n];
+ if (!buffer_string_is_empty(host->unixsocket)
+ && buffer_is_equal(host->unixsocket, unixsocket)
+ && !buffer_string_is_empty(host->bin_path))
+ return host;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int parse_binpath(char_array *env, buffer *b) {
+ char *start = b->ptr;
+ char c;
+ /* search for spaces */
+ for (size_t i = 0; i < buffer_string_length(b); ++i) {
+ switch(b->ptr[i]) {
+ case ' ':
+ case '\t':
+ /* a WS, stop here and copy the argument */
+
+ if (env->size == 0) {
+ env->size = 16;
+ env->ptr = malloc(env->size * sizeof(*env->ptr));
+ } else if (env->size == env->used) {
+ env->size += 16;
+ env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
+ }
+
+ c = b->ptr[i];
+ b->ptr[i] = '\0';
+ env->ptr[env->used++] = strdup(start);
+ b->ptr[i] = c;
+
+ start = b->ptr + i + 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (env->size == 0) {
+ env->size = 16;
+ env->ptr = malloc(env->size * sizeof(*env->ptr));
+ } else if (env->size == env->used) { /*need one extra for terminating NULL*/
+ env->size += 16;
+ env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
+ }
+
+ /* the rest */
+ env->ptr[env->used++] = strdup(start);
+
+ if (env->size == 0) {
+ env->size = 16;
+ env->ptr = malloc(env->size * sizeof(*env->ptr));
+ } else if (env->size == env->used) { /*need one extra for terminating NULL*/
+ env->size += 16;
+ env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
+ }
+
+ /* terminate */
+ env->ptr[env->used++] = NULL;
+
+ return 0;
+}
+
+enum {
+ GW_BALANCE_LEAST_CONNECTION,
+ GW_BALANCE_RR,
+ GW_BALANCE_HASH,
+ GW_BALANCE_STICKY
+};
+
+static gw_host * gw_host_get(server *srv, connection *con, gw_extension *extension, int balance, int debug) {
+ gw_host *host;
+ unsigned long last_max = ULONG_MAX;
+ int max_usage = INT_MAX;
+ int ndx = -1;
+ size_t k;
+
+ if (extension->used <= 1) {
+ if (1 == extension->used && extension->hosts[0]->active_procs > 0) {
+ ndx = 0;
+ }
+ } else switch(balance) {
+ case GW_BALANCE_HASH:
+ /* hash balancing */
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "proxy - used hash balancing, hosts:",
+ extension->used);
+ }
+
+ for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->used; ++k) {
+ unsigned long cur_max;
+ host = extension->hosts[k];
+ if (0 == host->active_procs) continue;
+
+ cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path))
+ + generate_crc32c(CONST_BUF_LEN(host->host)) /* cachable */
+ + generate_crc32c(CONST_BUF_LEN(con->uri.authority));
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbbbd",
+ "proxy - election:", con->uri.path,
+ host->host, con->uri.authority, cur_max);
+ }
+
+ if (last_max < cur_max || last_max == ULONG_MAX) {
+ last_max = cur_max;
+ ndx = k;
+ }
+ }
+
+ break;
+ case GW_BALANCE_LEAST_CONNECTION:
+ /* fair balancing */
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "proxy - used least connection");
+ }
+
+ for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->used; ++k) {
+ host = extension->hosts[k];
+ if (0 == host->active_procs) continue;
+
+ if (host->load < max_usage) {
+ max_usage = host->load;
+ ndx = k;
+ }
+ }
+
+ break;
+ case GW_BALANCE_RR:
+ /* round robin */
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "proxy - used round-robin balancing");
+ }
+
+ /* just to be sure */
+ force_assert(extension->used < INT_MAX);
+
+ host = extension->hosts[0];
+
+ /* Use last_used_ndx from first host in list */
+ k = extension->last_used_ndx;
+ ndx = k + 1; /* use next host after the last one */
+ if (ndx < 0) ndx = 0;
+
+ /* Search first active host after last_used_ndx */
+ while (ndx < (int) extension->used
+ && 0 == (host = extension->hosts[ndx])->active_procs) ++ndx;
+
+ if (ndx >= (int) extension->used) {
+ /* didn't find a higher id, wrap to the start */
+ for (ndx = 0; ndx <= (int) k; ++ndx) {
+ host = extension->hosts[ndx];
+ if (0 != host->active_procs) break;
+ }
+
+ /* No active host found */
+ if (0 == host->active_procs) ndx = -1;
+ }
+
+ /* Save new index for next round */
+ extension->last_used_ndx = ndx;
+
+ break;
+ case GW_BALANCE_STICKY:
+ /* source sticky balancing */
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "proxy - used sticky balancing, hosts:",
+ extension->used);
+ }
+
+ for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->used; ++k) {
+ unsigned long cur_max;
+ host = extension->hosts[k];
+
+ if (0 == host->active_procs) continue;
+
+ cur_max = generate_crc32c(CONST_BUF_LEN(con->dst_addr_buf))
+ + generate_crc32c(CONST_BUF_LEN(host->host))
+ + host->port;
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbbdd",
+ "proxy - election:", con->dst_addr_buf,
+ host->host, host->port, cur_max);
+ }
+
+ if (last_max < cur_max || last_max == ULONG_MAX) {
+ last_max = cur_max;
+ ndx = k;
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ if (-1 != ndx) {
+ /* found a server */
+ host = extension->hosts[ndx];
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbd",
+ "gw - found a host", host->host, host->port);
+ }
+
+ return host;
+ } else if (0 == srv->srvconf.max_worker) {
+ /* special-case adaptive spawning and 0 == host->min_procs */
+ for (k = 0; k < extension->used; ++k) {
+ host = extension->hosts[k];
+ if (0 == host->min_procs && 0 == host->num_procs
+ && !buffer_string_is_empty(host->bin_path)) {
+ gw_proc_spawn(srv, host, debug);
+ if (host->num_procs) return host;
+ }
+ }
+ }
+
+ /* all hosts are down */
+ /* sorry, we don't have a server alive for this ext */
+ con->http_status = 503; /* Service Unavailable */
+ con->mode = DIRECT;
+
+ /* only send the 'no handler' once */
+ if (!extension->note_is_sent) {
+ extension->note_is_sent = 1;
+ log_error_write(srv, __FILE__, __LINE__, "sBSbsbs",
+ "all handlers for", con->uri.path, "?",
+ con->uri.query, "on", extension->key, "are down.");
+ }
+
+ return NULL;
+}
+
+static int gw_establish_connection(server *srv, gw_host *host, gw_proc *proc, pid_t pid, int gw_fd, int debug) {
+ if (-1 == connect(gw_fd, proc->saddr, proc->saddrlen)) {
+ if (errno == EINPROGRESS ||
+ errno == EALREADY ||
+ errno == EINTR) {
+ if (debug > 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connect delayed; will continue later:",
+ proc->connection_name);
+ }
+
+ return 1;
+ } else {
+ gw_proc_connect_error(srv, host, proc, pid, errno, debug);
+ return -1;
+ }
+ }
+
+ if (debug > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "connect succeeded: ", gw_fd);
+ }
+
+ return 0;
+}
+
+static void gw_restart_dead_procs(server *srv, gw_host *host, int debug, int trigger) {
+ for (gw_proc *proc = host->first; proc; proc = proc->next) {
+ if (debug > 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sbdddd",
+ "proc:", proc->connection_name, proc->state,
+ proc->is_local, proc->load, proc->pid);
+ }
+
+ switch (proc->state) {
+ case PROC_STATE_RUNNING:
+ break;
+ case PROC_STATE_OVERLOADED:
+ gw_proc_check_enable(srv, host, proc);
+ break;
+ case PROC_STATE_KILLED:
+ if (trigger && ++proc->disabled_until > 4) {
+ int sig = (proc->disabled_until <= 8)
+ ? host->kill_signal
+ : proc->disabled_until <= 16 ? SIGTERM : SIGKILL;
+ kill(proc->pid, sig);
+ }
+ break;
+ case PROC_STATE_DIED_WAIT_FOR_PID:
+ /*(state should not happen in workers if server.max-worker > 0)*/
+ /*(if PROC_STATE_DIED_WAIT_FOR_PID is used in future, might want
+ * to save proc->disabled_until before gw_proc_waitpid() since
+ * gw_proc_waitpid will set proc->disabled_until to srv->cur_ts,
+ * and so process will not be restarted below until one sec later)*/
+ if (0 == gw_proc_waitpid(srv, host, proc)) {
+ gw_proc_check_enable(srv, host, proc);
+ }
+
+ if (proc->state != PROC_STATE_DIED) break;
+ /* fall through *//*(we have a dead proc now)*/
+
+ case PROC_STATE_DIED:
+ /* local procs get restarted by us,
+ * remote ones hopefully by the admin */
+
+ if (!buffer_string_is_empty(host->bin_path)) {
+ /* we still have connections bound to this proc,
+ * let them terminate first */
+ if (proc->load != 0) break;
+
+ /* avoid spinning if child exits too quickly */
+ if (proc->disabled_until >= srv->cur_ts) break;
+
+ /* restart the child */
+
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
+ "--- gw spawning",
+ "\n\tsocket", proc->connection_name,
+ "\n\tcurrent:", 1, "/", host->max_procs);
+ }
+
+ if (gw_spawn_connection(srv, host, proc, debug)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: spawning gw failed.");
+ }
+ } else {
+ gw_proc_check_enable(srv, host, proc);
+ }
+ break;
+ }
+ }
+}
+
+
+
+
+#include "base.h"
+#include "connections.h"
+#include "joblist.h"
+#include "response.h"
+
+
+/* ok, we need a prototype */
+static handler_t gw_handle_fdevent(server *srv, void *ctx, int revents);
+
+
+static gw_handler_ctx * handler_ctx_init(size_t sz) {
+ gw_handler_ctx *hctx = calloc(1, 0 == sz ? sizeof(*hctx) : sz);
+ force_assert(hctx);
+
+ hctx->fde_ndx = -1;
+
+ /*hctx->response = chunk_buffer_acquire();*//*(allocated when needed)*/
+
+ hctx->request_id = 0;
+ hctx->gw_mode = GW_RESPONDER;
+ hctx->state = GW_STATE_INIT;
+ hctx->proc = NULL;
+
+ hctx->fd = -1;
+
+ hctx->reconnects = 0;
+ hctx->send_content_body = 1;
+
+ /*hctx->rb = chunkqueue_init();*//*(allocated when needed)*/
+ hctx->wb = chunkqueue_init();
+ hctx->wb_reqlen = 0;
+
+ return hctx;
+}
+
+static void handler_ctx_free(gw_handler_ctx *hctx) {
+ /* caller MUST have called gw_backend_close(srv, hctx) if necessary */
+ if (hctx->handler_ctx_free) hctx->handler_ctx_free(hctx);
+ chunk_buffer_release(hctx->response);
+
+ chunkqueue_free(hctx->rb);
+ chunkqueue_free(hctx->wb);
+
+ free(hctx);
+}
+
+static void handler_ctx_clear(gw_handler_ctx *hctx) {
+ /* caller MUST have called gw_backend_close(srv, hctx) if necessary */
+
+ hctx->proc = NULL;
+ hctx->host = NULL;
+ hctx->ext = NULL;
+ /*hctx->ext_auth is intentionally preserved to flag prior authorizer*/
+
+ hctx->gw_mode = GW_RESPONDER;
+ hctx->state = GW_STATE_INIT;
+ /*hctx->state_timestamp = 0;*//*(unused; left as-is)*/
+
+ if (hctx->rb) chunkqueue_reset(hctx->rb);
+ if (hctx->wb) chunkqueue_reset(hctx->wb);
+ hctx->wb_reqlen = 0;
+
+ if (hctx->response) buffer_clear(hctx->response);
+
+ hctx->fd = -1;
+ hctx->fde_ndx = -1;
+ hctx->reconnects = 0;
+ hctx->request_id = 0;
+ hctx->send_content_body = 1;
+
+ /*plugin_config conf;*//*(no need to reset for same request)*/
+
+ /*hctx->remote_conn = NULL;*//*(no need to reset for same request)*/
+ /*hctx->plugin_data = NULL;*//*(no need to reset for same request)*/
+}
+
+
+void * gw_init(void) {
+ return calloc(1, sizeof(gw_plugin_data));
+}
+
+
+void gw_plugin_config_free(gw_plugin_config *s) {
+ gw_exts *exts = s->exts;
+ if (exts) {
+ for (size_t j = 0; j < exts->used; ++j) {
+ gw_extension *ex = exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ gw_proc *proc;
+ gw_host *host = ex->hosts[n];
+
+ for (proc = host->first; proc; proc = proc->next) {
+ if (proc->pid > 0) {
+ kill(proc->pid, host->kill_signal);
+ }
+
+ if (proc->is_local &&
+ !buffer_string_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
+ }
+ }
+
+ for (proc = host->unused_procs; proc; proc = proc->next) {
+ if (proc->pid > 0) {
+ kill(proc->pid, host->kill_signal);
+ }
+ if (proc->is_local &&
+ !buffer_string_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
+ }
+ }
+ }
+ }
+
+ gw_extensions_free(s->exts);
+ gw_extensions_free(s->exts_auth);
+ gw_extensions_free(s->exts_resp);
+ }
+ array_free(s->ext_mapping);
+ free(s);
+}
+
+handler_t gw_free(server *srv, void *p_d) {
+ gw_plugin_data *p = p_d;
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ gw_plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ gw_plugin_config_free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+ return HANDLER_GO_ON;
+}
+
+int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size_t i, int sh_exec) {
+ /* per-module plugin_config MUST have common "base class" gw_plugin_config*/
+ /* per-module plugin_data MUST have pointer-compatible common "base class"
+ * with gw_plugin_data (stemming from gw_plugin_config compatibility) */
+
+ data_array *da = (data_array *)du;
+ gw_plugin_config *s = p->config_storage[i];
+ buffer *gw_mode;
+ gw_host *host = NULL;
+
+ if (NULL == da) return 1;
+
+ if (da->type != TYPE_ARRAY || !array_is_kvarray(da->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for xxxxx.server; expected "
+ "( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
+ return 0;
+ }
+
+ p->srv_pid = srv->pid;
+
+ gw_mode = buffer_init();
+
+ s->exts = gw_extensions_init();
+ s->exts_auth = gw_extensions_init();
+ s->exts_resp = gw_extensions_init();
+ /*s->balance = GW_BALANCE_LEAST_CONNECTION;*//*(default)*/
+
+ /*
+ * gw.server = ( "<ext>" => ( ... ),
+ * "<ext>" => ( ... ) )
+ */
+
+ for (size_t j = 0; j < da->value->used; ++j) {
+ data_array *da_ext = (data_array *)da->value->data[j];
+
+ /*
+ * da_ext->key == name of the extension
+ */
+
+ /*
+ * gw.server = ( "<ext>" =>
+ * ( "<host>" => ( ... ),
+ * "<host>" => ( ... )
+ * ),
+ * "<ext>" => ... )
+ */
+
+ for (size_t n = 0; n < da_ext->value->used; ++n) {
+ data_array *da_host = (data_array *)da_ext->value->data[n];
+
+ config_values_t fcv[] = {
+ { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+
+ { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "min-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
+ { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
+
+ { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+
+ { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
+ { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
+ { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
+ { "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
+ { "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
+ { "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
+ { "x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
+ { "x-sendfile-docroot",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
+ { "tcp-fin-propagate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
+
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+ unsigned short host_mode = GW_RESPONDER;
+
+ if (da_host->type != TYPE_ARRAY || !array_is_kvany(da_host->value)){
+ log_error_write(srv, __FILE__, __LINE__, "SBS",
+ "unexpected value for gw.server near [",
+ da_host->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
+
+ goto error;
+ }
+
+ host = gw_host_init();
+ buffer_clear(gw_mode);
+
+ buffer_copy_buffer(host->id, da_host->key);
+
+ host->check_local = 1;
+ host->min_procs = 4;
+ host->max_procs = 4;
+ host->max_load_per_proc = 1;
+ host->idle_timeout = 60;
+ host->disable_time = 1;
+ host->break_scriptfilename_for_php = 0;
+ host->kill_signal = SIGTERM;
+ host->fix_root_path_name = 0;
+ host->listen_backlog = 1024;
+ host->xsendfile_allow = 0;
+ host->refcount = 0;
+
+ fcv[0].destination = host->host;
+ fcv[1].destination = host->docroot;
+ fcv[2].destination = gw_mode;
+ fcv[3].destination = host->unixsocket;
+ fcv[4].destination = host->bin_path;
+
+ fcv[5].destination = &(host->check_local);
+ fcv[6].destination = &(host->port);
+ fcv[7].destination = &(host->min_procs);
+ fcv[8].destination = &(host->max_procs);
+ fcv[9].destination = &(host->max_load_per_proc);
+ fcv[10].destination = &(host->idle_timeout);
+ fcv[11].destination = &(host->disable_time);
+
+ fcv[12].destination = host->bin_env;
+ fcv[13].destination = host->bin_env_copy;
+ fcv[14].destination = &(host->break_scriptfilename_for_php);
+ fcv[15].destination = &(host->xsendfile_allow);
+ fcv[16].destination = host->strip_request_uri;
+ fcv[17].destination = &(host->kill_signal);
+ fcv[18].destination = &(host->fix_root_path_name);
+ fcv[19].destination = &(host->listen_backlog);
+ fcv[20].destination = &(host->xsendfile_allow);
+ fcv[21].destination = host->xsendfile_docroot;
+ fcv[22].destination = &(host->tcp_fin_propagate);
+
+ if (0 != config_insert_values_internal(srv, da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) {
+ goto error;
+ }
+
+ for (size_t m = 0; m < da_host->value->used; ++m) {
+ if (NULL != strchr(da_host->value->data[m]->key->ptr, '_')) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "incorrect directive contains underscore ('_') instead of dash ('-'):",
+ da_host->value->data[m]->key);
+ }
+ }
+
+ if ((!buffer_string_is_empty(host->host) || host->port)
+ && !buffer_string_is_empty(host->unixsocket)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "either host/port or socket have to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
+ goto error;
+ }
+
+ if (!buffer_string_is_empty(host->host) && *host->host->ptr == '/'
+ && buffer_string_is_empty(host->unixsocket)) {
+ buffer_copy_buffer(host->unixsocket, host->host);
+ }
+
+ if (!buffer_string_is_empty(host->unixsocket)) {
+ /* unix domain socket */
+ struct sockaddr_un un;
+
+ if (buffer_string_length(host->unixsocket) + 1 > sizeof(un.sun_path) - 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "unixsocket is too long in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
+ goto error;
+ }
+
+ if (!buffer_string_is_empty(host->bin_path)) {
+ gw_host *duplicate = unixsocket_is_dup(p, i+1, host->unixsocket);
+ if (NULL != duplicate) {
+ if (!buffer_is_equal(host->bin_path, duplicate->bin_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "duplicate unixsocket path:",
+ host->unixsocket);
+ goto error;
+ }
+ gw_host_free(host);
+ host = duplicate;
+ ++host->refcount;
+ }
+ }
+
+ host->family = AF_UNIX;
+ } else {
+ /* tcp/ip */
+
+ if (buffer_string_is_empty(host->host) &&
+ buffer_string_is_empty(host->bin_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "host or binpath have to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
+ goto error;
+ } else if (0 == host->port) {
+ host->port = 80;
+ }
+
+ if (buffer_string_is_empty(host->host)) {
+ buffer_copy_string_len(host->host,
+ CONST_STR_LEN("127.0.0.1"));
+ }
+
+ host->family = (NULL != strchr(host->host->ptr, ':'))
+ ? AF_INET6
+ : AF_INET;
+ }
+
+ if (host->refcount) {
+ /* already init'd; skip spawning */
+ } else if (!buffer_string_is_empty(host->bin_path)) {
+ /* a local socket + self spawning */
+ struct stat st;
+ parse_binpath(&host->args, host->bin_path);
+ if (0 != stat(host->args.ptr[0], &st) || !S_ISREG(st.st_mode)
+ || !(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
+ log_error_write(srv, __FILE__, __LINE__, "SSs",
+ "invalid \"bin-path\" => \"", host->bin_path->ptr,
+ "\" (check that file exists, is regular file, "
+ "and is executable by lighttpd)");
+ }
+
+ if (sh_exec) {
+ /*(preserve prior behavior for SCGI exec of command)*/
+ /*(admin should really prefer to put
+ * any complex command into a script)*/
+ for (size_t m = 0; m < host->args.used; ++m)
+ free(host->args.ptr[m]);
+ free(host->args.ptr);
+
+ host->args.ptr = calloc(4, sizeof(char *));
+ force_assert(host->args.ptr);
+ host->args.used = 3;
+ host->args.size = 4;
+ host->args.ptr[0] = malloc(sizeof("/bin/sh"));
+ force_assert(host->args.ptr[0]);
+ memcpy(host->args.ptr[0], "/bin/sh", sizeof("/bin/sh"));
+ host->args.ptr[1] = malloc(sizeof("-c"));
+ force_assert(host->args.ptr[1]);
+ memcpy(host->args.ptr[1], "-c", sizeof("-c"));
+ host->args.ptr[2] =
+ malloc(sizeof("exec ")-1
+ + buffer_string_length(host->bin_path) + 1);
+ force_assert(host->args.ptr[2]);
+ memcpy(host->args.ptr[2], "exec ", sizeof("exec ")-1);
+ memcpy(host->args.ptr[2]+sizeof("exec ")-1,
+ host->bin_path->ptr,
+ buffer_string_length(host->bin_path)+1);
+ host->args.ptr[3] = NULL;
+ }
+
+ if (host->min_procs > host->max_procs)
+ host->min_procs = host->max_procs;
+ if (host->min_procs!= host->max_procs
+ && 0 != srv->srvconf.max_worker) {
+ host->min_procs = host->max_procs;
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "adaptive backend spawning disabled "
+ "(server.max_worker is non-zero)");
+ }
+ if (host->max_load_per_proc < 1)
+ host->max_load_per_proc = 0;
+
+ if (s->debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
+ "--- gw spawning local",
+ "\n\tproc:", host->bin_path,
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tmin-procs:", host->min_procs,
+ "\n\tmax-procs:", host->max_procs);
+ }
+
+ for (size_t pno = 0; pno < host->min_procs; ++pno) {
+ gw_proc *proc = gw_proc_init();
+ proc->id = host->num_procs++;
+ host->max_id++;
+
+ if (buffer_string_is_empty(host->unixsocket)) {
+ proc->port = host->port + pno;
+ } else {
+ buffer_copy_buffer(proc->unixsocket, host->unixsocket);
+ buffer_append_string_len(proc->unixsocket,
+ CONST_STR_LEN("-"));
+ buffer_append_int(proc->unixsocket, pno);
+ }
+
+ if (s->debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
+ "--- gw spawning",
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tcurrent:", pno, "/", host->max_procs);
+ }
+
+ if (0 != gw_proc_sockaddr_init(srv, host, proc)) {
+ gw_proc_free(proc);
+ goto error;
+ }
+
+ if (!srv->srvconf.preflight_check
+ && gw_spawn_connection(srv, host, proc, s->debug)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "[ERROR]: spawning gw failed.");
+ gw_proc_free(proc);
+ goto error;
+ }
+
+ gw_status_init(srv, host, proc);
+
+ proc->next = host->first;
+ if (host->first) host->first->prev = proc;
+
+ host->first = proc;
+ }
+ } else {
+ gw_proc *proc;
+
+ proc = gw_proc_init();
+ proc->id = host->num_procs++;
+ host->max_id++;
+ gw_proc_set_state(host, proc, PROC_STATE_RUNNING);
+
+ if (buffer_string_is_empty(host->unixsocket)) {
+ proc->port = host->port;
+ } else {
+ buffer_copy_buffer(proc->unixsocket, host->unixsocket);
+ }
+
+ gw_status_init(srv, host, proc);
+
+ host->first = proc;
+
+ host->min_procs = 1;
+ host->max_procs = 1;
+
+ if (0 != gw_proc_sockaddr_init(srv, host, proc)) goto error;
+ }
+
+ if (!buffer_string_is_empty(gw_mode)) {
+ if (strcmp(gw_mode->ptr, "responder") == 0) {
+ host_mode = GW_RESPONDER;
+ } else if (strcmp(gw_mode->ptr, "authorizer") == 0) {
+ host_mode = GW_AUTHORIZER;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "WARNING: unknown gw mode:",
+ gw_mode,"(ignored, mode set to responder)");
+ }
+ }
+
+ if (host->xsendfile_docroot->used) {
+ size_t k;
+ for (k = 0; k < host->xsendfile_docroot->used; ++k) {
+ data_string *ds = (data_string *)host->xsendfile_docroot->data[k];
+ if (ds->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected type for x-sendfile-docroot; expected: \"x-sendfile-docroot\" => ( \"/allowed/path\", ... )");
+ goto error;
+ }
+ if (ds->value->ptr[0] != '/') {
+ log_error_write(srv, __FILE__, __LINE__, "SBs",
+ "x-sendfile-docroot paths must begin with '/'; invalid: \"", ds->value, "\"");
+ goto error;
+ }
+ buffer_path_simplify(ds->value, ds->value);
+ buffer_append_slash(ds->value);
+ }
+ }
+
+ /* s->exts is list of exts -> hosts
+ * s->exts now used as combined list
+ * of authorizer and responder hosts (for backend maintenance)
+ * s->exts_auth is list of exts -> authorizer hosts
+ * s->exts_resp is list of exts -> responder hosts
+ * For each path/extension:
+ * there may be an independent GW_AUTHORIZER and GW_RESPONDER
+ * (The GW_AUTHORIZER and GW_RESPONDER could be handled by the same
+ * host, and an admin might want to do that for large uploads,
+ * since GW_AUTHORIZER runs prior to receiving (potentially large)
+ * request body from client and can authorizer or deny request
+ * prior to receiving the full upload)
+ */
+ gw_extension_insert(s->exts, da_ext->key, host);
+
+ if (host_mode == GW_AUTHORIZER) {
+ ++host->refcount;
+ gw_extension_insert(s->exts_auth, da_ext->key, host);
+ } else if (host_mode == GW_RESPONDER) {
+ ++host->refcount;
+ gw_extension_insert(s->exts_resp, da_ext->key, host);
+ } /*(else should have been rejected above)*/
+
+ host = NULL;
+ }
+ }
+
+ buffer_free(gw_mode);
+ return 1;
+
+error:
+ if (NULL != host) gw_host_free(host);
+ buffer_free(gw_mode);
+ return 0;
+}
+
+int gw_set_defaults_balance(server *srv, gw_plugin_config *s, data_unset *du) {
+ buffer *b;
+ if (NULL == du) {
+ b = NULL;
+ } else if (du->type == TYPE_STRING) {
+ b = ((data_string *)du)->value;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected type for xxxxx.balance; expected string");
+ return 0;
+ }
+ if (buffer_string_is_empty(b)) {
+ s->balance = GW_BALANCE_LEAST_CONNECTION;
+ } else if (buffer_is_equal_string(b, CONST_STR_LEN("fair"))) {
+ s->balance = GW_BALANCE_LEAST_CONNECTION;
+ } else if (buffer_is_equal_string(b, CONST_STR_LEN("least-connection"))) {
+ s->balance = GW_BALANCE_LEAST_CONNECTION;
+ } else if (buffer_is_equal_string(b, CONST_STR_LEN("round-robin"))) {
+ s->balance = GW_BALANCE_RR;
+ } else if (buffer_is_equal_string(b, CONST_STR_LEN("hash"))) {
+ s->balance = GW_BALANCE_HASH;
+ } else if (buffer_is_equal_string(b, CONST_STR_LEN("sticky"))) {
+ s->balance = GW_BALANCE_STICKY;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "xxxxx.balance has to be one of: "
+ "least-connection, round-robin, hash, sticky, but not:",
+ b);
+ return 0;
+ }
+ return 1;
+}
+
+static void gw_set_state(server *srv, gw_handler_ctx *hctx, gw_connection_state_t state) {
+ hctx->state = state;
+ hctx->state_timestamp = srv->cur_ts;
+}
+
+
+void gw_set_transparent(server *srv, gw_handler_ctx *hctx) {
+ if (AF_UNIX != hctx->host->family) {
+ if (-1 == fdevent_set_tcp_nodelay(hctx->fd, 1)) {
+ /*(error, but not critical)*/
+ }
+ }
+ hctx->wb_reqlen = -1;
+ gw_set_state(srv, hctx, GW_STATE_WRITE);
+}
+
+
+static void gw_backend_close(server *srv, gw_handler_ctx *hctx) {
+ if (hctx->fd >= 0) {
+ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+ /*fdevent_unregister(srv->ev, hctx->fd);*//*(handled below)*/
+ fdevent_sched_close(srv->ev, hctx->fd, 1);
+ hctx->fd = -1;
+ hctx->fde_ndx = -1;
+ }
+
+ if (hctx->host) {
+ if (hctx->proc) {
+ gw_proc_release(srv, hctx->host, hctx->proc, hctx->conf.debug);
+ hctx->proc = NULL;
+ }
+
+ gw_host_reset(srv, hctx->host);
+ hctx->host = NULL;
+ }
+}
+
+static void gw_connection_close(server *srv, gw_handler_ctx *hctx) {
+ gw_plugin_data *p = hctx->plugin_data;
+ connection *con = hctx->remote_conn;
+
+ gw_backend_close(srv, hctx);
+ handler_ctx_free(hctx);
+ con->plugin_ctx[p->id] = NULL;
+
+ if (con->mode == p->id) {
+ http_response_backend_done(srv, con);
+ }
+}
+
+static handler_t gw_reconnect(server *srv, gw_handler_ctx *hctx) {
+ gw_backend_close(srv, hctx);
+
+ hctx->host = gw_host_get(srv, hctx->remote_conn, hctx->ext,
+ hctx->conf.balance, hctx->conf.debug);
+ if (NULL == hctx->host) return HANDLER_FINISHED;
+
+ gw_host_assign(srv, hctx->host);
+ hctx->request_id = 0;
+ hctx->opts.xsendfile_allow = hctx->host->xsendfile_allow;
+ hctx->opts.xsendfile_docroot = hctx->host->xsendfile_docroot;
+ gw_set_state(srv, hctx, GW_STATE_INIT);
+ return HANDLER_COMEBACK;
+}
+
+
+handler_t gw_connection_reset(server *srv, connection *con, void *p_d) {
+ gw_plugin_data *p = p_d;
+ gw_handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (hctx) gw_connection_close(srv, hctx);
+
+ return HANDLER_GO_ON;
+}
+
+
+static void gw_conditional_tcp_fin(server *srv, gw_handler_ctx *hctx) {
+ connection *con = hctx->remote_conn;
+ /*assert(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN);*/
+ if (!chunkqueue_is_empty(hctx->wb)) return;
+ if (!hctx->host->tcp_fin_propagate) return;
+ if (hctx->gw_mode == GW_AUTHORIZER) return;
+ if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR)
+ return;
+
+ /* propagate shutdown SHUT_WR to backend if TCP half-close on con->fd */
+ con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR;
+ con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
+ con->is_readable = 0;
+ shutdown(hctx->fd, SHUT_WR);
+ fdevent_event_clr(srv->ev, &hctx->fde_ndx, hctx->fd, FDEVENT_OUT);
+}
+
+static handler_t gw_write_request(server *srv, gw_handler_ctx *hctx) {
+ switch(hctx->state) {
+ case GW_STATE_INIT:
+ /* do we have a running process for this host (max-procs) ? */
+ hctx->proc = NULL;
+
+ for (gw_proc *proc = hctx->host->first; proc; proc = proc->next) {
+ if (proc->state == PROC_STATE_RUNNING) {
+ hctx->proc = proc;
+ break;
+ }
+ }
+
+ /* all children are dead */
+ if (hctx->proc == NULL) {
+ return HANDLER_ERROR;
+ }
+
+ /* check the other procs if they have a lower load */
+ for (gw_proc *proc = hctx->proc->next; proc; proc = proc->next) {
+ if (proc->state != PROC_STATE_RUNNING) continue;
+ if (proc->load < hctx->proc->load) hctx->proc = proc;
+ }
+
+ gw_proc_load_inc(srv, hctx->host, hctx->proc);
+
+ hctx->fd = fdevent_socket_nb_cloexec(hctx->host->family,SOCK_STREAM,0);
+ if (-1 == hctx->fd) {
+ if (errno == EMFILE || errno == EINTR) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "wait for fd at connection:",
+ hctx->remote_conn->fd);
+ return HANDLER_WAIT_FOR_FD;
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "ssdd",
+ "socket failed:", strerror(errno),
+ srv->cur_fds, srv->max_fds);
+ return HANDLER_ERROR;
+ }
+
+ srv->cur_fds++;
+
+ fdevent_register(srv->ev, hctx->fd, gw_handle_fdevent, hctx);
+
+ if (hctx->proc->is_local) {
+ hctx->pid = hctx->proc->pid;
+ }
+
+ switch (gw_establish_connection(srv, hctx->host, hctx->proc, hctx->pid,
+ hctx->fd, hctx->conf.debug)) {
+ case 1: /* connection is in progress */
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+ gw_set_state(srv, hctx, GW_STATE_CONNECT_DELAYED);
+ return HANDLER_WAIT_FOR_EVENT;
+ case -1:/* connection error */
+ return HANDLER_ERROR;
+ case 0: /* everything is ok, go on */
+ hctx->reconnects = 0;
+ break;
+ }
+ /* fall through */
+ case GW_STATE_CONNECT_DELAYED:
+ if (hctx->state == GW_STATE_CONNECT_DELAYED) { /*(not GW_STATE_INIT)*/
+ int socket_error = fdevent_connect_status(hctx->fd);
+ if (socket_error != 0) {
+ gw_proc_connect_error(srv, hctx->host, hctx->proc, hctx->pid,
+ socket_error, hctx->conf.debug);
+ return HANDLER_ERROR;
+ }
+ /* go on with preparing the request */
+ }
+
+ gw_proc_connect_success(srv, hctx->host, hctx->proc, hctx->conf.debug);
+
+ gw_set_state(srv, hctx, GW_STATE_PREPARE_WRITE);
+ /* fall through */
+ case GW_STATE_PREPARE_WRITE:
+ /* ok, we have the connection */
+
+ {
+ handler_t rc = hctx->create_env(srv, hctx);
+ if (HANDLER_GO_ON != rc) {
+ if (HANDLER_FINISHED != rc && HANDLER_ERROR != rc)
+ fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd,
+ FDEVENT_OUT);
+ return rc;
+ }
+ }
+
+ /*(disable Nagle algorithm if streaming and content-length unknown)*/
+ if (AF_UNIX != hctx->host->family) {
+ connection *con = hctx->remote_conn;
+ if (con->request.content_length < 0) {
+ if (-1 == fdevent_set_tcp_nodelay(hctx->fd, 1)) {
+ /*(error, but not critical)*/
+ }
+ }
+ }
+
+ fdevent_event_add(srv->ev, &hctx->fde_ndx, hctx->fd,
+ FDEVENT_IN | FDEVENT_RDHUP);
+ gw_set_state(srv, hctx, GW_STATE_WRITE);
+ /* fall through */
+ case GW_STATE_WRITE:
+ if (!chunkqueue_is_empty(hctx->wb)) {
+ int ret;
+ #if 0
+ if (hctx->conf.debug > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sdsx",
+ "send data to backend ( fd =", hctx->fd,
+ "), size =", chunkqueue_length(hctx->wb));
+ }
+ #endif
+ ret = srv->network_backend_write(srv, hctx->fd, hctx->wb,
+ MAX_WRITE_LIMIT);
+
+ chunkqueue_remove_finished_chunks(hctx->wb);
+
+ if (ret < 0) {
+ switch(errno) {
+ case EPIPE:
+ case ENOTCONN:
+ case ECONNRESET:
+ /* the connection got dropped after accept()
+ * we don't care about that --
+ * if you accept() it, you have to handle it.
+ */
+ log_error_write(srv, __FILE__, __LINE__, "ssosb",
+ "connection was dropped after accept() "
+ "(perhaps the gw process died),",
+ "write-offset:", hctx->wb->bytes_out,
+ "socket:", hctx->proc->connection_name);
+ return HANDLER_ERROR;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), errno);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ if (hctx->wb->bytes_out == hctx->wb_reqlen) {
+ fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+ gw_set_state(srv, hctx, GW_STATE_READ);
+ } else {
+ off_t wblen = hctx->wb->bytes_in - hctx->wb->bytes_out;
+ if ((hctx->wb->bytes_in < hctx->wb_reqlen || hctx->wb_reqlen < 0)
+ && wblen < 65536 - 16384) {
+ connection *con = hctx->remote_conn;
+ /*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/
+ if (!(con->conf.stream_request_body
+ & FDEVENT_STREAM_REQUEST_POLLIN)) {
+ con->conf.stream_request_body |=
+ FDEVENT_STREAM_REQUEST_POLLIN;
+ con->is_readable = 1;/*trigger optimistic read from client*/
+ }
+ }
+ if (0 == wblen) {
+ fdevent_event_clr(srv->ev,&hctx->fde_ndx,hctx->fd,FDEVENT_OUT);
+ } else {
+ fdevent_event_add(srv->ev,&hctx->fde_ndx,hctx->fd,FDEVENT_OUT);
+ }
+ }
+
+ if (hctx->remote_conn->conf.stream_request_body
+ & FDEVENT_STREAM_REQUEST_TCP_FIN)
+ gw_conditional_tcp_fin(srv, hctx);
+
+ return HANDLER_WAIT_FOR_EVENT;
+ case GW_STATE_READ:
+ /* waiting for a response */
+ return HANDLER_WAIT_FOR_EVENT;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
+ return HANDLER_ERROR;
+ }
+}
+
+static handler_t gw_write_error(server *srv, gw_handler_ctx *hctx) {
+ connection *con = hctx->remote_conn;
+ int status = con->http_status;
+
+ if (hctx->state == GW_STATE_INIT ||
+ hctx->state == GW_STATE_CONNECT_DELAYED) {
+
+ /* (optimization to detect backend process exit while processing a
+ * large number of ready events; (this block could be removed)) */
+ if (0 == srv->srvconf.max_worker)
+ gw_restart_dead_procs(srv, hctx->host, hctx->conf.debug, 0);
+
+ /* cleanup this request and let request handler start request again */
+ if (hctx->reconnects++ < 5) return gw_reconnect(srv, hctx);
+ }
+
+ if (hctx->backend_error) hctx->backend_error(hctx);
+ gw_connection_close(srv, hctx);
+ con->http_status = (status == 400) ? 400 : 503;
+ return HANDLER_FINISHED;
+}
+
+static handler_t gw_send_request(server *srv, gw_handler_ctx *hctx) {
+ handler_t rc = gw_write_request(srv, hctx);
+ return (HANDLER_ERROR != rc) ? rc : gw_write_error(srv, hctx);
+}
+
+
+static handler_t gw_recv_response(server *srv, gw_handler_ctx *hctx);
+
+
+handler_t gw_handle_subrequest(server *srv, connection *con, void *p_d) {
+ gw_plugin_data *p = p_d;
+ gw_handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (con->mode != p->id) return HANDLER_GO_ON; /* not my job */
+
+ if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
+ && con->file_started) {
+ if (chunkqueue_length(con->write_queue) > 65536 - 4096) {
+ fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ }
+ else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)){
+ /* optimistic read from backend */
+ handler_t rc;
+ rc = gw_recv_response(srv, hctx); /*(might invalidate hctx)*/
+ if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/
+ fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ }
+ }
+
+ /* (do not receive request body before GW_AUTHORIZER has run or else
+ * the request body is discarded with handler_ctx_clear() after running
+ * the FastCGI Authorizer) */
+
+ if (hctx->gw_mode != GW_AUTHORIZER
+ && (0 == hctx->wb->bytes_in
+ ? (con->state == CON_STATE_READ_POST || -1 == hctx->wb_reqlen)
+ : (hctx->wb->bytes_in < hctx->wb_reqlen || hctx->wb_reqlen < 0))) {
+ /* leave excess data in con->request_content_queue, which is
+ * buffered to disk if too large and backend can not keep up */
+ /*(64k - 4k to attempt to avoid temporary files
+ * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/
+ if (hctx->wb->bytes_in - hctx->wb->bytes_out > 65536 - 4096) {
+ if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN) {
+ con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
+ }
+ if (0 != hctx->wb->bytes_in) return HANDLER_WAIT_FOR_EVENT;
+ }
+ else {
+ handler_t r = connection_handle_read_post_state(srv, con);
+ chunkqueue *req_cq = con->request_content_queue;
+ #if 0 /*(not reached since we send 411 Length Required below)*/
+ if (hctx->wb_reqlen < -1 && con->request.content_length >= 0) {
+ /* (completed receiving Transfer-Encoding: chunked) */
+ hctx->wb_reqlen= -hctx->wb_reqlen + con->request.content_length;
+ if (hctx->stdin_append) {
+ handler_t rc = hctx->stdin_append(srv, hctx);
+ if (HANDLER_GO_ON != rc) return rc;
+ }
+ }
+ #endif
+ if ((0 != hctx->wb->bytes_in || -1 == hctx->wb_reqlen)
+ && !chunkqueue_is_empty(req_cq)) {
+ if (hctx->stdin_append) {
+ handler_t rc = hctx->stdin_append(srv, hctx);
+ if (HANDLER_GO_ON != rc) return rc;
+ }
+ else
+ chunkqueue_append_chunkqueue(hctx->wb, req_cq);
+ if (fdevent_event_get_interest(srv->ev,hctx->fd) & FDEVENT_OUT){
+ return (r == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : r;
+ }
+ }
+ if (r != HANDLER_GO_ON) return r;
+
+
+ /* XXX: create configurable flag */
+ /* CGI environment requires that Content-Length be set.
+ * Send 411 Length Required if Content-Length missing.
+ * (occurs here if client sends Transfer-Encoding: chunked
+ * and module is flagged to stream request body to backend) */
+ /* proxy currently sends HTTP/1.0 request and ideally should send
+ * Content-Length with request if request body is present, so
+ * send 411 Length Required if Content-Length missing. */
+ if (-1 == con->request.content_length) {
+ return connection_handle_read_post_error(srv, con, 411);
+ }
+ }
+ }
+
+ {
+ handler_t rc =((0==hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
+ && hctx->state != GW_STATE_CONNECT_DELAYED)
+ ? gw_send_request(srv, hctx)
+ : HANDLER_WAIT_FOR_EVENT;
+ if (HANDLER_WAIT_FOR_EVENT != rc) return rc;
+ }
+
+ if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN)
+ gw_conditional_tcp_fin(srv, hctx);
+
+ return HANDLER_WAIT_FOR_EVENT;
+}
+
+
+static handler_t gw_recv_response(server *srv, gw_handler_ctx *hctx) {
+ connection *con = hctx->remote_conn;
+ gw_proc *proc = hctx->proc;
+ gw_host *host = hctx->host;
+ /*(XXX: make this a configurable flag for other protocols)*/
+ buffer *b = hctx->opts.backend == BACKEND_FASTCGI
+ ? chunk_buffer_acquire()
+ : hctx->response;
+
+ handler_t rc = http_response_read(srv, hctx->remote_conn, &hctx->opts,
+ b, hctx->fd, &hctx->fde_ndx);
+
+ if (b != hctx->response) chunk_buffer_release(b);
+
+ switch (rc) {
+ default:
+ return HANDLER_GO_ON;
+ case HANDLER_FINISHED:
+ if (hctx->gw_mode == GW_AUTHORIZER
+ && (200 == con->http_status || 0 == con->http_status)) {
+ /*
+ * If we are here in AUTHORIZER mode then a request for authorizer
+ * was processed already, and status 200 has been returned. We need
+ * now to handle authorized request.
+ */
+ buffer *physpath = NULL;
+
+ if (!buffer_string_is_empty(host->docroot)) {
+ buffer_copy_buffer(con->physical.doc_root, host->docroot);
+ buffer_copy_buffer(con->physical.basedir, host->docroot);
+
+ buffer_copy_buffer(con->physical.path, host->docroot);
+ buffer_append_string_buffer(con->physical.path, con->uri.path);
+ physpath = con->physical.path;
+ }
+
+ proc->last_used = srv->cur_ts;
+ gw_backend_close(srv, hctx);
+ handler_ctx_clear(hctx);
+
+ /* don't do more than 6 loops here; normally shouldn't happen */
+ if (++con->loops_per_request > 5) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "too many loops while processing request:",
+ con->request.orig_uri);
+ con->http_status = 500; /* Internal Server Error */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ /* restart the request so other handlers can process it */
+
+ if (physpath) con->physical.path = NULL;
+ connection_response_reset(srv,con);/*(includes con->http_status=0)*/
+ /* preserve con->physical.path with modified docroot */
+ if (physpath) con->physical.path = physpath;
+
+ /*(FYI: if multiple FastCGI authorizers were to be supported,
+ * next one could be started here instead of restarting request)*/
+
+ con->mode = DIRECT;
+ return HANDLER_COMEBACK;
+ } else {
+ /* we are done */
+ gw_connection_close(srv, hctx);
+ }
+
+ return HANDLER_FINISHED;
+ case HANDLER_COMEBACK: /*(not expected; treat as error)*/
+ case HANDLER_ERROR:
+ /* (optimization to detect backend process exit while processing a
+ * large number of ready events; (this block could be removed)) */
+ if (proc->is_local && 1 == proc->load && proc->pid == hctx->pid
+ && proc->state != PROC_STATE_DIED && 0 == srv->srvconf.max_worker) {
+ /* intentionally check proc->disabed_until before gw_proc_waitpid */
+ if (proc->disabled_until < srv->cur_ts
+ && 0 != gw_proc_waitpid(srv, host, proc)) {
+ if (hctx->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
+ "--- gw spawning",
+ "\n\tsocket", proc->connection_name,
+ "\n\tcurrent:", 1, "/", host->num_procs);
+ }
+
+ if (gw_spawn_connection(srv, host, proc, hctx->conf.debug)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "respawning failed, will retry later");
+ }
+ }
+ }
+
+ if (con->file_started == 0) {
+ /* nothing has been sent out yet, try to use another child */
+
+ if (hctx->wb->bytes_out == 0 &&
+ hctx->reconnects++ < 5) {
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
+ "response not received, request not sent",
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, "?", con->uri.query, ", reconnecting");
+
+ return gw_reconnect(srv, hctx);
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs",
+ "response not received, request sent:", hctx->wb->bytes_out,
+ "on socket:", proc->connection_name, "for",
+ con->uri.path, "?", con->uri.query, ", closing connection");
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
+ "response already sent out, but backend returned error",
+ "on socket:", proc->connection_name, "for",
+ con->uri.path, "?", con->uri.query, ", terminating connection");
+ }
+
+ if (hctx->backend_error) hctx->backend_error(hctx);
+ http_response_backend_error(srv, con);
+ gw_connection_close(srv, hctx);
+ return HANDLER_FINISHED;
+ }
+}
+
+
+static handler_t gw_handle_fdevent(server *srv, void *ctx, int revents) {
+ gw_handler_ctx *hctx = ctx;
+ connection *con = hctx->remote_conn;
+
+ joblist_append(srv, con);
+
+ if (revents & FDEVENT_IN) {
+ handler_t rc = gw_recv_response(srv, hctx); /*(might invalidate hctx)*/
+ if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/
+ }
+
+ if (revents & FDEVENT_OUT) {
+ return gw_send_request(srv, hctx); /*(might invalidate hctx)*/
+ }
+
+ /* perhaps this issue is already handled */
+ if (revents & (FDEVENT_HUP|FDEVENT_RDHUP)) {
+ if (hctx->state == GW_STATE_CONNECT_DELAYED) {
+ /* getoptsock will catch this one (right ?)
+ *
+ * if we are in connect we might get an EINPROGRESS
+ * in the first call and an FDEVENT_HUP in the
+ * second round
+ *
+ * FIXME: as it is a bit ugly.
+ *
+ */
+ gw_send_request(srv, hctx);
+ } else if (con->file_started) {
+ /* drain any remaining data from kernel pipe buffers
+ * even if (con->conf.stream_response_body
+ * & FDEVENT_STREAM_RESPONSE_BUFMIN)
+ * since event loop will spin on fd FDEVENT_HUP event
+ * until unregistered. */
+ handler_t rc;
+ const unsigned short flags = con->conf.stream_response_body;
+ con->conf.stream_response_body &= ~FDEVENT_STREAM_RESPONSE_BUFMIN;
+ con->conf.stream_response_body |= FDEVENT_STREAM_RESPONSE_POLLRDHUP;
+ do {
+ rc = gw_recv_response(srv,hctx); /*(might invalidate hctx)*/
+ } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/
+ con->conf.stream_response_body = flags;
+ return rc; /* HANDLER_FINISHED or HANDLER_ERROR */
+ } else {
+ gw_proc *proc = hctx->proc;
+ log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd",
+ "error: unexpected close of gw connection for",
+ con->uri.path, "?", con->uri.query,
+ "(no gw process on socket:", proc->connection_name, "?)",
+ hctx->state);
+
+ gw_connection_close(srv, hctx);
+ }
+ } else if (revents & FDEVENT_ERR) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "gw: got a FDEVENT_ERR. Don't know why.");
+
+ if (hctx->backend_error) hctx->backend_error(hctx);
+ http_response_backend_error(srv, con);
+ gw_connection_close(srv, hctx);
+ }
+
+ return HANDLER_FINISHED;
+}
+
+handler_t gw_check_extension(server *srv, connection *con, gw_plugin_data *p, int uri_path_handler, size_t hctx_sz) {
+ #if 0 /*(caller must handle)*/
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+ gw_patch_connection(srv, con, p);
+ if (NULL == p->conf.exts) return HANDLER_GO_ON;
+ #endif
+
+ buffer *fn = uri_path_handler ? con->uri.path : con->physical.path;
+ size_t s_len = buffer_string_length(fn);
+ gw_extension *extension = NULL;
+ gw_host *host = NULL;
+ gw_handler_ctx *hctx;
+ unsigned short gw_mode;
+
+ if (0 == s_len) return HANDLER_GO_ON; /*(not expected)*/
+
+ /* check p->conf.exts_auth list and then p->conf.ext_resp list
+ * (skip p->conf.exts_auth if array is empty
+ * or if GW_AUTHORIZER already ran in this request) */
+ hctx = con->plugin_ctx[p->id];
+ /*(hctx not NULL if GW_AUTHORIZER ran; hctx->ext_auth check is redundant)*/
+ gw_mode = (NULL == hctx || NULL == hctx->ext_auth)
+ ? 0 /*GW_AUTHORIZER p->conf.exts_auth will be searched next*/
+ : GW_AUTHORIZER; /*GW_RESPONDER p->conf.exts_resp will be searched next*/
+
+ do {
+
+ gw_exts *exts;
+ if (0 == gw_mode) {
+ gw_mode = GW_AUTHORIZER;
+ exts = p->conf.exts_auth;
+ } else {
+ gw_mode = GW_RESPONDER;
+ exts = p->conf.exts_resp;
+ }
+
+ if (0 == exts->used) continue;
+
+ /* gw.map-extensions maps extensions to existing gw.server entries
+ *
+ * gw.map-extensions = ( ".php3" => ".php" )
+ *
+ * gw.server = ( ".php" => ... )
+ *
+ * */
+
+ /* check if extension-mapping matches */
+ if (p->conf.ext_mapping) {
+ data_string *ds =
+ (data_string *)array_match_key_suffix(p->conf.ext_mapping, fn);
+ if (NULL != ds) {
+ /* found a mapping */
+ /* check if we know the extension */
+ size_t k;
+ for (k = 0; k < exts->used; ++k) {
+ extension = exts->exts[k];
+
+ if (buffer_is_equal(ds->value, extension->key)) {
+ break;
+ }
+ }
+
+ if (k == exts->used) {
+ /* found nothing */
+ extension = NULL;
+ }
+ }
+ }
+
+ if (extension == NULL) {
+ size_t uri_path_len = buffer_string_length(con->uri.path);
+
+ /* check if extension matches */
+ for (size_t k = 0; k < exts->used; ++k) {
+ gw_extension *ext = exts->exts[k];
+ size_t ct_len = buffer_string_length(ext->key);
+
+ /* check _url_ in the form "/gw_pattern" */
+ if (ext->key->ptr[0] == '/') {
+ if (ct_len <= uri_path_len
+ && 0==memcmp(con->uri.path->ptr,ext->key->ptr,ct_len)){
+ extension = ext;
+ break;
+ }
+ } else if (ct_len <= s_len
+ && 0 == memcmp(fn->ptr + s_len - ct_len,
+ ext->key->ptr, ct_len)) {
+ /* check extension in the form ".fcg" */
+ extension = ext;
+ break;
+ }
+ }
+ }
+
+ } while (NULL == extension && gw_mode != GW_RESPONDER);
+
+ /* extension doesn't match */
+ if (NULL == extension) {
+ return HANDLER_GO_ON;
+ }
+
+ /* check if we have at least one server for this extension up and running */
+ host = gw_host_get(srv, con, extension, p->conf.balance, p->conf.debug);
+ if (NULL == host) {
+ return HANDLER_FINISHED;
+ }
+
+ /* a note about no handler is not sent yet */
+ extension->note_is_sent = 0;
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ if (uri_path_handler) {
+ if (host->check_local != 0) {
+ return HANDLER_GO_ON;
+ } else {
+ /* do not split path info for authorizer */
+ if (gw_mode != GW_AUTHORIZER) {
+ /* the prefix is the SCRIPT_NAME,
+ * everything from start to the next slash
+ * this is important for check-local = "disable"
+ *
+ * if prefix = /admin.gw
+ *
+ * /admin.gw/foo/bar
+ *
+ * SCRIPT_NAME = /admin.gw
+ * PATH_INFO = /foo/bar
+ *
+ * if prefix = /cgi-bin/
+ *
+ * /cgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /cgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ * if prefix = /, and fix-root-path-name is enable
+ *
+ * /cgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /cgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ */
+ char *pathinfo;
+
+ /* the rewrite is only done for /prefix/? matches */
+ if (host->fix_root_path_name && extension->key->ptr[0] == '/'
+ && extension->key->ptr[1] == '\0'){
+ buffer_copy_buffer(con->request.pathinfo, con->uri.path);
+ buffer_clear(con->uri.path);
+ } else if (extension->key->ptr[0] == '/'
+ && buffer_string_length(con->uri.path)
+ > buffer_string_length(extension->key)
+ && (pathinfo =
+ strchr(con->uri.path->ptr
+ + buffer_string_length(extension->key),
+ '/')) != NULL) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+ buffer_string_set_length(
+ con->uri.path,
+ buffer_string_length(con->uri.path)
+ - buffer_string_length(con->request.pathinfo));
+ }
+ }
+ }
+ }
+
+ if (!hctx) hctx = handler_ctx_init(hctx_sz);
+
+ hctx->remote_conn = con;
+ hctx->plugin_data = p;
+ hctx->host = host;
+ hctx->proc = NULL;
+ hctx->ext = extension;
+ gw_host_assign(srv, host);
+
+ hctx->gw_mode = gw_mode;
+ if (gw_mode == GW_AUTHORIZER) {
+ hctx->ext_auth = hctx->ext;
+ }
+
+ /*hctx->conf.exts = p->conf.exts;*/
+ /*hctx->conf.exts_auth = p->conf.exts_auth;*/
+ /*hctx->conf.exts_resp = p->conf.exts_resp;*/
+ /*hctx->conf.ext_mapping = p->conf.ext_mapping;*/
+ hctx->conf.balance = p->conf.balance;
+ hctx->conf.proto = p->conf.proto;
+ hctx->conf.debug = p->conf.debug;
+
+ hctx->opts.fdfmt = S_IFSOCK;
+ hctx->opts.authorizer = (gw_mode == GW_AUTHORIZER);
+ hctx->opts.local_redir = 0;
+ hctx->opts.xsendfile_allow = host->xsendfile_allow;
+ hctx->opts.xsendfile_docroot = host->xsendfile_docroot;
+
+ con->plugin_ctx[p->id] = hctx;
+
+ con->mode = p->id;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_gw");
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static void gw_handle_trigger_host(server *srv, gw_host *host, int debug) {
+ /*
+ * TODO:
+ *
+ * - add timeout for a connect to a non-gw process
+ * (use state_timestamp + state)
+ *
+ * perhaps we should kill a connect attempt after 10-15 seconds
+ *
+ * currently we wait for the TCP timeout which is 180 seconds on Linux
+ */
+
+ /* check each child proc to detect if proc exited */
+
+ gw_proc *proc;
+ time_t idle_timestamp;
+ int overload = 1;
+
+ for (proc = host->first; proc; proc = proc->next) {
+ gw_proc_waitpid(srv, host, proc);
+ }
+
+ gw_restart_dead_procs(srv, host, debug, 1);
+
+ /* check if adaptive spawning enabled */
+ if (host->min_procs == host->max_procs) return;
+ if (buffer_string_is_empty(host->bin_path)) return;
+
+ for (proc = host->first; proc; proc = proc->next) {
+ if (proc->load <= host->max_load_per_proc) {
+ overload = 0;
+ break;
+ }
+ }
+
+ if (overload && host->num_procs && host->num_procs < host->max_procs) {
+ /* overload, spawn new child */
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "overload detected, spawning a new child");
+ }
+
+ gw_proc_spawn(srv, host, debug);
+ }
+
+ idle_timestamp = srv->cur_ts - host->idle_timeout;
+ for (proc = host->first; proc; proc = proc->next) {
+ if (host->num_procs <= host->min_procs) break;
+ if (0 != proc->load) continue;
+ if (proc->pid <= 0) continue;
+ if (proc->last_used >= idle_timestamp) continue;
+
+ /* terminate proc that has been idling for a long time */
+ if (debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbsd",
+ "idle-timeout reached, terminating child:",
+ "socket:", proc->unixsocket, "pid", proc->pid);
+ }
+
+ gw_proc_kill(srv, host, proc);
+
+ /* proc is now in unused, let next second handle next process */
+ break;
+ }
+
+ for (proc = host->unused_procs; proc; proc = proc->next) {
+ gw_proc_waitpid(srv, host, proc);
+ }
+}
+
+static void gw_handle_trigger_exts(server *srv, gw_exts *exts, int debug) {
+ for (size_t j = 0; j < exts->used; ++j) {
+ gw_extension *ex = exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ gw_handle_trigger_host(srv, ex->hosts[n], debug);
+ }
+ }
+}
+
+static void gw_handle_trigger_exts_wkr(server *srv, gw_exts *exts) {
+ for (size_t j = 0; j < exts->used; ++j) {
+ gw_extension * const ex = exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ gw_host * const host = ex->hosts[n];
+ for (gw_proc *proc = host->first; proc; proc = proc->next) {
+ if (proc->state == PROC_STATE_OVERLOADED)
+ gw_proc_check_enable(srv, host, proc);
+ }
+ }
+ }
+}
+
+handler_t gw_handle_trigger(server *srv, void *p_d) {
+ gw_plugin_data *p = p_d;
+ int wkr = (0 != srv->srvconf.max_worker && p->srv_pid != srv->pid);
+
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ gw_plugin_config *conf = p->config_storage[i];
+ gw_exts *exts = conf->exts;
+ int debug = conf->debug ? conf->debug : p->config_storage[0]->debug;
+ if (NULL == exts) continue;
+ wkr
+ ? gw_handle_trigger_exts_wkr(srv, exts)
+ : gw_handle_trigger_exts(srv, exts, debug);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+handler_t gw_handle_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) {
+ gw_plugin_data *p = p_d;
+ if (0 != srv->srvconf.max_worker && p->srv_pid != srv->pid)
+ return HANDLER_GO_ON;
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ gw_plugin_config *conf = p->config_storage[i];
+ gw_exts *exts = conf->exts;
+ int debug = conf->debug ? conf->debug : p->config_storage[0]->debug;
+ if (NULL == exts) continue;
+ for (size_t j = 0; j < exts->used; ++j) {
+ gw_extension *ex = exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ gw_host *host = ex->hosts[n];
+ gw_proc *proc;
+ for (proc = host->first; proc; proc = proc->next) {
+ if (!proc->is_local || proc->pid != pid) continue;
+
+ gw_proc_waitpid_log(srv, host, proc, status);
+ gw_proc_set_state(host, proc, PROC_STATE_DIED);
+ proc->pid = 0;
+
+ /* restart, but avoid spinning if child exits too quickly */
+ if (proc->disabled_until < srv->cur_ts) {
+ if (proc->state != PROC_STATE_KILLED)
+ proc->disabled_until = srv->cur_ts;
+ if (gw_spawn_connection(srv, host, proc, debug)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: spawning gw failed.");
+ }
+ }
+
+ return HANDLER_FINISHED;
+ }
+ for (proc = host->unused_procs; proc; proc = proc->next) {
+ if (!proc->is_local || proc->pid != pid) continue;
+
+ gw_proc_waitpid_log(srv, host, proc, status);
+ if (proc->state != PROC_STATE_KILLED)
+ proc->disabled_until = srv->cur_ts;
+ gw_proc_set_state(host, proc, PROC_STATE_DIED);
+ proc->pid = 0;
+ return HANDLER_FINISHED;
+ }
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/gw_backend.h b/data/lighttpd/lighttpd-1.4.53/src/gw_backend.h
new file mode 100644
index 000000000..5b00705a5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/gw_backend.h
@@ -0,0 +1,348 @@
+#ifndef INCLUDED_GW_BACKEND_H
+#define INCLUDED_GW_BACKEND_H
+
+#include "first.h"
+
+#include <sys/types.h>
+#include "sys-socket.h"
+
+#include "array.h"
+#include "buffer.h"
+
+typedef struct {
+ char **ptr;
+
+ size_t size;
+ size_t used;
+} char_array;
+
+typedef struct gw_proc {
+ size_t id; /* id will be between 1 and max_procs */
+ buffer *unixsocket; /* config.socket + "-" + id */
+ unsigned port; /* config.port + pno */
+ socklen_t saddrlen;
+ struct sockaddr *saddr;
+
+ /* either tcp:<host>:<port> or unix:<socket> for debugging purposes */
+ buffer *connection_name;
+
+ pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
+
+
+ size_t load; /* number of requests waiting on this process */
+
+ time_t last_used; /* see idle_timeout */
+ size_t requests; /* see max_requests */
+ struct gw_proc *prev, *next; /* see first */
+
+ time_t disabled_until; /* proc disabled until given time */
+
+ int is_local;
+
+ enum {
+ PROC_STATE_RUNNING, /* alive */
+ PROC_STATE_OVERLOADED, /* listen-queue is full */
+ PROC_STATE_DIED_WAIT_FOR_PID, /* */
+ PROC_STATE_DIED, /* marked as dead, should be restarted */
+ PROC_STATE_KILLED /* killed (signal sent to proc) */
+ } state;
+} gw_proc;
+
+typedef struct {
+ /* the key that is used to reference this value */
+ buffer *id;
+
+ /* list of processes handling this extension
+ * sorted by lowest load
+ *
+ * whenever a job is done move it up in the list
+ * until it is sorted, move it down as soon as the
+ * job is started
+ */
+ gw_proc *first;
+ gw_proc *unused_procs;
+
+ /*
+ * spawn at least min_procs, at max_procs.
+ *
+ * as soon as the load of the first entry
+ * is max_load_per_proc we spawn a new one
+ * and add it to the first entry and give it
+ * the load
+ *
+ */
+
+ unsigned short min_procs;
+ unsigned short max_procs;
+ size_t num_procs; /* how many procs are started */
+ size_t active_procs; /* how many procs in state PROC_STATE_RUNNING */
+
+ unsigned short max_load_per_proc;
+
+ /*
+ * kick the process from the list if it was not
+ * used for idle_timeout until min_procs is
+ * reached. this helps to get the processlist
+ * small again we had a small peak load.
+ *
+ */
+
+ unsigned short idle_timeout;
+
+ /*
+ * time after a disabled remote connection is tried to be re-enabled
+ *
+ *
+ */
+
+ unsigned short disable_time;
+
+ /*
+ * some gw processes get a little bit larger
+ * than wanted. max_requests_per_proc kills a
+ * process after a number of handled requests.
+ *
+ */
+ size_t max_requests_per_proc;
+
+
+ /* config */
+
+ /*
+ * host:port
+ *
+ * if host is one of the local IP adresses the
+ * whole connection is local
+ *
+ * if port is not 0, and host is not specified,
+ * "localhost" (INADDR_LOOPBACK) is assumed.
+ *
+ */
+ buffer *host;
+ unsigned short port;
+ unsigned short family; /* sa_family_t */
+
+ /*
+ * Unix Domain Socket
+ *
+ * instead of TCP/IP we can use Unix Domain Sockets
+ * - more secure (you have fileperms to play with)
+ * - more control (on locally)
+ * - more speed (no extra overhead)
+ */
+ buffer *unixsocket;
+
+ /* if socket is local we can start the gw process ourself
+ *
+ * bin-path is the path to the binary
+ *
+ * check min_procs and max_procs for the number
+ * of process to start up
+ */
+ buffer *bin_path;
+
+ /* bin-path is set bin-environment is taken to
+ * create the environement before starting the
+ * FastCGI process
+ *
+ */
+ array *bin_env;
+
+ array *bin_env_copy;
+
+ /*
+ * docroot-translation between URL->phys and the
+ * remote host
+ *
+ * reasons:
+ * - different dir-layout if remote
+ * - chroot if local
+ *
+ */
+ buffer *docroot;
+
+ /*
+ * check_local tells you if the phys file is stat()ed
+ * or not. FastCGI doesn't care if the service is
+ * remote. If the web-server side doesn't contain
+ * the FastCGI-files we should not stat() for them
+ * and say '404 not found'.
+ */
+ unsigned short check_local;
+
+ /*
+ * append PATH_INFO to SCRIPT_FILENAME
+ *
+ * php needs this if cgi.fix_pathinfo is provided
+ *
+ */
+
+ unsigned short break_scriptfilename_for_php;
+
+ /*
+ * workaround for program when prefix="/"
+ *
+ * rule to build PATH_INFO is hardcoded for when check_local is disabled
+ * enable this option to use the workaround
+ *
+ */
+
+ unsigned short fix_root_path_name;
+
+ /*
+ * If the backend includes X-Sendfile in the response
+ * we use the value as filename and ignore the content.
+ *
+ */
+ unsigned short xsendfile_allow;
+ array *xsendfile_docroot;
+
+ ssize_t load;
+
+ size_t max_id; /* corresponds most of the time to num_procs */
+
+ buffer *strip_request_uri;
+
+ unsigned short tcp_fin_propagate;
+ unsigned short kill_signal; /* we need a setting for this as libfcgi
+ applications prefer SIGUSR1 while the
+ rest of the world would use SIGTERM
+ *sigh* */
+
+ int listen_backlog;
+ int refcount;
+
+ char_array args;
+} gw_host;
+
+/*
+ * one extension can have multiple hosts assigned
+ * one host can spawn additional processes on the same
+ * socket (if we control it)
+ *
+ * ext -> host -> procs
+ * 1:n 1:n
+ *
+ * if the gw process is remote that whole goes down
+ * to
+ *
+ * ext -> host -> procs
+ * 1:n 1:1
+ *
+ * in case of PHP and FCGI_CHILDREN we have again a procs
+ * but we don't control it directly.
+ *
+ */
+
+typedef struct {
+ buffer *key; /* like .php */
+
+ int note_is_sent;
+ int last_used_ndx;
+
+ gw_host **hosts;
+
+ size_t used;
+ size_t size;
+} gw_extension;
+
+typedef struct {
+ gw_extension **exts;
+
+ size_t used;
+ size_t size;
+} gw_exts;
+
+
+
+
+#include "base_decls.h"
+#include "chunk.h"
+#include "plugin.h"
+#include "response.h"
+
+typedef struct gw_plugin_config {
+ gw_exts *exts;
+ gw_exts *exts_auth;
+ gw_exts *exts_resp;
+
+ array *ext_mapping;
+
+ int balance;
+ int proto;
+ int debug;
+} gw_plugin_config;
+
+/* generic plugin data, shared between all connections */
+typedef struct gw_plugin_data {
+ PLUGIN_DATA;
+ gw_plugin_config **config_storage;
+
+ gw_plugin_config conf; /* used only as long as no gw_handler_ctx is setup */
+ pid_t srv_pid;
+} gw_plugin_data;
+
+/* connection specific data */
+typedef enum {
+ GW_STATE_INIT,
+ GW_STATE_CONNECT_DELAYED,
+ GW_STATE_PREPARE_WRITE,
+ GW_STATE_WRITE,
+ GW_STATE_READ
+} gw_connection_state_t;
+
+#define GW_RESPONDER 1
+#define GW_AUTHORIZER 2
+#define GW_FILTER 3 /*(not implemented)*/
+
+typedef struct gw_handler_ctx {
+ gw_proc *proc;
+ gw_host *host;
+ gw_extension *ext;
+ gw_extension *ext_auth; /* (future: might allow multiple authorizers)*/
+ unsigned short gw_mode; /* mode: GW_AUTHORIZER or GW_RESPONDER */
+
+ gw_connection_state_t state;
+ time_t state_timestamp;
+
+ chunkqueue *rb; /* read queue */
+ chunkqueue *wb; /* write queue */
+ off_t wb_reqlen;
+
+ buffer *response;
+
+ int fd; /* fd to the gw process */
+ int fde_ndx; /* index into the fd-event buffer */
+
+ pid_t pid;
+ int reconnects; /* number of reconnect attempts */
+
+ int request_id;
+ int send_content_body;
+
+ http_response_opts opts;
+ gw_plugin_config conf;
+
+ connection *remote_conn; /* dumb pointer */
+ gw_plugin_data *plugin_data; /* dumb pointer */
+ handler_t(*stdin_append)(server *srv, struct gw_handler_ctx *hctx);
+ handler_t(*create_env)(server *srv, struct gw_handler_ctx *hctx);
+ void(*backend_error)(struct gw_handler_ctx *hctx);
+ void(*handler_ctx_free)(void *hctx);
+} gw_handler_ctx;
+
+
+void * gw_init(void);
+void gw_plugin_config_free(gw_plugin_config *s);
+handler_t gw_free(server *srv, void *p_d);
+int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size_t i, int sh_exec);
+int gw_set_defaults_balance(server *srv, gw_plugin_config *s, data_unset *du);
+handler_t gw_check_extension(server *srv, connection *con, gw_plugin_data *p, int uri_path_handler, size_t hctx_sz);
+handler_t gw_connection_reset(server *srv, connection *con, void *p_d);
+handler_t gw_handle_subrequest(server *srv, connection *con, void *p_d);
+handler_t gw_handle_trigger(server *srv, void *p_d);
+handler_t gw_handle_waitpid_cb(server *srv, void *p_d, pid_t pid, int status);
+
+void gw_set_transparent(server *srv, gw_handler_ctx *hctx);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http-header-glue.c b/data/lighttpd/lighttpd-1.4.53/src/http-header-glue.c
new file mode 100644
index 000000000..6aae9728c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http-header-glue.c
@@ -0,0 +1,1527 @@
+#include "first.h"
+
+#include "base.h"
+#include "array.h"
+#include "buffer.h"
+#include "fdevent.h"
+#include "log.h"
+#include "etag.h"
+#include "http_chunk.h"
+#include "http_header.h"
+#include "response.h"
+#include "sock_addr.h"
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <time.h>
+
+#include "sys-strings.h"
+#include "sys-socket.h"
+#include <unistd.h>
+
+
+int http_response_buffer_append_authority(server *srv, connection *con, buffer *o) {
+ if (!buffer_string_is_empty(con->uri.authority)) {
+ buffer_append_string_buffer(o, con->uri.authority);
+ } else {
+ /* get the name of the currently connected socket */
+ sock_addr our_addr;
+ socklen_t our_addr_len;
+
+ our_addr.plain.sa_family = 0;
+ our_addr_len = sizeof(our_addr);
+
+ if (-1 == getsockname(con->fd, (struct sockaddr *)&our_addr, &our_addr_len)
+ || our_addr_len > (socklen_t)sizeof(our_addr)) {
+ con->http_status = 500;
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "can't get sockname", strerror(errno));
+ return -1;
+ }
+
+ if (our_addr.plain.sa_family == AF_INET
+ && our_addr.ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
+ static char lhost[32];
+ static size_t lhost_len = 0;
+ if (0 != lhost_len) {
+ buffer_append_string_len(o, lhost, lhost_len);
+ }
+ else {
+ size_t olen = buffer_string_length(o);
+ if (0 == sock_addr_nameinfo_append_buffer(srv, o, &our_addr)) {
+ lhost_len = buffer_string_length(o) - olen;
+ if (lhost_len < sizeof(lhost)) {
+ memcpy(lhost, o->ptr+olen, lhost_len+1); /*(+1 for '\0')*/
+ }
+ else {
+ lhost_len = 0;
+ }
+ }
+ else {
+ lhost_len = sizeof("localhost")-1;
+ memcpy(lhost, "localhost", lhost_len+1); /*(+1 for '\0')*/
+ buffer_append_string_len(o, lhost, lhost_len);
+ }
+ }
+ } else if (!buffer_string_is_empty(con->server_name)) {
+ buffer_append_string_buffer(o, con->server_name);
+ } else
+ /* Lookup name: secondly try to get hostname for bind address */
+ if (0 != sock_addr_nameinfo_append_buffer(srv, o, &our_addr)) {
+ con->http_status = 500;
+ return -1;
+ }
+
+ {
+ unsigned short listen_port = sock_addr_get_port(&our_addr);
+ unsigned short default_port = 80;
+ if (buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https"))) {
+ default_port = 443;
+ }
+ if (0 == listen_port) listen_port = srv->srvconf.port;
+ if (default_port != listen_port) {
+ buffer_append_string_len(o, CONST_STR_LEN(":"));
+ buffer_append_int(o, listen_port);
+ }
+ }
+ }
+ return 0;
+}
+
+int http_response_redirect_to_directory(server *srv, connection *con) {
+ buffer *o = srv->tmp_buf;
+ buffer_copy_buffer(o, con->uri.scheme);
+ buffer_append_string_len(o, CONST_STR_LEN("://"));
+ if (0 != http_response_buffer_append_authority(srv, con, o)) {
+ return -1;
+ }
+ buffer_append_string_encoded(o, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
+ buffer_append_string_len(o, CONST_STR_LEN("/"));
+ if (!buffer_string_is_empty(con->uri.query)) {
+ buffer_append_string_len(o, CONST_STR_LEN("?"));
+ buffer_append_string_buffer(o, con->uri.query);
+ }
+
+ http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
+
+ con->http_status = 301;
+ con->file_finished = 1;
+ return 0;
+}
+
+buffer * strftime_cache_get(server *srv, time_t last_mod) {
+ static int i;
+ struct tm *tm;
+
+ for (int j = 0; j < FILE_CACHE_MAX; ++j) {
+ if (srv->mtime_cache[j].mtime == last_mod)
+ return srv->mtime_cache[j].str; /* found cache-entry */
+ }
+
+ if (++i == FILE_CACHE_MAX) {
+ i = 0;
+ }
+
+ srv->mtime_cache[i].mtime = last_mod;
+ tm = gmtime(&(srv->mtime_cache[i].mtime));
+ buffer_clear(srv->mtime_cache[i].str);
+ buffer_append_strftime(srv->mtime_cache[i].str, "%a, %d %b %Y %H:%M:%S GMT", tm);
+
+ return srv->mtime_cache[i].str;
+}
+
+
+int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
+ buffer *vb;
+ int head_or_get =
+ ( HTTP_METHOD_GET == con->request.http_method
+ || HTTP_METHOD_HEAD == con->request.http_method);
+ UNUSED(srv);
+
+ /*
+ * 14.26 If-None-Match
+ * [...]
+ * If none of the entity tags match, then the server MAY perform the
+ * requested method as if the If-None-Match header field did not exist,
+ * but MUST also ignore any If-Modified-Since header field(s) in the
+ * request. That is, if no entity tags match, then the server MUST NOT
+ * return a 304 (Not Modified) response.
+ */
+
+ if ((vb = http_header_request_get(con, HTTP_HEADER_IF_NONE_MATCH, CONST_STR_LEN("If-None-Match")))) {
+ /* use strong etag checking for now: weak comparison must not be used
+ * for ranged requests
+ */
+ if (etag_is_equal(con->physical.etag, vb->ptr, 0)) {
+ if (head_or_get) {
+ con->http_status = 304;
+ return HANDLER_FINISHED;
+ } else {
+ con->http_status = 412;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ }
+ } else if (head_or_get
+ && (vb = http_header_request_get(con, HTTP_HEADER_IF_MODIFIED_SINCE, CONST_STR_LEN("If-Modified-Since")))) {
+ /* last-modified handling */
+ size_t used_len;
+ char *semicolon;
+
+ if (NULL == (semicolon = strchr(vb->ptr, ';'))) {
+ used_len = buffer_string_length(vb);
+ } else {
+ used_len = semicolon - vb->ptr;
+ }
+
+ if (buffer_is_equal_string(mtime, vb->ptr, used_len)) {
+ if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
+ return HANDLER_FINISHED;
+ } else {
+ char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
+ time_t t_header, t_file;
+ struct tm tm;
+
+ /* convert to timestamp */
+ if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
+
+ memcpy(buf, vb->ptr, used_len);
+ buf[used_len] = '\0';
+
+ if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
+ /**
+ * parsing failed, let's get out of here
+ */
+ return HANDLER_GO_ON;
+ }
+ tm.tm_isdst = 0;
+ t_header = mktime(&tm);
+
+ strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ tm.tm_isdst = 0;
+ t_file = mktime(&tm);
+
+ if (t_file > t_header) return HANDLER_GO_ON;
+
+ con->http_status = 304;
+ return HANDLER_FINISHED;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+void http_response_body_clear (connection *con, int preserve_length) {
+ con->response.send_chunked = 0;
+ if (con->response.htags & HTTP_HEADER_TRANSFER_ENCODING) {
+ http_header_response_unset(con, HTTP_HEADER_TRANSFER_ENCODING, CONST_STR_LEN("Transfer-Encoding"));
+ }
+ if (!preserve_length) { /* preserve for HEAD responses and no-content responses (204, 205, 304) */
+ con->response.content_length = -1;
+ if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ }
+ }
+ chunkqueue_reset(con->write_queue);
+}
+
+
+static int http_response_parse_range(server *srv, connection *con, buffer *path, stat_cache_entry *sce, const char *range) {
+ int multipart = 0;
+ int error;
+ off_t start, end;
+ const char *s, *minus;
+ static const char boundary[] = "fkj49sn38dcn3";
+ buffer *content_type = http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"));
+
+ start = 0;
+ end = sce->st.st_size - 1;
+
+ con->response.content_length = 0;
+
+ for (s = range, error = 0;
+ !error && *s && NULL != (minus = strchr(s, '-')); ) {
+ char *err;
+ off_t la = 0, le;
+ *((const char **)&err) = s; /*(quiet clang --analyze)*/
+
+ if (s != minus) {
+ la = strtoll(s, &err, 10);
+ if (err != minus) {
+ /* should not have multiple range-unit in Range, but
+ * handle just in case multiple Range headers merged */
+ while (*s == ' ' || *s == '\t') ++s;
+ if (0 != strncmp(s, "bytes=", 6)) return -1;
+ s += 6;
+ if (s != minus) {
+ la = strtoll(s, &err, 10);
+ if (err != minus) return -1;
+ }
+ }
+ }
+
+ if (s == minus) {
+ /* -<stop> */
+
+ le = strtoll(s, &err, 10);
+
+ if (le == 0) {
+ /* RFC 2616 - 14.35.1 */
+
+ con->http_status = 416;
+ error = 1;
+ } else if (*err == '\0') {
+ /* end */
+ s = err;
+
+ end = sce->st.st_size - 1;
+ start = sce->st.st_size + le;
+ } else if (*err == ',') {
+ multipart = 1;
+ s = err + 1;
+
+ end = sce->st.st_size - 1;
+ start = sce->st.st_size + le;
+ } else {
+ error = 1;
+ }
+
+ } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
+ /* <start>- */
+
+ /* ok */
+
+ if (*(err + 1) == '\0') {
+ s = err + 1;
+
+ end = sce->st.st_size - 1;
+ start = la;
+
+ } else if (*(err + 1) == ',') {
+ multipart = 1;
+ s = err + 2;
+
+ end = sce->st.st_size - 1;
+ start = la;
+ } else {
+ error = 1;
+ }
+ } else {
+ /* <start>-<stop> */
+
+ le = strtoll(minus+1, &err, 10);
+
+ /* RFC 2616 - 14.35.1 */
+ if (la > le) {
+ error = 1;
+ }
+
+ if (*err == '\0') {
+ /* ok, end*/
+ s = err;
+
+ end = le;
+ start = la;
+ } else if (*err == ',') {
+ multipart = 1;
+ s = err + 1;
+
+ end = le;
+ start = la;
+ } else {
+ /* error */
+
+ error = 1;
+ }
+ }
+
+ if (!error) {
+ if (start < 0) start = 0;
+
+ /* RFC 2616 - 14.35.1 */
+ if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
+
+ if (start > sce->st.st_size - 1) {
+ error = 1;
+
+ con->http_status = 416;
+ }
+ }
+
+ if (!error) {
+ if (multipart) {
+ /* write boundary-header */
+ buffer *b = srv->tmp_buf;
+ buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));
+ buffer_append_string_len(b, boundary, sizeof(boundary)-1);
+
+ /* write Content-Range */
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));
+ buffer_append_int(b, start);
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ buffer_append_int(b, end);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_int(b, sce->st.st_size);
+
+ if (content_type) {
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: "));
+ buffer_append_string_buffer(b, content_type);
+ }
+
+ /* write END-OF-HEADER */
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+ con->response.content_length += buffer_string_length(b);
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+ }
+
+ chunkqueue_append_file(con->write_queue, path, start, end - start + 1);
+ con->response.content_length += end - start + 1;
+ }
+ }
+
+ /* something went wrong */
+ if (error) return -1;
+
+ if (multipart) {
+ /* add boundary end */
+ buffer *b = srv->tmp_buf;
+ buffer_copy_string_len(b, "\r\n--", 4);
+ buffer_append_string_len(b, boundary, sizeof(boundary)-1);
+ buffer_append_string_len(b, "--\r\n", 4);
+
+ con->response.content_length += buffer_string_length(b);
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+
+ /* set header-fields */
+
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("multipart/byteranges; boundary="));
+ buffer_append_string_len(srv->tmp_buf, boundary, sizeof(boundary)-1);
+
+ /* overwrite content-type */
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(srv->tmp_buf));
+ } else {
+ /* add Content-Range-header */
+
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("bytes "));
+ buffer_append_int(srv->tmp_buf, start);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("-"));
+ buffer_append_int(srv->tmp_buf, end);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
+ buffer_append_int(srv->tmp_buf, sce->st.st_size);
+
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(srv->tmp_buf));
+ }
+
+ /* ok, the file is set-up */
+ return 0;
+}
+
+
+void http_response_send_file (server *srv, connection *con, buffer *path) {
+ stat_cache_entry *sce = NULL;
+ buffer *mtime = NULL;
+ buffer *vb;
+ int allow_caching = (0 == con->http_status || 200 == con->http_status);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, path, &sce)) {
+ con->http_status = (errno == ENOENT) ? 404 : 403;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "not a regular file:", con->uri.path,
+ "->", path);
+
+ return;
+ }
+
+ /* we only handline regular files */
+#ifdef HAVE_LSTAT
+ if ((sce->is_symlink == 1) && !con->conf.follow_symlink) {
+ con->http_status = 403;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", path);
+ }
+
+ return;
+ }
+#endif
+ if (!S_ISREG(sce->st.st_mode)) {
+ con->http_status = 403;
+
+ if (con->conf.log_file_not_found) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "not a regular file:", con->uri.path,
+ "->", sce->name);
+ }
+
+ return;
+ }
+
+ /* mod_compress might set several data directly, don't overwrite them */
+
+ /* set response content-type, if not set already */
+
+ if (NULL == http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"))) {
+ stat_cache_content_type_get(srv, con, path, sce);
+ if (buffer_string_is_empty(sce->content_type)) {
+ /* we are setting application/octet-stream, but also announce that
+ * this header field might change in the seconds few requests
+ *
+ * This should fix the aggressive caching of FF and the script download
+ * seen by the first installations
+ */
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream"));
+
+ allow_caching = 0;
+ } else {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ }
+ }
+
+ if (con->conf.range_requests) {
+ http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
+ }
+
+ if (allow_caching) {
+ if (con->etag_flags != 0 && !buffer_string_is_empty(stat_cache_etag_get(sce, con->etag_flags))) {
+ if (NULL == http_header_response_get(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"))) {
+ /* generate e-tag */
+ etag_mutate(con->physical.etag, sce->etag);
+
+ http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ }
+ }
+
+ /* prepare header */
+ if (NULL == (mtime = http_header_response_get(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified")))) {
+ mtime = strftime_cache_get(srv, sce->st.st_mtime);
+ http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ }
+
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
+ return;
+ }
+ }
+
+ if (con->conf.range_requests
+ && (200 == con->http_status || 0 == con->http_status)
+ && NULL != (vb = http_header_request_get(con, HTTP_HEADER_RANGE, CONST_STR_LEN("Range")))
+ && NULL == http_header_response_get(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"))) {
+ buffer *range = vb;
+ int do_range_request = 1;
+ /* check if we have a conditional GET */
+
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("If-Range")))) {
+ /* if the value is the same as our ETag, we do a Range-request,
+ * otherwise a full 200 */
+
+ if (vb->ptr[0] == '"') {
+ /**
+ * client wants a ETag
+ */
+ if (!con->physical.etag) {
+ do_range_request = 0;
+ } else if (!buffer_is_equal(vb, con->physical.etag)) {
+ do_range_request = 0;
+ }
+ } else if (!mtime) {
+ /**
+ * we don't have a Last-Modified and can match the If-Range:
+ *
+ * sending all
+ */
+ do_range_request = 0;
+ } else if (!buffer_is_equal(vb, mtime)) {
+ do_range_request = 0;
+ }
+ }
+
+ if (do_range_request
+ && !buffer_string_is_empty(range)
+ && 0 == strncmp(range->ptr, "bytes=", 6)) {
+ /* support only "bytes" byte-unit */
+ /* content prepared, I'm done */
+ con->file_finished = 1;
+
+ if (0 == http_response_parse_range(srv, con, path, sce, range->ptr+6)) {
+ con->http_status = 206;
+ }
+ return;
+ }
+ }
+
+ /* if we are still here, prepare body */
+
+ /* we add it here for all requests
+ * the HEAD request will drop it afterwards again
+ */
+ if (0 == sce->st.st_size || 0 == http_chunk_append_file(srv, con, path)) {
+ con->http_status = 200;
+ con->file_finished = 1;
+ } else {
+ con->http_status = 403;
+ }
+}
+
+
+static void http_response_xsendfile (server *srv, connection *con, buffer *path, const array *xdocroot) {
+ const int status = con->http_status;
+ int valid = 1;
+
+ /* reset Content-Length, if set by backend
+ * Content-Length might later be set to size of X-Sendfile static file,
+ * determined by open(), fstat() to reduces race conditions if the file
+ * is modified between stat() (stat_cache_get_entry()) and open(). */
+ if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ con->response.content_length = -1;
+ }
+
+ buffer_urldecode_path(path);
+ if (!buffer_is_valid_UTF8(path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "X-Sendfile invalid UTF-8 after url-decode:", path);
+ if (con->http_status < 400) {
+ con->http_status = 502;
+ con->mode = DIRECT;
+ }
+ return;
+ }
+ buffer_path_simplify(path, path);
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(path);
+ }
+
+ /* check that path is under xdocroot(s)
+ * - xdocroot should have trailing slash appended at config time
+ * - con->conf.force_lowercase_filenames is not a server-wide setting,
+ * and so can not be definitively applied to xdocroot at config time*/
+ if (xdocroot->used) {
+ size_t i, xlen = buffer_string_length(path);
+ for (i = 0; i < xdocroot->used; ++i) {
+ data_string *ds = (data_string *)xdocroot->data[i];
+ size_t dlen = buffer_string_length(ds->value);
+ if (dlen <= xlen
+ && (!con->conf.force_lowercase_filenames
+ ? 0 == memcmp(path->ptr, ds->value->ptr, dlen)
+ : 0 == strncasecmp(path->ptr, ds->value->ptr, dlen))) {
+ break;
+ }
+ }
+ if (i == xdocroot->used) {
+ log_error_write(srv, __FILE__, __LINE__, "SBs",
+ "X-Sendfile (", path,
+ ") not under configured x-sendfile-docroot(s)");
+ con->http_status = 403;
+ valid = 0;
+ }
+ }
+
+ if (valid) http_response_send_file(srv, con, path);
+
+ if (con->http_status >= 400 && status < 300) {
+ con->mode = DIRECT;
+ } else if (0 != status && 200 != status) {
+ con->http_status = status;
+ }
+}
+
+
+static void http_response_xsendfile2(server *srv, connection *con, const buffer *value, const array *xdocroot) {
+ const char *pos = value->ptr;
+ buffer *b = srv->tmp_buf;
+ const int status = con->http_status;
+
+ /* reset Content-Length, if set by backend */
+ if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ con->response.content_length = -1;
+ }
+
+ while (*pos) {
+ const char *filename, *range;
+ stat_cache_entry *sce;
+ off_t begin_range, end_range, range_len;
+
+ while (' ' == *pos) pos++;
+ if (!*pos) break;
+
+ filename = pos;
+ if (NULL == (range = strchr(pos, ' '))) {
+ /* missing range */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "Couldn't find range after filename:", filename);
+ con->http_status = 502;
+ break;
+ }
+ buffer_copy_string_len(b, filename, range - filename);
+
+ /* find end of range */
+ for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ;
+
+ buffer_urldecode_path(b);
+ if (!buffer_is_valid_UTF8(b)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "X-Sendfile2 invalid UTF-8 after url-decode:", b);
+ con->http_status = 502;
+ break;
+ }
+ buffer_path_simplify(b, b);
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(b);
+ }
+ if (xdocroot->used) {
+ size_t i, xlen = buffer_string_length(b);
+ for (i = 0; i < xdocroot->used; ++i) {
+ data_string *ds = (data_string *)xdocroot->data[i];
+ size_t dlen = buffer_string_length(ds->value);
+ if (dlen <= xlen
+ && (!con->conf.force_lowercase_filenames
+ ? 0 == memcmp(b->ptr, ds->value->ptr, dlen)
+ : 0 == strncasecmp(b->ptr, ds->value->ptr, dlen))) {
+ break;
+ }
+ }
+ if (i == xdocroot->used) {
+ log_error_write(srv, __FILE__, __LINE__, "SBs",
+ "X-Sendfile2 (", b,
+ ") not under configured x-sendfile-docroot(s)");
+ con->http_status = 403;
+ break;
+ }
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "send-file error: "
+ "couldn't get stat_cache entry for X-Sendfile2:",
+ b);
+ con->http_status = 404;
+ break;
+ } else if (!S_ISREG(sce->st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "send-file error: wrong filetype for X-Sendfile2:",
+ b);
+ con->http_status = 502;
+ break;
+ }
+ /* found the file */
+
+ /* parse range */
+ end_range = sce->st.st_size - 1;
+ {
+ char *rpos = NULL;
+ errno = 0;
+ begin_range = strtoll(range, &rpos, 10);
+ if (errno != 0 || begin_range < 0 || rpos == range)
+ goto range_failed;
+ if ('-' != *rpos++) goto range_failed;
+ if (rpos != pos) {
+ range = rpos;
+ end_range = strtoll(range, &rpos, 10);
+ if (errno != 0 || end_range < 0 || rpos == range)
+ goto range_failed;
+ }
+ if (rpos != pos) goto range_failed;
+
+ goto range_success;
+
+range_failed:
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "Couldn't decode range after filename:", filename);
+ con->http_status = 502;
+ break;
+
+range_success: ;
+ }
+
+ /* no parameters accepted */
+
+ while (*pos == ' ') pos++;
+ if (*pos != '\0' && *pos != ',') {
+ con->http_status = 502;
+ break;
+ }
+
+ range_len = end_range - begin_range + 1;
+ if (range_len < 0) {
+ con->http_status = 502;
+ break;
+ }
+ if (range_len != 0) {
+ if (0 != http_chunk_append_file_range(srv, con, b,
+ begin_range, range_len)) {
+ con->http_status = 502;
+ break;
+ }
+ }
+
+ if (*pos == ',') pos++;
+ }
+
+ if (con->http_status >= 400 && status < 300) {
+ con->mode = DIRECT;
+ } else if (0 != status && 200 != status) {
+ con->http_status = status;
+ }
+}
+
+
+void http_response_backend_error (server *srv, connection *con) {
+ UNUSED(srv);
+ if (con->file_started) {
+ /*(response might have been already started, kill the connection)*/
+ /*(mode == DIRECT to avoid later call to http_response_backend_done())*/
+ con->mode = DIRECT; /*(avoid sending final chunked block)*/
+ con->keep_alive = 0; /*(no keep-alive; final chunked block not sent)*/
+ con->file_finished = 1;
+ } /*(else error status set later by http_response_backend_done())*/
+}
+
+void http_response_backend_done (server *srv, connection *con) {
+ /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END,
+ * i.e. not called from handle_connection_close or connection_reset
+ * hooks, except maybe from errdoc handler, which later resets state)*/
+ switch (con->state) {
+ case CON_STATE_HANDLE_REQUEST:
+ case CON_STATE_READ_POST:
+ if (!con->file_started) {
+ /* Send an error if we haven't sent any data yet */
+ con->http_status = 500;
+ con->mode = DIRECT;
+ break;
+ } /* else fall through */
+ case CON_STATE_WRITE:
+ if (!con->file_finished) {
+ http_chunk_close(srv, con);
+ con->file_finished = 1;
+ }
+ default:
+ break;
+ }
+}
+
+
+void http_response_upgrade_read_body_unknown(server *srv, connection *con) {
+ /* act as transparent proxy */
+ UNUSED(srv);
+ if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST))
+ con->conf.stream_request_body |=
+ (FDEVENT_STREAM_REQUEST_BUFMIN | FDEVENT_STREAM_REQUEST);
+ if (!(con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE))
+ con->conf.stream_response_body |=
+ (FDEVENT_STREAM_RESPONSE_BUFMIN | FDEVENT_STREAM_RESPONSE);
+ con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
+ con->request.content_length = -2;
+ con->keep_alive = 0;
+}
+
+
+static handler_t http_response_process_local_redir(server *srv, connection *con, size_t blen) {
+ /* [RFC3875] The Common Gateway Interface (CGI) Version 1.1
+ * [RFC3875] 6.2.2 Local Redirect Response
+ *
+ * The CGI script can return a URI path and query-string
+ * ('local-pathquery') for a local resource in a Location header field.
+ * This indicates to the server that it should reprocess the request
+ * using the path specified.
+ *
+ * local-redir-response = local-Location NL
+ *
+ * The script MUST NOT return any other header fields or a message-body,
+ * and the server MUST generate the response that it would have produced
+ * in response to a request containing the URL
+ *
+ * scheme "://" server-name ":" server-port local-pathquery
+ *
+ * (Might not have begun to receive body yet, but do skip local-redir
+ * if we already have started receiving a response body (blen > 0))
+ * (Also, while not required by the RFC, do not send local-redir back
+ * to same URL, since CGI should have handled it internally if it
+ * really wanted to do that internally)
+ */
+
+ /* con->http_status >= 300 && con->http_status < 400) */
+ size_t ulen = buffer_string_length(con->uri.path);
+ buffer *vb = http_header_response_get(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"));
+ if (NULL != vb
+ && vb->ptr[0] == '/'
+ && (0 != strncmp(vb->ptr, con->uri.path->ptr, ulen)
+ || ( vb->ptr[ulen] != '\0'
+ && vb->ptr[ulen] != '/'
+ && vb->ptr[ulen] != '?'))
+ && 0 == blen
+ && !(con->response.htags & HTTP_HEADER_STATUS) /*no "Status" or NPH response*/
+ && 1 == con->response.headers->used) {
+ if (++con->loops_per_request > 5) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "too many internal loops while processing request:",
+ con->request.orig_uri);
+ con->http_status = 500; /* Internal Server Error */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ buffer_copy_buffer(con->request.uri, vb);
+
+ if (con->request.content_length) {
+ if (con->request.content_length
+ != con->request_content_queue->bytes_in) {
+ con->keep_alive = 0;
+ }
+ con->request.content_length = 0;
+ chunkqueue_reset(con->request_content_queue);
+ }
+
+ if (con->http_status != 307 && con->http_status != 308) {
+ /* Note: request body (if any) sent to initial dynamic handler
+ * and is not available to the internal redirect */
+ con->request.http_method = HTTP_METHOD_GET;
+ }
+
+ /*(caller must reset request as follows)*/
+ /*connection_response_reset(srv, con);*/ /*(sets con->http_status = 0)*/
+ /*plugins_call_connection_reset(srv, con);*/
+
+ return HANDLER_COMEBACK;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static int http_response_process_headers(server *srv, connection *con, http_response_opts *opts, buffer *hdrs) {
+ char *ns;
+ const char *s;
+ int line = 0;
+ int status_is_set = 0;
+
+ for (s = hdrs->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1, ++line) {
+ const char *key, *value;
+ int key_len;
+ enum http_header_e id;
+
+ /* strip the \n */
+ ns[0] = '\0';
+ if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
+
+ if (0 == line && 0 == strncmp(s, "HTTP/1.", 7)) {
+ /* non-parsed headers ... we parse them anyway */
+ if ((s[7] == '1' || s[7] == '0') && s[8] == ' ') {
+ /* after the space should be a status code for us */
+ int status = strtol(s+9, NULL, 10);
+ if (status >= 100 && status < 1000) {
+ status_is_set = 1;
+ con->response.htags |= HTTP_HEADER_STATUS;
+ con->http_status = status;
+ } /* else we expected 3 digits and didn't get them */
+ }
+
+ if (0 == con->http_status) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "invalid HTTP status line:", s);
+ con->http_status = 502; /* Bad Gateway */
+ con->mode = DIRECT;
+ return -1;
+ }
+
+ continue;
+ }
+
+ /* parse the headers */
+ key = s;
+ if (NULL == (value = strchr(s, ':'))) {
+ /* we expect: "<key>: <value>\r\n" */
+ continue;
+ }
+
+ key_len = value - key;
+ do { ++value; } while (*value == ' ' || *value == '\t'); /* skip LWS */
+ id = http_header_hkey_get(key, key_len);
+
+ if (opts->authorizer) {
+ if (0 == con->http_status || 200 == con->http_status) {
+ if (id == HTTP_HEADER_STATUS) {
+ int status = strtol(value, NULL, 10);
+ if (status >= 100 && status < 1000) {
+ con->http_status = status;
+ } else {
+ con->http_status = 502; /* Bad Gateway */
+ break;
+ }
+ } else if (id == HTTP_HEADER_OTHER && key_len > 9
+ && 0==strncasecmp(key, CONST_STR_LEN("Variable-"))) {
+ http_header_env_append(con, key + 9, key_len - 9, value, strlen(value));
+ }
+ continue;
+ }
+ }
+
+ switch (id) {
+ case HTTP_HEADER_STATUS:
+ {
+ int status;
+ if (opts->backend == BACKEND_PROXY) break; /*(pass w/o parse)*/
+ status = strtol(value, NULL, 10);
+ if (status >= 100 && status < 1000) {
+ con->http_status = status;
+ status_is_set = 1;
+ } else {
+ con->http_status = 502;
+ con->mode = DIRECT;
+ }
+ continue; /* do not send Status to client */
+ }
+ break;
+ case HTTP_HEADER_UPGRADE:
+ /*(technically, should also verify Connection: upgrade)*/
+ /*(flag only for mod_proxy and mod_cgi (for now))*/
+ if (opts->backend != BACKEND_PROXY
+ && opts->backend != BACKEND_CGI) {
+ id = HTTP_HEADER_OTHER;
+ }
+ break;
+ case HTTP_HEADER_CONNECTION:
+ if (opts->backend == BACKEND_PROXY) continue;
+ con->response.keep_alive =
+ (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
+ break;
+ case HTTP_HEADER_CONTENT_LENGTH:
+ con->response.content_length = strtoul(value, NULL, 10);
+ break;
+ case HTTP_HEADER_TRANSFER_ENCODING:
+ if (opts->backend == BACKEND_PROXY) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "proxy backend sent invalid response header "
+ "(Transfer-Encoding) to HTTP/1.0 request");
+ con->http_status = 502; /* Bad Gateway */
+ con->mode = DIRECT;
+ return -1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ http_header_response_insert(con, id, key, key_len, value, strlen(value));
+ }
+
+ /* CGI/1.1 rev 03 - 7.2.1.2 */
+ /* (proxy requires Status-Line, so never true for proxy)*/
+ if (!status_is_set && (con->response.htags & HTTP_HEADER_LOCATION)) {
+ con->http_status = 302;
+ }
+
+ return 0;
+}
+
+
+handler_t http_response_parse_headers(server *srv, connection *con, http_response_opts *opts, buffer *b) {
+ /**
+ * possible formats of response headers:
+ *
+ * proxy or NPH (non-parsed headers):
+ *
+ * HTTP/1.0 200 Ok\n
+ * Header: Value\n
+ * \n
+ *
+ * CGI:
+ *
+ * Header: Value\n
+ * Status: 200\n
+ * \n
+ *
+ * and different mixes of \n and \r\n combinations
+ *
+ * Some users also forget about CGI and just send a response
+ * and hope we handle it. No headers, no header-content separator
+ */
+
+ int is_nph = (0 == strncmp(b->ptr, "HTTP/1.", 7)); /*nph (non-parsed hdrs)*/
+ int is_header_end = 0;
+ size_t last_eol = 0;
+ size_t i = 0, header_len = buffer_string_length(b);
+ const char *bstart;
+ size_t blen;
+
+ if (b->ptr[0] == '\n' || (b->ptr[0] == '\r' && b->ptr[1] == '\n')) {
+ /* no HTTP headers */
+ i = (b->ptr[0] == '\n') ? 0 : 1;
+ is_header_end = 1;
+ } else if (is_nph || b->ptr[(i = strcspn(b->ptr, ":\n"))] == ':') {
+ /* HTTP headers */
+ ++i;
+ for (char *c; NULL != (c = strchr(b->ptr+i, '\n')); ++i) {
+ i = (uintptr_t)(c - b->ptr);
+ /**
+ * check if we saw a \n(\r)?\n sequence
+ */
+ if (last_eol > 0 &&
+ ((i - last_eol == 1) ||
+ (i - last_eol == 2 && b->ptr[i - 1] == '\r'))) {
+ is_header_end = 1;
+ break;
+ }
+
+ last_eol = i;
+ }
+ } else if (i == header_len) { /* (no newline yet; partial header line?) */
+ } else if (opts->backend == BACKEND_CGI) {
+ /* no HTTP headers, but a body (special-case for CGI compat) */
+ /* no colon found; does not appear to be HTTP headers */
+ if (0 != http_chunk_append_buffer(srv, con, b)) {
+ return HANDLER_ERROR;
+ }
+ con->http_status = 200; /* OK */
+ con->file_started = 1;
+ return HANDLER_GO_ON;
+ } else {
+ /* invalid response headers */
+ con->http_status = 502; /* Bad Gateway */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ if (!is_header_end) {
+ /*(reuse MAX_HTTP_REQUEST_HEADER as max size
+ * for response headers from backends)*/
+ if (header_len > MAX_HTTP_REQUEST_HEADER) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "response headers too large for", con->uri.path);
+ con->http_status = 502; /* Bad Gateway */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ return HANDLER_GO_ON;
+ }
+
+ /* the body starts after the EOL */
+ bstart = b->ptr + (i + 1);
+ blen = header_len - (i + 1);
+
+ /* strip the last \r?\n */
+ if (i > 0 && (b->ptr[i - 1] == '\r')) {
+ i--;
+ }
+
+ buffer_string_set_length(b, i);
+
+ if (opts->backend == BACKEND_PROXY && !is_nph) {
+ /* invalid response Status-Line from HTTP proxy */
+ con->http_status = 502; /* Bad Gateway */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ if (0 != http_response_process_headers(srv, con, opts, b)) {
+ return HANDLER_ERROR;
+ }
+
+ con->file_started = 1;
+
+ if (opts->authorizer
+ && (con->http_status == 0 || con->http_status == 200)) {
+ return HANDLER_GO_ON;
+ }
+
+ if (con->mode == DIRECT) {
+ return HANDLER_FINISHED;
+ }
+
+ if (opts->local_redir && con->http_status >= 300 && con->http_status < 400){
+ /*(con->response.htags & HTTP_HEADER_LOCATION)*/
+ handler_t rc = http_response_process_local_redir(srv, con, blen);
+ if (con->mode == DIRECT) con->file_started = 0;
+ if (rc != HANDLER_GO_ON) return rc;
+ }
+
+ if (opts->xsendfile_allow) {
+ buffer *vb;
+ /* X-Sendfile2 is deprecated; historical for fastcgi */
+ if (opts->backend == BACKEND_FASTCGI
+ && NULL != (vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-Sendfile2")))) {
+ http_response_xsendfile2(srv, con, vb, opts->xsendfile_docroot);
+ /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */
+ buffer_clear(vb); /*(do not send to client)*/
+ if (con->mode == DIRECT) con->file_started = 0;
+ return HANDLER_FINISHED;
+ } else if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-Sendfile")))
+ || (opts->backend == BACKEND_FASTCGI /* X-LIGHTTPD-send-file is deprecated; historical for fastcgi */
+ && NULL != (vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-LIGHTTPD-send-file"))))) {
+ http_response_xsendfile(srv, con, vb, opts->xsendfile_docroot);
+ /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */
+ buffer_clear(vb); /*(do not send to client)*/
+ if (con->mode == DIRECT) con->file_started = 0;
+ return HANDLER_FINISHED;
+ }
+ }
+
+ if (blen > 0) {
+ if (0 != http_chunk_append_mem(srv, con, bstart, blen)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ /* (callback for response headers complete) */
+ return (opts->headers) ? opts->headers(srv, con, opts) : HANDLER_GO_ON;
+}
+
+
+handler_t http_response_read(server *srv, connection *con, http_response_opts *opts, buffer *b, int fd, int *fde_ndx) {
+ while (1) {
+ ssize_t n;
+ size_t avail = buffer_string_space(b);
+ unsigned int toread = 0;
+
+ if (0 == fdevent_ioctl_fionread(fd, opts->fdfmt, (int *)&toread)) {
+ if (avail < toread) {
+ size_t blen = buffer_string_length(b);
+ if (toread + blen < 4096)
+ toread = 4095 - blen;
+ else if (toread > MAX_READ_LIMIT)
+ toread = MAX_READ_LIMIT;
+ }
+ else if (0 == toread) {
+ #if 0
+ return (fdevent_event_get_interest(srv->ev, fd) & FDEVENT_IN)
+ ? HANDLER_FINISHED /* read finished */
+ : HANDLER_GO_ON; /* optimistic read; data not ready */
+ #else
+ if (!(fdevent_event_get_interest(srv->ev, fd) & FDEVENT_IN)) {
+ if (!(con->conf.stream_response_body
+ & FDEVENT_STREAM_RESPONSE_POLLRDHUP))
+ return HANDLER_GO_ON;/*optimistic read; data not ready*/
+ }
+ if (0 == avail) /* let read() below indicate if EOF or EAGAIN */
+ toread = 1024;
+ #endif
+ }
+ }
+ else if (avail < 1024) {
+ toread = 4095 - avail;
+ }
+
+ if (con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) {
+ off_t cqlen = chunkqueue_length(con->write_queue);
+ if (cqlen + (off_t)toread > 65536 - 4096) {
+ if (!con->is_writable) {
+ /*(defer removal of FDEVENT_IN interest since
+ * connection_state_machine() might be able to send data
+ * immediately, unless !con->is_writable, where
+ * connection_state_machine() might not loop back to call
+ * mod_proxy_handle_subrequest())*/
+ fdevent_event_clr(srv->ev, fde_ndx, fd, FDEVENT_IN);
+ }
+ if (cqlen >= 65536-1) return HANDLER_GO_ON;
+ toread = 65536 - 1 - (unsigned int)cqlen;
+ /* Note: heuristic is fuzzy in that it limits how much to read
+ * from backend based on how much is pending to write to client.
+ * Modules where data from backend is framed (e.g. FastCGI) may
+ * want to limit how much is buffered from backend while waiting
+ * for a complete data frame or data packet from backend. */
+ }
+ }
+
+ if (avail < toread) {
+ /*(add avail+toread to reduce allocations when ioctl EOPNOTSUPP)*/
+ avail = avail ? avail - 1 + toread : toread;
+ buffer_string_prepare_append(b, avail);
+ }
+
+ n = read(fd, b->ptr+buffer_string_length(b), avail);
+
+ if (n < 0) {
+ switch (errno) {
+ case EAGAIN:
+ #ifdef EWOULDBLOCK
+ #if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+ #endif
+ #endif
+ case EINTR:
+ return HANDLER_GO_ON;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssdd",
+ "read():", strerror(errno), con->fd, fd);
+ return HANDLER_ERROR;
+ }
+ }
+
+ buffer_commit(b, (size_t)n);
+
+ if (NULL != opts->parse) {
+ handler_t rc = opts->parse(srv, con, opts, b, (size_t)n);
+ if (rc != HANDLER_GO_ON) return rc;
+ } else if (0 == n) {
+ /* note: no further data is sent to backend after read EOF on socket
+ * (not checking for half-closed TCP socket)
+ * (backend should read all data desired prior to closing socket,
+ * though might send app-level close data frame, if applicable) */
+ return HANDLER_FINISHED; /* read finished */
+ } else if (0 == con->file_started) {
+ /* split header from body */
+ handler_t rc = http_response_parse_headers(srv, con, opts, b);
+ if (rc != HANDLER_GO_ON) return rc;
+ /* accumulate response in b until headers completed (or error) */
+ if (con->file_started) buffer_clear(b);
+ } else {
+ if (0 != http_chunk_append_buffer(srv, con, b)) {
+ /* error writing to tempfile;
+ * truncate response or send 500 if nothing sent yet */
+ return HANDLER_ERROR;
+ }
+ buffer_clear(b);
+ }
+
+ if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
+ && chunkqueue_length(con->write_queue) > 65536 - 4096) {
+ if (!con->is_writable) {
+ /*(defer removal of FDEVENT_IN interest since
+ * connection_state_machine() might be able to send
+ * data immediately, unless !con->is_writable, where
+ * connection_state_machine() might not loop back to
+ * call the subrequest handler)*/
+ fdevent_event_clr(srv->ev, fde_ndx, fd, FDEVENT_IN);
+ }
+ break;
+ }
+
+ if ((size_t)n < avail)
+ break; /* emptied kernel read buffer or partial read */
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cgi_header_append_cb cb, void *vdata) {
+
+ /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
+
+ int rc = 0;
+ server_socket *srv_sock = con->srv_socket;
+ const char *s;
+ size_t n;
+ char buf[LI_ITOSTRING_LENGTH];
+ sock_addr *addr;
+ sock_addr addrbuf;
+ char b2[INET6_ADDRSTRLEN + 1];
+
+ /* (CONTENT_LENGTH must be first for SCGI) */
+ if (!opts->authorizer) {
+ li_itostrn(buf, sizeof(buf), con->request.content_length);
+ rc |= cb(vdata, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
+ }
+
+ if (!buffer_string_is_empty(con->uri.query)) {
+ rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"),
+ CONST_BUF_LEN(con->uri.query));
+ } else {
+ rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"),
+ CONST_STR_LEN(""));
+ }
+ if (!buffer_string_is_empty(opts->strip_request_uri)) {
+ /**
+ * /app1/index/list
+ *
+ * stripping /app1 or /app1/ should lead to
+ *
+ * /index/list
+ *
+ */
+ size_t len = buffer_string_length(opts->strip_request_uri);
+ if ('/' == opts->strip_request_uri->ptr[len-1]) {
+ --len;
+ }
+
+ if (buffer_string_length(con->request.orig_uri) >= len
+ && 0 == memcmp(con->request.orig_uri->ptr,
+ opts->strip_request_uri->ptr, len)
+ && con->request.orig_uri->ptr[len] == '/') {
+ rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
+ con->request.orig_uri->ptr+len,
+ buffer_string_length(con->request.orig_uri) - len);
+ } else {
+ rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
+ CONST_BUF_LEN(con->request.orig_uri));
+ }
+ } else {
+ rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
+ CONST_BUF_LEN(con->request.orig_uri));
+ }
+ if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
+ rc |= cb(vdata, CONST_STR_LEN("REDIRECT_URI"),
+ CONST_BUF_LEN(con->request.uri));
+ }
+ /* set REDIRECT_STATUS for php compiled with --force-redirect
+ * (if REDIRECT_STATUS has not already been set by error handler) */
+ if (0 == con->error_handler_saved_status) {
+ rc |= cb(vdata, CONST_STR_LEN("REDIRECT_STATUS"),
+ CONST_STR_LEN("200"));
+ }
+
+ /*
+ * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
+ * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
+ * (6.1.14, 6.1.6, 6.1.7)
+ */
+ if (!opts->authorizer) {
+ rc |= cb(vdata, CONST_STR_LEN("SCRIPT_NAME"),
+ CONST_BUF_LEN(con->uri.path));
+ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ rc |= cb(vdata, CONST_STR_LEN("PATH_INFO"),
+ CONST_BUF_LEN(con->request.pathinfo));
+ /* PATH_TRANSLATED is only defined if PATH_INFO is set */
+ if (!buffer_string_is_empty(opts->docroot)) {
+ buffer_copy_buffer(srv->tmp_buf, opts->docroot);
+ } else {
+ buffer_copy_buffer(srv->tmp_buf, con->physical.basedir);
+ }
+ buffer_append_string_buffer(srv->tmp_buf, con->request.pathinfo);
+ rc |= cb(vdata, CONST_STR_LEN("PATH_TRANSLATED"),
+ CONST_BUF_LEN(srv->tmp_buf));
+ }
+ }
+
+ /*
+ * SCRIPT_FILENAME and DOCUMENT_ROOT for php
+ * The PHP manual http://www.php.net/manual/en/reserved.variables.php
+ * treatment of PATH_TRANSLATED is different from the one of CGI specs.
+ * (see php.ini cgi.fix_pathinfo = 1 config parameter)
+ */
+
+ if (!buffer_string_is_empty(opts->docroot)) {
+ /* alternate docroot, e.g. for remote FastCGI or SCGI server */
+ buffer_copy_buffer(srv->tmp_buf, opts->docroot);
+ buffer_append_string_buffer(srv->tmp_buf, con->uri.path);
+ rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
+ CONST_BUF_LEN(srv->tmp_buf));
+ rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"),
+ CONST_BUF_LEN(opts->docroot));
+ } else {
+ if (opts->break_scriptfilename_for_php) {
+ /* php.ini config cgi.fix_pathinfo = 1 need a broken SCRIPT_FILENAME
+ * to find out what PATH_INFO is itself
+ *
+ * see src/sapi/cgi_main.c, init_request_info()
+ */
+ buffer_copy_buffer(srv->tmp_buf, con->physical.path);
+ buffer_append_string_buffer(srv->tmp_buf, con->request.pathinfo);
+ rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
+ CONST_BUF_LEN(srv->tmp_buf));
+ } else {
+ rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
+ CONST_BUF_LEN(con->physical.path));
+ }
+ rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"),
+ CONST_BUF_LEN(con->physical.basedir));
+ }
+
+ s = get_http_method_name(con->request.http_method);
+ force_assert(s);
+ rc |= cb(vdata, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
+
+ s = get_http_version_name(con->request.http_version);
+ force_assert(s);
+ rc |= cb(vdata, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
+
+ rc |= cb(vdata, CONST_STR_LEN("SERVER_SOFTWARE"),
+ CONST_BUF_LEN(con->conf.server_tag));
+
+ rc |= cb(vdata, CONST_STR_LEN("GATEWAY_INTERFACE"),
+ CONST_STR_LEN("CGI/1.1"));
+
+ rc |= cb(vdata, CONST_STR_LEN("REQUEST_SCHEME"),
+ CONST_BUF_LEN(con->uri.scheme));
+
+ if (buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https"))) {
+ rc |= cb(vdata, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
+ }
+
+ addr = &srv_sock->addr;
+ li_utostrn(buf, sizeof(buf), sock_addr_get_port(addr));
+ rc |= cb(vdata, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
+
+ switch (addr->plain.sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (sock_addr_is_addr_wildcard(addr)) {
+ socklen_t addrlen = sizeof(addrbuf);
+ if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
+ addr = &addrbuf;
+ } else {
+ s = "";
+ break;
+ }
+ }
+ s = sock_addr_inet_ntop(addr, b2, sizeof(b2)-1);
+ if (NULL == s) s = "";
+ break;
+ default:
+ s = "";
+ break;
+ }
+ force_assert(s);
+ rc |= cb(vdata, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
+
+ if (!buffer_string_is_empty(con->server_name)) {
+ size_t len = buffer_string_length(con->server_name);
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+ if (colon) len = (colon + 1) - con->server_name->ptr;
+ } else {
+ const char *colon = strchr(con->server_name->ptr, ':');
+ if (colon) len = colon - con->server_name->ptr;
+ }
+
+ rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"),
+ con->server_name->ptr, len);
+ } else {
+ /* set to be same as SERVER_ADDR (above) */
+ rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
+ }
+
+ rc |= cb(vdata, CONST_STR_LEN("REMOTE_ADDR"),
+ CONST_BUF_LEN(con->dst_addr_buf));
+
+ li_utostrn(buf, sizeof(buf), sock_addr_get_port(&con->dst_addr));
+ rc |= cb(vdata, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
+
+ for (n = 0; n < con->request.headers->used; n++) {
+ data_string *ds = (data_string *)con->request.headers->data[n];
+ if (!buffer_string_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ /* Security: Do not emit HTTP_PROXY in environment.
+ * Some executables use HTTP_PROXY to configure
+ * outgoing proxy. See also https://httpoxy.org/ */
+ if (buffer_is_equal_caseless_string(ds->key,
+ CONST_STR_LEN("Proxy"))) {
+ continue;
+ }
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf,
+ CONST_BUF_LEN(ds->key), 1);
+ rc |= cb(vdata, CONST_BUF_LEN(srv->tmp_buf),
+ CONST_BUF_LEN(ds->value));
+ }
+ }
+
+ srv->request_env(srv, con);
+
+ for (n = 0; n < con->environment->used; n++) {
+ data_string *ds = (data_string *)con->environment->data[n];
+ if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
+ buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf,
+ CONST_BUF_LEN(ds->key), 0);
+ rc |= cb(vdata, CONST_BUF_LEN(srv->tmp_buf),
+ CONST_BUF_LEN(ds->value));
+ }
+ }
+
+ return rc;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_auth.c b/data/lighttpd/lighttpd-1.4.53/src/http_auth.c
new file mode 100644
index 000000000..484da8ff2
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_auth.c
@@ -0,0 +1,171 @@
+#include "first.h"
+
+#include "http_auth.h"
+#include "http_header.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static http_auth_scheme_t http_auth_schemes[8];
+
+const http_auth_scheme_t * http_auth_scheme_get (const buffer *name)
+{
+ int i = 0;
+ while (NULL != http_auth_schemes[i].name
+ && 0 != strcmp(http_auth_schemes[i].name, name->ptr)) {
+ ++i;
+ }
+ return (NULL != http_auth_schemes[i].name) ? http_auth_schemes+i : NULL;
+}
+
+void http_auth_scheme_set (const http_auth_scheme_t *scheme)
+{
+ unsigned int i = 0;
+ while (NULL != http_auth_schemes[i].name) ++i;
+ /*(must resize http_auth_schemes[] if too many different auth schemes)*/
+ force_assert(i<(sizeof(http_auth_schemes)/sizeof(http_auth_scheme_t))-1);
+ memcpy(http_auth_schemes+i, scheme, sizeof(http_auth_scheme_t));
+}
+
+
+static http_auth_backend_t http_auth_backends[12];
+
+const http_auth_backend_t * http_auth_backend_get (const buffer *name)
+{
+ int i = 0;
+ while (NULL != http_auth_backends[i].name
+ && 0 != strcmp(http_auth_backends[i].name, name->ptr)) {
+ ++i;
+ }
+ return (NULL != http_auth_backends[i].name) ? http_auth_backends+i : NULL;
+}
+
+void http_auth_backend_set (const http_auth_backend_t *backend)
+{
+ unsigned int i = 0;
+ while (NULL != http_auth_backends[i].name) ++i;
+ /*(must resize http_auth_backends[] if too many different auth backends)*/
+ force_assert(i<(sizeof(http_auth_backends)/sizeof(http_auth_backend_t))-1);
+ memcpy(http_auth_backends+i, backend, sizeof(http_auth_backend_t));
+}
+
+
+int http_auth_const_time_memeq (const char *a, const size_t alen, const char *b, const size_t blen)
+{
+ /* constant time memory compare, unless compiler figures it out
+ * (similar to mod_secdownload.c:const_time_memeq()) */
+ /* round to next multiple of 64 to avoid potentially leaking exact
+ * password length when subject to high precision timing attacks) */
+ size_t lim = ((alen >= blen ? alen : blen) + 0x3F) & ~0x3F;
+ int diff = 0;
+ for (size_t i = 0, j = 0; lim; --lim) {
+ diff |= (a[i] ^ b[j]);
+ i += (i < alen);
+ j += (j < blen);
+ }
+ return (0 == diff);
+}
+
+
+void http_auth_dumbdata_reset (void)
+{
+ memset(http_auth_schemes, 0, sizeof(http_auth_schemes));
+ memset(http_auth_backends, 0, sizeof(http_auth_backends));
+}
+
+
+http_auth_require_t * http_auth_require_init (void)
+{
+ http_auth_require_t *require = calloc(1, sizeof(http_auth_require_t));
+ force_assert(NULL != require);
+
+ require->realm = buffer_init();
+ require->valid_user = 0;
+ require->user = array_init();
+ require->group = array_init();
+ require->host = array_init();
+
+ return require;
+}
+
+void http_auth_require_free (http_auth_require_t * const require)
+{
+ buffer_free(require->realm);
+ array_free(require->user);
+ array_free(require->group);
+ array_free(require->host);
+ free(require);
+}
+
+/* (case-sensitive version of array.c:array_get_index(),
+ * and common case expects small num of allowed tokens,
+ * so it is reasonably performant to simply walk the array) */
+static int http_auth_array_contains (const array * const a, const char * const k, const size_t klen)
+{
+ for (size_t i = 0, used = a->used; i < used; ++i) {
+ if (buffer_is_equal_string(a->data[i]->key, k, klen)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int http_auth_match_rules (const http_auth_require_t * const require, const char * const user, const char * const group, const char * const host)
+{
+ if (NULL != user
+ && (require->valid_user
+ || http_auth_array_contains(require->user, user, strlen(user)))) {
+ return 1; /* match */
+ }
+
+ if (NULL != group
+ && http_auth_array_contains(require->group, group, strlen(group))) {
+ return 1; /* match */
+ }
+
+ if (NULL != host
+ && http_auth_array_contains(require->host, host, strlen(host))) {
+ return 1; /* match */
+ }
+
+ return 0; /* no match */
+}
+
+void http_auth_setenv(connection *con, const char *username, size_t ulen, const char *auth_type, size_t alen) {
+ http_header_env_set(con, CONST_STR_LEN("REMOTE_USER"), username, ulen);
+ http_header_env_set(con, CONST_STR_LEN("AUTH_TYPE"), auth_type, alen);
+}
+
+int http_auth_md5_hex2bin (const char *md5hex, size_t len, unsigned char md5bin[16])
+{
+ /* validate and transform 32-byte MD5 hex string to 16-byte binary MD5 */
+ if (32 != len) return -1; /*(Note: char *md5hex must be a 32-char string)*/
+ for (int i = 0; i < 32; i+=2) {
+ int hi = md5hex[i];
+ int lo = md5hex[i+1];
+ if ('0' <= hi && hi <= '9') hi -= '0';
+ else if ((hi |= 0x20), 'a' <= hi && hi <= 'f') hi += -'a' + 10;
+ else return -1;
+ if ('0' <= lo && lo <= '9') lo -= '0';
+ else if ((lo |= 0x20), 'a' <= lo && lo <= 'f') lo += -'a' + 10;
+ else return -1;
+ md5bin[(i >> 1)] = (unsigned char)((hi << 4) | lo);
+ }
+ return 0;
+}
+
+#if 0
+int http_auth_md5_hex2lc (char *md5hex)
+{
+ /* validate and transform 32-byte MD5 hex string to lowercase */
+ int i;
+ for (i = 0; md5hex[i]; ++i) {
+ int c = md5hex[i];
+ if ('0' <= c && c <= '9') continue;
+ else if ((c |= 0x20), 'a' <= c && c <= 'f') md5hex[i] = c;
+ else return -1;
+ }
+ return (32 == i) ? 0 : -1; /*(Note: char *md5hex must be a 32-char string)*/
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_auth.h b/data/lighttpd/lighttpd-1.4.53/src/http_auth.h
new file mode 100644
index 000000000..e652d71bd
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_auth.h
@@ -0,0 +1,52 @@
+#ifndef _HTTP_AUTH_H_
+#define _HTTP_AUTH_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+#include "array.h"
+
+void http_auth_dumbdata_reset (void);
+
+struct http_auth_scheme_t;
+struct http_auth_require_t;
+struct http_auth_backend_t;
+
+typedef struct http_auth_require_t {
+ const struct http_auth_scheme_t *scheme;
+ buffer *realm;
+ int valid_user;
+ array *user;
+ array *group;
+ array *host;
+} http_auth_require_t;
+
+http_auth_require_t * http_auth_require_init (void);
+void http_auth_require_free (http_auth_require_t *require);
+int http_auth_match_rules (const http_auth_require_t *require, const char *user, const char *group, const char *host);
+
+typedef struct http_auth_backend_t {
+ const char *name;
+ handler_t(*basic)(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+ handler_t(*digest)(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
+ void *p_d;
+} http_auth_backend_t;
+
+typedef struct http_auth_scheme_t {
+ const char *name;
+ handler_t(*checkfn)(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
+ /*(backend is arg only because auth.backend is separate config directive)*/
+ void *p_d;
+} http_auth_scheme_t;
+
+const http_auth_scheme_t * http_auth_scheme_get (const buffer *name);
+void http_auth_scheme_set (const http_auth_scheme_t *scheme);
+const http_auth_backend_t * http_auth_backend_get (const buffer *name);
+void http_auth_backend_set (const http_auth_backend_t *backend);
+int http_auth_const_time_memeq (const char *a, size_t alen, const char *b, size_t blen);
+
+void http_auth_setenv(connection *con, const char *username, size_t ulen, const char *auth_type, size_t alen);
+
+int http_auth_md5_hex2bin (const char *md5hex, size_t len, unsigned char md5bin[16]);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_chunk.c b/data/lighttpd/lighttpd-1.4.53/src/http_chunk.c
new file mode 100644
index 000000000..1bdf2fa89
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_chunk.c
@@ -0,0 +1,236 @@
+#include "first.h"
+
+/**
+ * the HTTP chunk-API
+ *
+ *
+ */
+
+#include "base.h"
+#include "chunk.h"
+#include "http_chunk.h"
+#include "stat_cache.h"
+#include "fdevent.h"
+#include "log.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+static buffer * http_chunk_header(buffer *b, uintmax_t len) {
+ buffer_clear(b);
+ buffer_append_uint_hex(b, len);
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ return b;
+}
+
+static void http_chunk_append_len(server *srv, connection *con, uintmax_t len) {
+ buffer *b = http_chunk_header(srv->tmp_chunk_len, len);
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+}
+
+static int http_chunk_append_file_open_fstat(server *srv, connection *con, buffer *fn, struct stat *st) {
+ if (!con->conf.follow_symlink) {
+ /*(preserve existing stat_cache symlink checks)*/
+ stat_cache_entry *sce;
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, fn, &sce)) return -1;
+ }
+
+ return stat_cache_open_rdonly_fstat(srv, con, fn, st);
+}
+
+static void http_chunk_append_file_fd_range(server *srv, connection *con, buffer *fn, int fd, off_t offset, off_t len) {
+ chunkqueue *cq = con->write_queue;
+
+ if (con->response.send_chunked) {
+ http_chunk_append_len(srv, con, (uintmax_t)len);
+ }
+
+ chunkqueue_append_file_fd(cq, fn, fd, offset, len);
+
+ if (con->response.send_chunked) {
+ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+}
+
+int http_chunk_append_file_range(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
+ struct stat st;
+ const int fd = http_chunk_append_file_open_fstat(srv, con, fn, &st);
+ if (fd < 0) return -1;
+
+ if (-1 == len) {
+ if (offset >= st.st_size) {
+ close(fd);
+ return (offset == st.st_size) ? 0 : -1;
+ }
+ len = st.st_size - offset;
+ } else if (st.st_size - offset < len) {
+ close(fd);
+ return -1;
+ }
+
+ http_chunk_append_file_fd_range(srv, con, fn, fd, offset, len);
+ return 0;
+}
+
+int http_chunk_append_file(server *srv, connection *con, buffer *fn) {
+ struct stat st;
+ const int fd = http_chunk_append_file_open_fstat(srv, con, fn, &st);
+ if (fd < 0) return -1;
+
+ if (0 != st.st_size) {
+ http_chunk_append_file_fd_range(srv, con, fn, fd, 0, st.st_size);
+ } else {
+ close(fd);
+ }
+ return 0;
+}
+
+static int http_chunk_append_to_tempfile(server *srv, connection *con, const char * mem, size_t len) {
+ chunkqueue * const cq = con->write_queue;
+
+ if (con->response.send_chunked) {
+ buffer *b = http_chunk_header(srv->tmp_chunk_len, len);
+ if (0 != chunkqueue_append_mem_to_tempfile(srv, cq, CONST_BUF_LEN(b))) {
+ return -1;
+ }
+ }
+
+ if (0 != chunkqueue_append_mem_to_tempfile(srv, cq, mem, len)) {
+ return -1;
+ }
+
+ if (con->response.send_chunked) {
+ if (0 != chunkqueue_append_mem_to_tempfile(srv, cq, CONST_STR_LEN("\r\n"))) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int http_chunk_append_cq_to_tempfile(server *srv, connection *con, chunkqueue *src, size_t len) {
+ chunkqueue * const cq = con->write_queue;
+
+ if (con->response.send_chunked) {
+ buffer *b = http_chunk_header(srv->tmp_chunk_len, len);
+ if (0 != chunkqueue_append_mem_to_tempfile(srv, cq, CONST_BUF_LEN(b))) {
+ return -1;
+ }
+ }
+
+ if (0 != chunkqueue_steal_with_tempfiles(srv, cq, src, len)) {
+ return -1;
+ }
+
+ if (con->response.send_chunked) {
+ if (0!=chunkqueue_append_mem_to_tempfile(srv,cq,CONST_STR_LEN("\r\n"))){
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int http_chunk_uses_tempfile(server *srv, connection *con, size_t len) {
+ chunkqueue * const cq = con->write_queue;
+ chunk *c = cq->last;
+ UNUSED(srv);
+
+ /* current usage does not append_mem or append_buffer after appending
+ * file, so not checking if users of this interface have appended large
+ * (references to) files to chunkqueue, which would not be in memory
+ * (but included in calculation for whether or not to use temp file) */
+
+ /*(allow slightly larger mem use if FDEVENT_STREAM_RESPONSE_BUFMIN
+ * to reduce creation of temp files when backend producer will be
+ * blocked until more data is sent to network to client)*/
+
+ if ((c && c->type == FILE_CHUNK && c->file.is_temp)
+ || cq->bytes_in - cq->bytes_out + len
+ > 1024 * ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) ? 128 : 64)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
+ chunkqueue * const cq = con->write_queue;
+ size_t len = buffer_string_length(mem);
+ if (0 == len) return 0;
+
+ if (http_chunk_uses_tempfile(srv, con, len)) {
+ return http_chunk_append_to_tempfile(srv, con, mem->ptr, len);
+ }
+
+ if (con->response.send_chunked) {
+ http_chunk_append_len(srv, con, len);
+ }
+
+ /*(chunkqueue_append_buffer() might steal buffer contents)*/
+ chunkqueue_append_buffer(cq, mem);
+
+ if (con->response.send_chunked) {
+ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+
+ return 0;
+}
+
+int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
+ chunkqueue * const cq = con->write_queue;
+ if (0 == len) return 0;
+ force_assert(NULL != mem);
+
+ if (http_chunk_uses_tempfile(srv, con, len)) {
+ return http_chunk_append_to_tempfile(srv, con, mem, len);
+ }
+
+ if (con->response.send_chunked) {
+ http_chunk_append_len(srv, con, len);
+ }
+
+ chunkqueue_append_mem(cq, mem, len);
+
+ if (con->response.send_chunked) {
+ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+
+ return 0;
+}
+
+int http_chunk_transfer_cqlen(server *srv, connection *con, chunkqueue *src, size_t len) {
+ chunkqueue * const cq = con->write_queue;
+ if (0 == len) return 0;
+
+ if (http_chunk_uses_tempfile(srv, con, len)) {
+ return http_chunk_append_cq_to_tempfile(srv, con, src, len);
+ }
+
+ if (con->response.send_chunked) {
+ http_chunk_append_len(srv, con, len);
+ }
+
+ chunkqueue_steal(cq, src, len);
+
+ if (con->response.send_chunked) {
+ chunkqueue_append_mem(cq, CONST_STR_LEN("\r\n"));
+ }
+
+ return 0;
+}
+
+void http_chunk_close(server *srv, connection *con) {
+ UNUSED(srv);
+ force_assert(NULL != con);
+
+ if (con->response.send_chunked) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("0\r\n\r\n"));
+ }
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_chunk.h b/data/lighttpd/lighttpd-1.4.53/src/http_chunk.h
new file mode 100644
index 000000000..ab335257a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_chunk.h
@@ -0,0 +1,14 @@
+#ifndef _HTTP_CHUNK_H_
+#define _HTTP_CHUNK_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len); /* copies memory */
+int http_chunk_append_buffer(server *srv, connection *con, buffer *mem); /* may reset "mem" */
+int http_chunk_transfer_cqlen(server *srv, connection *con, chunkqueue *src, size_t len);
+int http_chunk_append_file(server *srv, connection *con, buffer *fn); /* copies "fn" */
+int http_chunk_append_file_range(server *srv, connection *con, buffer *fn, off_t offset, off_t len); /* copies "fn" */
+void http_chunk_close(server *srv, connection *con);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_header.c b/data/lighttpd/lighttpd-1.4.53/src/http_header.c
new file mode 100644
index 000000000..22e0d70c5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_header.c
@@ -0,0 +1,190 @@
+#include "first.h"
+
+#include "http_header.h"
+#include "base.h"
+#include "array.h"
+#include "buffer.h"
+
+
+typedef struct keyvlenvalue {
+ const int key;
+ const char * const value;
+ const size_t vlen;
+} keyvlenvalue;
+
+/* Note: must be sorted by length */
+/* Note: must be kept in sync with http_header.h enum http_header_e */
+static const keyvlenvalue http_headers[] = {
+ { HTTP_HEADER_HOST, CONST_STR_LEN("Host") }
+ ,{ HTTP_HEADER_DATE, CONST_STR_LEN("Date") }
+ ,{ HTTP_HEADER_ETAG, CONST_STR_LEN("ETag") }
+ ,{ HTTP_HEADER_VARY, CONST_STR_LEN("Vary") }
+ ,{ HTTP_HEADER_RANGE, CONST_STR_LEN("Range") }
+ ,{ HTTP_HEADER_COOKIE, CONST_STR_LEN("Cookie") }
+ ,{ HTTP_HEADER_EXPECT, CONST_STR_LEN("Expect") }
+ ,{ HTTP_HEADER_STATUS, CONST_STR_LEN("Status") }
+ ,{ HTTP_HEADER_SERVER, CONST_STR_LEN("Server") }
+ ,{ HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade") }
+ ,{ HTTP_HEADER_LOCATION, CONST_STR_LEN("Location") }
+ ,{ HTTP_HEADER_FORWARDED, CONST_STR_LEN("Forwarded") }
+ ,{ HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection") }
+ ,{ HTTP_HEADER_SET_COOKIE, CONST_STR_LEN("Set-Cookie") }
+ ,{ HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type") }
+ ,{ HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified") }
+ ,{ HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization") }
+ ,{ HTTP_HEADER_IF_NONE_MATCH, CONST_STR_LEN("If-None-Match") }
+ ,{ HTTP_HEADER_CACHE_CONTROL, CONST_STR_LEN("Cache-Control") }
+ ,{ HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length") }
+ ,{ HTTP_HEADER_ACCEPT_ENCODING, CONST_STR_LEN("Accept-Encoding") }
+ ,{ HTTP_HEADER_X_FORWARDED_FOR, CONST_STR_LEN("X-Forwarded-For") }
+ ,{ HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding") }
+ ,{ HTTP_HEADER_CONTENT_LOCATION, CONST_STR_LEN("Content-Location") }
+ ,{ HTTP_HEADER_IF_MODIFIED_SINCE, CONST_STR_LEN("If-Modified-Since") }
+ ,{ HTTP_HEADER_TRANSFER_ENCODING, CONST_STR_LEN("Transfer-Encoding") }
+ ,{ HTTP_HEADER_X_FORWARDED_PROTO, CONST_STR_LEN("X-Forwarded-Proto") }
+ ,{ HTTP_HEADER_OTHER, NULL, 0 }
+};
+
+enum http_header_e http_header_hkey_get(const char *s, size_t slen) {
+ const struct keyvlenvalue * const kv = http_headers;
+ for (int i = 0; kv[i].vlen && slen >= kv[i].vlen; ++i) {
+ if (slen == kv[i].vlen
+ && 0 == buffer_caseless_compare(s, slen, kv[i].value, kv[i].vlen))
+ return (enum http_header_e)kv[i].key;
+ }
+ return HTTP_HEADER_OTHER;
+}
+
+
+buffer * http_header_response_get(connection *con, enum http_header_e id, const char *k, size_t klen) {
+ data_string * const ds =
+ (id <= HTTP_HEADER_OTHER || (con->response.htags & id))
+ ? (data_string *)array_get_element_klen(con->response.headers, k, klen)
+ : NULL;
+ return ds && !buffer_string_is_empty(ds->value) ? ds->value : NULL;
+}
+
+void http_header_response_unset(connection *con, enum http_header_e id, const char *k, size_t klen) {
+ if (id <= HTTP_HEADER_OTHER || (con->response.htags & id)) {
+ if (id > HTTP_HEADER_OTHER) con->response.htags &= ~id;
+ array_set_key_value(con->response.headers, k, klen, CONST_STR_LEN(""));
+ }
+}
+
+void http_header_response_set(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
+ /* set value, including setting blank value if 0 == vlen
+ * (note: if 0 == vlen, header is still inserted with blank value,
+ * which is used to indicate a "removed" header)
+ */
+ if (id > HTTP_HEADER_OTHER)
+ (vlen) ? (con->response.htags |= id) : (con->response.htags &= ~id);
+ array_set_key_value(con->response.headers, k, klen, v, vlen);
+}
+
+void http_header_response_append(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
+ if (vlen) {
+ data_string *ds= (id <= HTTP_HEADER_OTHER || (con->response.htags & id))
+ ? (data_string *)array_get_element_klen(con->response.headers,k,klen)
+ : NULL;
+ if (id > HTTP_HEADER_OTHER) con->response.htags |= id;
+ if (NULL == ds) {
+ array_insert_key_value(con->response.headers, k, klen, v, vlen);
+ }
+ else { /* append value */
+ buffer *vb = ds->value;
+ if (!buffer_string_is_empty(vb))
+ buffer_append_string_len(vb, CONST_STR_LEN(", "));
+ buffer_append_string_len(vb, v, vlen);
+ }
+ }
+}
+
+void http_header_response_insert(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
+ if (vlen) {
+ data_string *ds= (id <= HTTP_HEADER_OTHER || (con->response.htags & id))
+ ? (data_string *)array_get_element_klen(con->response.headers,k,klen)
+ : NULL;
+ if (id > HTTP_HEADER_OTHER) con->response.htags |= id;
+ if (NULL == ds) {
+ array_insert_key_value(con->response.headers, k, klen, v, vlen);
+ }
+ else { /* append value */
+ buffer *vb = ds->value;
+ if (!buffer_string_is_empty(vb)) {
+ buffer_append_string_len(vb, CONST_STR_LEN("\r\n"));
+ buffer_append_string_len(vb, k, klen);
+ buffer_append_string_len(vb, CONST_STR_LEN(": "));
+ }
+ buffer_append_string_len(vb, v, vlen);
+ }
+ }
+}
+
+
+buffer * http_header_request_get(connection *con, enum http_header_e id, const char *k, size_t klen) {
+ data_string * const ds =
+ (id <= HTTP_HEADER_OTHER || (con->request.htags & id))
+ ? (data_string *)array_get_element_klen(con->request.headers, k, klen)
+ : NULL;
+ return ds && !buffer_string_is_empty(ds->value) ? ds->value : NULL;
+}
+
+void http_header_request_unset(connection *con, enum http_header_e id, const char *k, size_t klen) {
+ if (id <= HTTP_HEADER_OTHER || (con->request.htags & id)) {
+ if (id > HTTP_HEADER_OTHER) con->request.htags &= ~id;
+ array_set_key_value(con->request.headers, k, klen, CONST_STR_LEN(""));
+ }
+}
+
+void http_header_request_set(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
+ /* set value, including setting blank value if 0 == vlen
+ * (note: if 0 == vlen, header is still inserted with blank value,
+ * which is used to indicate a "removed" header)
+ */
+ if (id > HTTP_HEADER_OTHER)
+ (vlen) ? (con->request.htags |= id) : (con->request.htags &= ~id);
+ array_set_key_value(con->request.headers, k, klen, v, vlen);
+}
+
+void http_header_request_append(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
+ if (vlen) {
+ data_string *ds = (id <= HTTP_HEADER_OTHER || (con->request.htags & id))
+ ? (data_string *)array_get_element_klen(con->request.headers, k, klen)
+ : NULL;
+ if (id > HTTP_HEADER_OTHER) con->request.htags |= id;
+ if (NULL == ds) {
+ array_insert_key_value(con->request.headers, k, klen, v, vlen);
+ }
+ else { /* append value */
+ buffer *vb = ds->value;
+ if (!buffer_string_is_empty(vb))
+ buffer_append_string_len(vb, CONST_STR_LEN(", "));
+ buffer_append_string_len(vb, v, vlen);
+ }
+ }
+}
+
+
+buffer * http_header_env_get(connection *con, const char *k, size_t klen) {
+ data_string * const ds =
+ (data_string *)array_get_element_klen(con->environment, k, klen);
+ return ds && !buffer_string_is_empty(ds->value) ? ds->value : NULL;
+}
+
+void http_header_env_set(connection *con, const char *k, size_t klen, const char *v, size_t vlen) {
+ array_set_key_value(con->environment, k, klen, v, vlen);
+}
+
+void http_header_env_append(connection *con, const char *k, size_t klen, const char *v, size_t vlen) {
+ /*if (vlen)*/ /* skip check; permit env var w/ blank value to be appended */
+ {
+ buffer * const vb = http_header_env_get(con, k, klen);
+ if (NULL == vb) {
+ array_insert_key_value(con->environment, k, klen, v, vlen);
+ }
+ else if (vlen) { /* append value */
+ buffer_append_string_len(vb, CONST_STR_LEN(", "));
+ buffer_append_string_len(vb, v, vlen);
+ }
+ }
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_header.h b/data/lighttpd/lighttpd-1.4.53/src/http_header.h
new file mode 100644
index 000000000..f19d1d96e
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_header.h
@@ -0,0 +1,59 @@
+#ifndef INCLUDED_HTTP_HEADER_H
+#define INCLUDED_HTTP_HEADER_H
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+/* Note: must be kept in sync with http_header.c http_headers[] */
+/* Note: when adding new items, must replace OTHER in existing code for item */
+enum http_header_e {
+ HTTP_HEADER_UNSPECIFIED = -1
+ ,HTTP_HEADER_OTHER = 0x00000000
+ ,HTTP_HEADER_ACCEPT_ENCODING = 0x00000001
+ ,HTTP_HEADER_AUTHORIZATION = 0x00000002
+ ,HTTP_HEADER_CACHE_CONTROL = 0x00000004
+ ,HTTP_HEADER_CONNECTION = 0x00000008
+ ,HTTP_HEADER_CONTENT_ENCODING = 0x00000010
+ ,HTTP_HEADER_CONTENT_LENGTH = 0x00000020
+ ,HTTP_HEADER_CONTENT_LOCATION = 0x00000040
+ ,HTTP_HEADER_CONTENT_TYPE = 0x00000080
+ ,HTTP_HEADER_COOKIE = 0x00000100
+ ,HTTP_HEADER_DATE = 0x00000200
+ ,HTTP_HEADER_ETAG = 0x00000400
+ ,HTTP_HEADER_EXPECT = 0x00000800
+ ,HTTP_HEADER_FORWARDED = 0x00001000
+ ,HTTP_HEADER_HOST = 0x00002000
+ ,HTTP_HEADER_IF_MODIFIED_SINCE = 0x00004000
+ ,HTTP_HEADER_IF_NONE_MATCH = 0x00008000
+ ,HTTP_HEADER_LAST_MODIFIED = 0x00010000
+ ,HTTP_HEADER_LOCATION = 0x00020000
+ ,HTTP_HEADER_RANGE = 0x00040000
+ ,HTTP_HEADER_SERVER = 0x00080000
+ ,HTTP_HEADER_SET_COOKIE = 0x00100000
+ ,HTTP_HEADER_STATUS = 0x00200000
+ ,HTTP_HEADER_TRANSFER_ENCODING = 0x00400000
+ ,HTTP_HEADER_UPGRADE = 0x00800000
+ ,HTTP_HEADER_VARY = 0x01000000
+ ,HTTP_HEADER_X_FORWARDED_FOR = 0x02000000
+ ,HTTP_HEADER_X_FORWARDED_PROTO = 0x04000000
+};
+
+enum http_header_e http_header_hkey_get(const char *s, size_t slen);
+
+buffer * http_header_response_get(connection *con, enum http_header_e id, const char *k, size_t klen);
+void http_header_response_unset(connection *con, enum http_header_e id, const char *k, size_t klen);
+void http_header_response_set(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen);
+void http_header_response_append(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen);
+void http_header_response_insert(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen);
+
+buffer * http_header_request_get(connection *con, enum http_header_e id, const char *k, size_t klen);
+void http_header_request_unset(connection *con, enum http_header_e id, const char *k, size_t klen);
+void http_header_request_set(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen);
+void http_header_request_append(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen);
+
+buffer * http_header_env_get(connection *con, const char *k, size_t klen);
+void http_header_env_set(connection *con, const char *k, size_t klen, const char *v, size_t vlen);
+void http_header_env_append(connection *con, const char *k, size_t klen, const char *v, size_t vlen);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_kv.c b/data/lighttpd/lighttpd-1.4.53/src/http_kv.c
new file mode 100644
index 000000000..2ddbf7da3
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_kv.c
@@ -0,0 +1,176 @@
+#include "first.h"
+
+#include "http_kv.h"
+#include "buffer.h"
+
+#include <string.h>
+
+typedef struct {
+ int key;
+ const char *value;
+ size_t vlen;
+} keyvalue;
+
+static const keyvalue http_versions[] = {
+ { HTTP_VERSION_1_1, CONST_STR_LEN("HTTP/1.1") },
+ { HTTP_VERSION_1_0, CONST_STR_LEN("HTTP/1.0") },
+ { HTTP_VERSION_UNSET, NULL, 0 }
+};
+
+static const keyvalue http_methods[] = {
+ { HTTP_METHOD_GET, CONST_STR_LEN("GET") },
+ { HTTP_METHOD_HEAD, CONST_STR_LEN("HEAD") },
+ { HTTP_METHOD_POST, CONST_STR_LEN("POST") },
+ { HTTP_METHOD_PUT, CONST_STR_LEN("PUT") },
+ { HTTP_METHOD_DELETE, CONST_STR_LEN("DELETE") },
+ { HTTP_METHOD_CONNECT, CONST_STR_LEN("CONNECT") },
+ { HTTP_METHOD_OPTIONS, CONST_STR_LEN("OPTIONS") },
+ { HTTP_METHOD_TRACE, CONST_STR_LEN("TRACE") },
+ { HTTP_METHOD_ACL, CONST_STR_LEN("ACL") },
+ { HTTP_METHOD_BASELINE_CONTROL, CONST_STR_LEN("BASELINE-CONTROL") },
+ { HTTP_METHOD_BIND, CONST_STR_LEN("BIND") },
+ { HTTP_METHOD_CHECKIN, CONST_STR_LEN("CHECKIN") },
+ { HTTP_METHOD_CHECKOUT, CONST_STR_LEN("CHECKOUT") },
+ { HTTP_METHOD_COPY, CONST_STR_LEN("COPY") },
+ { HTTP_METHOD_LABEL, CONST_STR_LEN("LABEL") },
+ { HTTP_METHOD_LINK, CONST_STR_LEN("LINK") },
+ { HTTP_METHOD_LOCK, CONST_STR_LEN("LOCK") },
+ { HTTP_METHOD_MERGE, CONST_STR_LEN("MERGE") },
+ { HTTP_METHOD_MKACTIVITY, CONST_STR_LEN("MKACTIVITY") },
+ { HTTP_METHOD_MKCALENDAR, CONST_STR_LEN("MKCALENDAR") },
+ { HTTP_METHOD_MKCOL, CONST_STR_LEN("MKCOL") },
+ { HTTP_METHOD_MKREDIRECTREF, CONST_STR_LEN("MKREDIRECTREF") },
+ { HTTP_METHOD_MKWORKSPACE, CONST_STR_LEN("MKWORKSPACE") },
+ { HTTP_METHOD_MOVE, CONST_STR_LEN("MOVE") },
+ { HTTP_METHOD_ORDERPATCH, CONST_STR_LEN("ORDERPATCH") },
+ { HTTP_METHOD_PATCH, CONST_STR_LEN("PATCH") },
+ { HTTP_METHOD_PROPFIND, CONST_STR_LEN("PROPFIND") },
+ { HTTP_METHOD_PROPPATCH, CONST_STR_LEN("PROPPATCH") },
+ { HTTP_METHOD_REBIND, CONST_STR_LEN("REBIND") },
+ { HTTP_METHOD_REPORT, CONST_STR_LEN("REPORT") },
+ { HTTP_METHOD_SEARCH, CONST_STR_LEN("SEARCH") },
+ { HTTP_METHOD_UNBIND, CONST_STR_LEN("UNBIND") },
+ { HTTP_METHOD_UNCHECKOUT, CONST_STR_LEN("UNCHECKOUT") },
+ { HTTP_METHOD_UNLINK, CONST_STR_LEN("UNLINK") },
+ { HTTP_METHOD_UNLOCK, CONST_STR_LEN("UNLOCK") },
+ { HTTP_METHOD_UPDATE, CONST_STR_LEN("UPDATE") },
+ { HTTP_METHOD_UPDATEREDIRECTREF, CONST_STR_LEN("UPDATEREDIRECTREF") },
+ { HTTP_METHOD_VERSION_CONTROL, CONST_STR_LEN("VERSION-CONTROL") },
+
+ { HTTP_METHOD_UNSET, NULL, 0 }
+};
+
+static const keyvalue http_status[] = {
+ { 100, CONST_STR_LEN("100 Continue") },
+ { 101, CONST_STR_LEN("101 Switching Protocols") },
+ { 102, CONST_STR_LEN("102 Processing") }, /* WebDAV */
+ { 200, CONST_STR_LEN("200 OK") },
+ { 201, CONST_STR_LEN("201 Created") },
+ { 202, CONST_STR_LEN("202 Accepted") },
+ { 203, CONST_STR_LEN("203 Non-Authoritative Information") },
+ { 204, CONST_STR_LEN("204 No Content") },
+ { 205, CONST_STR_LEN("205 Reset Content") },
+ { 206, CONST_STR_LEN("206 Partial Content") },
+ { 207, CONST_STR_LEN("207 Multi-status") }, /* WebDAV */
+ { 300, CONST_STR_LEN("300 Multiple Choices") },
+ { 301, CONST_STR_LEN("301 Moved Permanently") },
+ { 302, CONST_STR_LEN("302 Found") },
+ { 303, CONST_STR_LEN("303 See Other") },
+ { 304, CONST_STR_LEN("304 Not Modified") },
+ { 305, CONST_STR_LEN("305 Use Proxy") },
+ { 306, CONST_STR_LEN("306 (Unused)") },
+ { 307, CONST_STR_LEN("307 Temporary Redirect") },
+ { 308, CONST_STR_LEN("308 Permanent Redirect") },
+ { 400, CONST_STR_LEN("400 Bad Request") },
+ { 401, CONST_STR_LEN("401 Unauthorized") },
+ { 402, CONST_STR_LEN("402 Payment Required") },
+ { 403, CONST_STR_LEN("403 Forbidden") },
+ { 404, CONST_STR_LEN("404 Not Found") },
+ { 405, CONST_STR_LEN("405 Method Not Allowed") },
+ { 406, CONST_STR_LEN("406 Not Acceptable") },
+ { 407, CONST_STR_LEN("407 Proxy Authentication Required") },
+ { 408, CONST_STR_LEN("408 Request Timeout") },
+ { 409, CONST_STR_LEN("409 Conflict") },
+ { 410, CONST_STR_LEN("410 Gone") },
+ { 411, CONST_STR_LEN("411 Length Required") },
+ { 412, CONST_STR_LEN("412 Precondition Failed") },
+ { 413, CONST_STR_LEN("413 Request Entity Too Large") },
+ { 414, CONST_STR_LEN("414 Request-URI Too Long") },
+ { 415, CONST_STR_LEN("415 Unsupported Media Type") },
+ { 416, CONST_STR_LEN("416 Requested Range Not Satisfiable") },
+ { 417, CONST_STR_LEN("417 Expectation Failed") },
+ { 422, CONST_STR_LEN("422 Unprocessable Entity") }, /* WebDAV */
+ { 423, CONST_STR_LEN("423 Locked") }, /* WebDAV */
+ { 424, CONST_STR_LEN("424 Failed Dependency") }, /* WebDAV */
+ { 426, CONST_STR_LEN("426 Upgrade Required") }, /* TLS */
+ { 500, CONST_STR_LEN("500 Internal Server Error") },
+ { 501, CONST_STR_LEN("501 Not Implemented") },
+ { 502, CONST_STR_LEN("502 Bad Gateway") },
+ { 503, CONST_STR_LEN("503 Service Not Available") },
+ { 504, CONST_STR_LEN("504 Gateway Timeout") },
+ { 505, CONST_STR_LEN("505 HTTP Version Not Supported") },
+ { 507, CONST_STR_LEN("507 Insufficient Storage") }, /* WebDAV */
+
+ { -1, NULL, 0 }
+};
+
+
+static const char *keyvalue_get_value(const keyvalue *kv, int k) {
+ int i;
+ for (i = 0; kv[i].value; i++) {
+ if (kv[i].key == k) return kv[i].value;
+ }
+ return NULL;
+}
+
+static int keyvalue_get_key(const keyvalue *kv, const char *s) {
+ int i;
+ for (i = 0; kv[i].value; i++) {
+ if (0 == strcmp(kv[i].value, s)) return kv[i].key;
+ }
+ return -1;
+}
+
+
+const char *get_http_version_name(int i) {
+ return keyvalue_get_value(http_versions, i);
+}
+
+const char *get_http_status_name(int i) {
+ return keyvalue_get_value(http_status, i);
+}
+
+const char *get_http_method_name(http_method_t i) {
+ return keyvalue_get_value(http_methods, i);
+}
+
+int get_http_version_key(const char *s) {
+ return keyvalue_get_key(http_versions, s);
+}
+
+http_method_t get_http_method_key(const char *s) {
+ return (http_method_t)keyvalue_get_key(http_methods, s);
+}
+
+
+void http_status_append(buffer * const b, const int status) {
+ const keyvalue * const kv = http_status;
+ int i;
+ for (i = 0; kv[i].key != status && kv[i].value; ++i) ;
+ if (kv[i].value) {
+ buffer_append_string_len(b, kv[i].value, kv[i].vlen);
+ }
+ else {
+ buffer_append_int(b, status);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ }
+}
+
+void http_method_append(buffer * const b, const http_method_t method) {
+ const keyvalue * const kv = http_methods;
+ int i;
+ for (i = 0; kv[i].key != method && kv[i].value; ++i) ;
+ if (kv[i].value) {
+ buffer_append_string_len(b, kv[i].value, kv[i].vlen);
+ }
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_kv.h b/data/lighttpd/lighttpd-1.4.53/src/http_kv.h
new file mode 100644
index 000000000..41abb6aaf
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_kv.h
@@ -0,0 +1,69 @@
+#ifndef INCLUDED_HTTP_KV_H
+#define INCLUDED_HTTP_KV_H
+#include "first.h"
+
+#include "buffer.h"
+
+/* sources:
+ * - [RFC2616], Section 9
+ * (or http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-22)
+ * - http://tools.ietf.org/html/draft-ietf-httpbis-method-registrations-11, Appendix A
+ *
+ * http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-22, Section 8.1 defines
+ * a new registry (not available yet):
+ * http://www.iana.org/assignments/http-methods
+ */
+
+typedef enum {
+ HTTP_METHOD_UNSET = -1,
+ HTTP_METHOD_GET, /* [RFC2616], Section 9.3 */
+ HTTP_METHOD_HEAD, /* [RFC2616], Section 9.4 */
+ HTTP_METHOD_POST, /* [RFC2616], Section 9.5 */
+ HTTP_METHOD_PUT, /* [RFC2616], Section 9.6 */
+ HTTP_METHOD_DELETE, /* [RFC2616], Section 9.7 */
+ HTTP_METHOD_CONNECT, /* [RFC2616], Section 9.9 */
+ HTTP_METHOD_OPTIONS, /* [RFC2616], Section 9.2 */
+ HTTP_METHOD_TRACE, /* [RFC2616], Section 9.8 */
+ HTTP_METHOD_ACL, /* [RFC3744], Section 8.1 */
+ HTTP_METHOD_BASELINE_CONTROL, /* [RFC3253], Section 12.6 */
+ HTTP_METHOD_BIND, /* [RFC5842], Section 4 */
+ HTTP_METHOD_CHECKIN, /* [RFC3253], Section 4.4 and [RFC3253], Section 9.4 */
+ HTTP_METHOD_CHECKOUT, /* [RFC3253], Section 4.3 and [RFC3253], Section 8.8 */
+ HTTP_METHOD_COPY, /* [RFC4918], Section 9.8 */
+ HTTP_METHOD_LABEL, /* [RFC3253], Section 8.2 */
+ HTTP_METHOD_LINK, /* [RFC2068], Section 19.6.1.2 */
+ HTTP_METHOD_LOCK, /* [RFC4918], Section 9.10 */
+ HTTP_METHOD_MERGE, /* [RFC3253], Section 11.2 */
+ HTTP_METHOD_MKACTIVITY, /* [RFC3253], Section 13.5 */
+ HTTP_METHOD_MKCALENDAR, /* [RFC4791], Section 5.3.1 */
+ HTTP_METHOD_MKCOL, /* [RFC4918], Section 9.3 */
+ HTTP_METHOD_MKREDIRECTREF, /* [RFC4437], Section 6 */
+ HTTP_METHOD_MKWORKSPACE, /* [RFC3253], Section 6.3 */
+ HTTP_METHOD_MOVE, /* [RFC4918], Section 9.9 */
+ HTTP_METHOD_ORDERPATCH, /* [RFC3648], Section 7 */
+ HTTP_METHOD_PATCH, /* [RFC5789], Section 2 */
+ HTTP_METHOD_PROPFIND, /* [RFC4918], Section 9.1 */
+ HTTP_METHOD_PROPPATCH, /* [RFC4918], Section 9.2 */
+ HTTP_METHOD_REBIND, /* [RFC5842], Section 6 */
+ HTTP_METHOD_REPORT, /* [RFC3253], Section 3.6 */
+ HTTP_METHOD_SEARCH, /* [RFC5323], Section 2 */
+ HTTP_METHOD_UNBIND, /* [RFC5842], Section 5 */
+ HTTP_METHOD_UNCHECKOUT, /* [RFC3253], Section 4.5 */
+ HTTP_METHOD_UNLINK, /* [RFC2068], Section 19.6.1.3 */
+ HTTP_METHOD_UNLOCK, /* [RFC4918], Section 9.11 */
+ HTTP_METHOD_UPDATE, /* [RFC3253], Section 7.1 */
+ HTTP_METHOD_UPDATEREDIRECTREF, /* [RFC4437], Section 7 */
+ HTTP_METHOD_VERSION_CONTROL /* [RFC3253], Section 3.5 */
+} http_method_t;
+
+typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } http_version_t;
+
+const char *get_http_status_name(int i);
+const char *get_http_version_name(int i);
+const char *get_http_method_name(http_method_t i);
+int get_http_version_key(const char *s);
+http_method_t get_http_method_key(const char *s);
+void http_status_append(buffer *b, int status);
+void http_method_append(buffer *b, http_method_t method);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.c b/data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.c
new file mode 100644
index 000000000..db8871ce3
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.c
@@ -0,0 +1,35 @@
+#include "first.h"
+
+#include "http_vhostdb.h"
+
+#include <string.h>
+
+
+static http_vhostdb_backend_t http_vhostdb_backends[8];
+
+void http_vhostdb_dumbdata_reset (void)
+{
+ memset(http_vhostdb_backends, 0, sizeof(http_vhostdb_backends));
+}
+
+const http_vhostdb_backend_t * http_vhostdb_backend_get (const buffer *name)
+{
+ int i = 0;
+ while (NULL != http_vhostdb_backends[i].name
+ && 0 != strcmp(http_vhostdb_backends[i].name, name->ptr)) {
+ ++i;
+ }
+ return (NULL != http_vhostdb_backends[i].name)
+ ? http_vhostdb_backends+i
+ : NULL;
+}
+
+void http_vhostdb_backend_set (const http_vhostdb_backend_t *backend)
+{
+ unsigned int i = 0;
+ while (NULL != http_vhostdb_backends[i].name) ++i;
+ /*(must resize http_vhostdb_backends[] if too many different backends)*/
+ force_assert(
+ i < (sizeof(http_vhostdb_backends)/sizeof(http_vhostdb_backend_t))-1);
+ memcpy(http_vhostdb_backends+i, backend, sizeof(http_vhostdb_backend_t));
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.h b/data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.h
new file mode 100644
index 000000000..01036077b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/http_vhostdb.h
@@ -0,0 +1,21 @@
+#ifndef _HTTP_VHOST_H_
+#define _HTTP_VHOST_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+void http_vhostdb_dumbdata_reset (void);
+
+struct http_vhostdb_backend_t;
+
+typedef struct http_vhostdb_backend_t {
+ const char *name;
+ int(*query)(server *srv, connection *con, void *p_d, buffer *result);
+ void *p_d;
+} http_vhostdb_backend_t;
+
+const http_vhostdb_backend_t * http_vhostdb_backend_get (const buffer *name);
+void http_vhostdb_backend_set (const http_vhostdb_backend_t *backend);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.c b/data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.c
new file mode 100644
index 000000000..868b8df2f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.c
@@ -0,0 +1,76 @@
+#include "first.h"
+
+#include "inet_ntop_cache.h"
+
+#include "sys-socket.h"
+#include <sys/types.h>
+#include <string.h>
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+#include "sock_addr.h"
+
+
+const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
+#ifdef HAVE_IPV6
+ typedef struct {
+ int family;
+ union {
+ struct in6_addr ipv6;
+ struct in_addr ipv4;
+ } addr;
+ char b2[INET6_ADDRSTRLEN + 1];
+ } inet_ntop_cache_type;
+ #define INET_NTOP_CACHE_MAX 4
+ static inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
+ static int ndx;
+
+ int i;
+ UNUSED(srv);
+ #ifdef HAVE_SYS_UN_H
+ if (addr->plain.sa_family == AF_UNIX) return addr->un.sun_path;
+ #endif
+ for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
+ if (inet_ntop_cache[i].family == addr->plain.sa_family) {
+ if (inet_ntop_cache[i].family == AF_INET6 &&
+ 0 == memcmp(inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16)) {
+ /* IPv6 found in cache */
+ break;
+ } else if (inet_ntop_cache[i].family == AF_INET &&
+ inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
+ /* IPv4 found in cache */
+ break;
+
+ }
+ }
+ }
+
+ if (i == INET_NTOP_CACHE_MAX) {
+ /* not found in cache */
+ const char *s;
+
+ i = ndx;
+ if (++ndx >= INET_NTOP_CACHE_MAX) ndx = 0;
+ s = sock_addr_inet_ntop(addr, inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
+ if (NULL == s) return "";
+
+ inet_ntop_cache[i].family = addr->plain.sa_family;
+
+ if (inet_ntop_cache[i].family == AF_INET) {
+ inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
+ } else if (inet_ntop_cache[i].family == AF_INET6) {
+ memcpy(inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
+ }
+ }
+
+ return inet_ntop_cache[i].b2;
+#else
+ UNUSED(srv);
+ if (addr->plain.sa_family == AF_INET) return inet_ntoa(addr->ipv4.sin_addr);
+ #ifdef HAVE_SYS_UN_H
+ if (addr->plain.sa_family == AF_UNIX) return addr->un.sun_path;
+ #endif
+ return "";
+#endif
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.h b/data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.h
new file mode 100644
index 000000000..027f40977
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/inet_ntop_cache.h
@@ -0,0 +1,9 @@
+#ifndef _INET_NTOP_CACHE_H_
+#define _INET_NTOP_CACHE_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/joblist.c b/data/lighttpd/lighttpd-1.4.53/src/joblist.c
new file mode 100644
index 000000000..7c2102478
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/joblist.c
@@ -0,0 +1,66 @@
+#include "first.h"
+
+#include "base.h"
+#include "joblist.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+int joblist_append(server *srv, connection *con) {
+ if (srv->joblist->size == 0) {
+ srv->joblist->size = 16;
+ srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
+ force_assert(NULL != srv->joblist->ptr);
+ } else if (srv->joblist->used == srv->joblist->size) {
+ srv->joblist->size += 16;
+ srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
+ force_assert(NULL != srv->joblist->ptr);
+ }
+
+ srv->joblist->ptr[srv->joblist->used++] = con;
+
+ return 0;
+}
+
+void joblist_free(server *srv, connections *joblist) {
+ UNUSED(srv);
+
+ free(joblist->ptr);
+ free(joblist);
+}
+
+connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
+ connection *con;
+ UNUSED(srv);
+
+
+ if (fdwaitqueue->used == 0) return NULL;
+
+ con = fdwaitqueue->ptr[0];
+
+ memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
+
+ return con;
+}
+
+int fdwaitqueue_append(server *srv, connection *con) {
+ if (srv->fdwaitqueue->size == 0) {
+ srv->fdwaitqueue->size = 16;
+ srv->fdwaitqueue->ptr = malloc(sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
+ force_assert(NULL != srv->fdwaitqueue->ptr);
+ } else if (srv->fdwaitqueue->used == srv->fdwaitqueue->size) {
+ srv->fdwaitqueue->size += 16;
+ srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
+ force_assert(NULL != srv->fdwaitqueue->ptr);
+ }
+
+ srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
+
+ return 0;
+}
+
+void fdwaitqueue_free(server *srv, connections *fdwaitqueue) {
+ UNUSED(srv);
+ free(fdwaitqueue->ptr);
+ free(fdwaitqueue);
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/joblist.h b/data/lighttpd/lighttpd-1.4.53/src/joblist.h
new file mode 100644
index 000000000..78c40e53b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/joblist.h
@@ -0,0 +1,14 @@
+#ifndef _JOB_LIST_H_
+#define _JOB_LIST_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+int joblist_append(server *srv, connection *con);
+void joblist_free(server *srv, connections *joblist);
+
+int fdwaitqueue_append(server *srv, connection *con);
+void fdwaitqueue_free(server *srv, connections *fdwaitqueue);
+connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/keyvalue.c b/data/lighttpd/lighttpd-1.4.53/src/keyvalue.c
new file mode 100644
index 000000000..c1b6b019c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/keyvalue.c
@@ -0,0 +1,460 @@
+#include "first.h"
+
+#include "keyvalue.h"
+#include "base.h"
+#include "burl.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_PCRE_H
+#include <pcre.h>
+#endif
+
+typedef struct pcre_keyvalue {
+#ifdef HAVE_PCRE_H
+ pcre *key;
+ pcre_extra *key_extra;
+#endif
+ buffer *value;
+} pcre_keyvalue;
+
+pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
+ pcre_keyvalue_buffer *kvb;
+
+ kvb = calloc(1, sizeof(*kvb));
+ force_assert(NULL != kvb);
+
+ return kvb;
+}
+
+int pcre_keyvalue_buffer_append(server *srv, pcre_keyvalue_buffer *kvb, buffer *key, buffer *value) {
+#ifdef HAVE_PCRE_H
+ size_t i;
+ const char *errptr;
+ int erroff;
+ pcre_keyvalue *kv;
+
+ if (!key) return -1;
+
+ if (kvb->size == 0) {
+ kvb->size = 4;
+ kvb->used = 0;
+
+ kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
+ force_assert(NULL != kvb->kv);
+
+ for(i = 0; i < kvb->size; i++) {
+ kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
+ force_assert(NULL != kvb->kv[i]);
+ }
+ } else if (kvb->used == kvb->size) {
+ kvb->size += 4;
+
+ kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
+ force_assert(NULL != kvb->kv);
+
+ for(i = kvb->used; i < kvb->size; i++) {
+ kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
+ force_assert(NULL != kvb->kv[i]);
+ }
+ }
+
+ kv = kvb->kv[kvb->used];
+ if (NULL == (kv->key = pcre_compile(key->ptr,
+ 0, &errptr, &erroff, NULL))) {
+
+ log_error_write(srv, __FILE__, __LINE__, "SS",
+ "rexexp compilation error at ", errptr);
+ return -1;
+ }
+
+ if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
+ errptr != NULL) {
+ return -1;
+ }
+
+ kv->value = buffer_init_buffer(value);
+
+ kvb->used++;
+
+#else
+ static int logged_message = 0;
+ if (logged_message) return 0;
+ logged_message = 1;
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "pcre support is missing, please install libpcre and the headers");
+ UNUSED(kvb);
+ UNUSED(key);
+ UNUSED(value);
+#endif
+
+ return 0;
+}
+
+void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb) {
+#ifdef HAVE_PCRE_H
+ size_t i;
+ pcre_keyvalue *kv;
+
+ for (i = 0; i < kvb->size; i++) {
+ kv = kvb->kv[i];
+ if (kv->key) pcre_free(kv->key);
+ if (kv->key_extra) pcre_free(kv->key_extra);
+ if (kv->value) buffer_free(kv->value);
+ free(kv);
+ }
+
+ if (kvb->kv) free(kvb->kv);
+#endif
+
+ free(kvb);
+}
+
+#ifdef HAVE_PCRE_H
+static void pcre_keyvalue_buffer_append_match(buffer *b, const char **list, int n, unsigned int num, int flags) {
+ if (num < (unsigned int)n) { /* n is always > 0 */
+ burl_append(b, list[num], strlen(list[num]), flags);
+ }
+}
+
+static void pcre_keyvalue_buffer_append_ctxmatch(buffer *b, pcre_keyvalue_ctx *ctx, unsigned int num, int flags) {
+ const struct cond_cache_t * const cache = ctx->cache;
+ if (!cache) return; /* no enclosing match context */
+ if ((int)num < cache->patterncount) {
+ const int off = cache->matches[(num <<= 1)]; /*(num *= 2)*/
+ const int len = cache->matches[num+1] - off;
+ burl_append(b, cache->comp_value->ptr + off, (size_t)len, flags);
+ }
+}
+
+static int pcre_keyvalue_buffer_subst_ext(buffer *b, const char *pattern, const char **list, int n, pcre_keyvalue_ctx *ctx) {
+ const unsigned char *p = (unsigned char *)pattern+2;/* +2 past ${} or %{} */
+ int flags = 0;
+ while (!light_isdigit(*p) && *p != '}' && *p != '\0') {
+ if (0) {
+ }
+ else if (p[0] == 'e' && p[1] == 's' && p[2] == 'c') {
+ p+=3;
+ if (p[0] == ':') {
+ flags |= BURL_ENCODE_ALL;
+ p+=1;
+ }
+ else if (0 == strncmp((const char *)p, "ape:", 4)) {
+ flags |= BURL_ENCODE_ALL;
+ p+=4;
+ }
+ else if (0 == strncmp((const char *)p, "nde:", 4)) {
+ flags |= BURL_ENCODE_NDE;
+ p+=4;
+ }
+ else if (0 == strncmp((const char *)p, "psnde:", 6)) {
+ flags |= BURL_ENCODE_PSNDE;
+ p+=6;
+ }
+ else { /* skip unrecognized esc... */
+ p = (const unsigned char *)strchr((const char *)p, ':');
+ if (NULL == p) return -1;
+ ++p;
+ }
+ }
+ else if (p[0] == 'n' && p[1] == 'o') {
+ p+=2;
+ if (0 == strncmp((const char *)p, "esc:", 4)) {
+ flags |= BURL_ENCODE_NONE;
+ p+=4;
+ }
+ else if (0 == strncmp((const char *)p, "escape:", 7)) {
+ flags |= BURL_ENCODE_NONE;
+ p+=7;
+ }
+ else { /* skip unrecognized no... */
+ p = (const unsigned char *)strchr((const char *)p, ':');
+ if (NULL == p) return -1;
+ ++p;
+ }
+ }
+ else if (p[0] == 't' && p[1] == 'o') {
+ p+=2;
+ if (0 == strncmp((const char *)p, "lower:", 6)) {
+ flags |= BURL_TOLOWER;
+ p+=6;
+ }
+ else if (0 == strncmp((const char *)p, "upper:", 6)) {
+ flags |= BURL_TOLOWER;
+ p+=6;
+ }
+ else { /* skip unrecognized to... */
+ p = (const unsigned char *)strchr((const char *)p, ':');
+ if (NULL == p) return -1;
+ ++p;
+ }
+ }
+ else if (p[0] == 'u' && p[1] == 'r' && p[2] == 'l' && p[3] == '.') {
+ p+=4;
+ if (0 == strncmp((const char *)p, "scheme}", 7)) {
+ burl_append(b, CONST_BUF_LEN(ctx->burl->scheme), flags);
+ p+=6;
+ }
+ else if (0 == strncmp((const char *)p, "authority}", 10)) {
+ burl_append(b, CONST_BUF_LEN(ctx->burl->authority), flags);
+ p+=9;
+ }
+ else if (0 == strncmp((const char *)p, "port}", 5)) {
+ buffer_append_int(b, (int)ctx->burl->port);
+ p+=4;
+ }
+ else if (0 == strncmp((const char *)p, "path}", 5)) {
+ burl_append(b, CONST_BUF_LEN(ctx->burl->path), flags);
+ p+=4;
+ }
+ else if (0 == strncmp((const char *)p, "query}", 6)) {
+ burl_append(b, CONST_BUF_LEN(ctx->burl->query), flags);
+ p+=5;
+ }
+ else { /* skip unrecognized url.* */
+ p = (const unsigned char *)strchr((const char *)p, '}');
+ if (NULL == p) return -1;
+ }
+ break;
+ }
+ else if (p[0] == 'q' && p[1] == 's' && p[2] == 'a' && p[3] == '}') {
+ const buffer *qs = ctx->burl->query;
+ if (!buffer_is_empty(qs)) {
+ if (NULL != strchr(b->ptr, '?')) {
+ if (!buffer_string_is_empty(qs))
+ buffer_append_string_len(b, CONST_STR_LEN("&"));
+ }
+ else {
+ buffer_append_string_len(b, CONST_STR_LEN("?"));
+ }
+ burl_append(b, CONST_BUF_LEN(qs), flags);
+ }
+ p+=3;
+ break;
+ }
+ else if (p[0] == 'e' && p[1] == 'n' && p[2] == 'c'
+ && 0 == strncmp((const char *)p+3, "b64u:", 5)) {
+ flags |= BURL_ENCODE_B64U;
+ p+=8;
+ }
+ else if (p[0] == 'd' && p[1] == 'e' && p[2] == 'c'
+ && 0 == strncmp((const char *)p+3, "b64u:", 5)) {
+ flags |= BURL_DECODE_B64U;
+ p+=8;
+ }
+ else ++p; /* skip unrecognized char */
+ }
+ if (*p == '\0') return -1;
+ if (*p != '}') { /* light_isdigit(*p) */
+ unsigned int num = *p - '0';
+ ++p;
+ if (light_isdigit(*p)) num = num * 10 + (*p++ - '0');
+ if (*p != '}') {
+ p = (const unsigned char *)strchr((const char *)p, '}');
+ if (NULL == p) return -1;
+ }
+ if (0 == flags) flags = BURL_ENCODE_PSNDE; /* default */
+ pattern[0] == '$' /*(else '%')*/
+ ? pcre_keyvalue_buffer_append_match(b, list, n, num, flags)
+ : pcre_keyvalue_buffer_append_ctxmatch(b, ctx, num, flags);
+ }
+ return (int)(p + 1 - (unsigned char *)pattern - 2);
+}
+
+static void pcre_keyvalue_buffer_subst(buffer *b, const buffer *patternb, const char **list, int n, pcre_keyvalue_ctx *ctx) {
+ const char *pattern = patternb->ptr;
+ const size_t pattern_len = buffer_string_length(patternb);
+ size_t start = 0;
+
+ /* search for $... or %... pattern substitutions */
+
+ buffer_clear(b);
+
+ for (size_t k = 0; k + 1 < pattern_len; ++k) {
+ if (pattern[k] == '$' || pattern[k] == '%') {
+
+ buffer_append_string_len(b, pattern + start, k - start);
+
+ if (pattern[k + 1] == '{') {
+ int num = pcre_keyvalue_buffer_subst_ext(b, pattern+k, list, n, ctx);
+ if (num < 0) return; /* error; truncate result */
+ k += (size_t)num;
+ } else if (light_isdigit(((unsigned char *)pattern)[k + 1])) {
+ unsigned int num = (unsigned int)pattern[k + 1] - '0';
+ pattern[k] == '$' /*(else '%')*/
+ ? pcre_keyvalue_buffer_append_match(b, list, n, num, 0)
+ : pcre_keyvalue_buffer_append_ctxmatch(b, ctx, num, 0);
+ } else {
+ /* enable escape: "%%" => "%", "%a" => "%a", "$$" => "$" */
+ buffer_append_string_len(b, pattern+k, pattern[k] == pattern[k+1] ? 1 : 2);
+ }
+
+ k++;
+ start = k + 1;
+ }
+ }
+
+ buffer_append_string_len(b, pattern + start, pattern_len - start);
+}
+
+handler_t pcre_keyvalue_buffer_process(pcre_keyvalue_buffer *kvb, pcre_keyvalue_ctx *ctx, buffer *input, buffer *result) {
+ for (int i = 0, used = (int)kvb->used; i < used; ++i) {
+ pcre_keyvalue * const kv = kvb->kv[i];
+ #define N 20
+ int ovec[N * 3];
+ #undef N
+ int n = pcre_exec(kv->key, kv->key_extra, CONST_BUF_LEN(input),
+ 0, 0, ovec, sizeof(ovec)/sizeof(int));
+ if (n < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ return HANDLER_ERROR;
+ }
+ }
+ else if (buffer_string_is_empty(kv->value)) {
+ /* short-circuit if blank replacement pattern
+ * (do not attempt to match against remaining kvb rules) */
+ ctx->m = i;
+ return HANDLER_GO_ON;
+ }
+ else { /* it matched */
+ const char **list;
+ ctx->m = i;
+ pcre_get_substring_list(input->ptr, ovec, n, &list);
+ pcre_keyvalue_buffer_subst(result, kv->value, list, n, ctx);
+ pcre_free(list);
+ return HANDLER_FINISHED;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+#else
+handler_t pcre_keyvalue_buffer_process(pcre_keyvalue_buffer *kvb, pcre_keyvalue_ctx *ctx, buffer *input, buffer *result) {
+ UNUSED(kvb);
+ UNUSED(ctx);
+ UNUSED(input);
+ UNUSED(result);
+ return HANDLER_GO_ON;
+}
+#endif
+
+
+/* modified from burl_normalize_basic() to handle %% extra encoding layer */
+
+/* c (char) and n (nibble) MUST be unsigned integer types */
+#define li_cton(c,n) \
+ (((n) = (c) - '0') <= 9 || (((n) = ((c)&0xdf) - 'A') <= 5 ? ((n) += 10) : 0))
+
+static void pcre_keyvalue_burl_percent_toupper (buffer *b)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ const int used = (int)buffer_string_length(b);
+ unsigned int n1, n2;
+ for (int i = 0; i < used; ++i) {
+ if (s[i]=='%' && li_cton(s[i+1],n1) && li_cton(s[i+2],n2)) {
+ if (s[i+1] >= 'a') b->ptr[i+1] &= 0xdf; /* uppercase hex */
+ if (s[i+2] >= 'a') b->ptr[i+2] &= 0xdf; /* uppercase hex */
+ i+=2;
+ }
+ }
+}
+
+static void pcre_keyvalue_burl_percent_percent_toupper (buffer *b)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ const int used = (int)buffer_string_length(b);
+ unsigned int n1, n2;
+ for (int i = 0; i < used; ++i) {
+ if (s[i] == '%' && s[i+1]=='%'
+ && li_cton(s[i+2],n1) && li_cton(s[i+3],n2)) {
+ if (s[i+2] >= 'a') b->ptr[i+2] &= 0xdf; /* uppercase hex */
+ if (s[i+3] >= 'a') b->ptr[i+3] &= 0xdf; /* uppercase hex */
+ i+=3;
+ }
+ }
+}
+
+static const char hex_chars_uc[] = "0123456789ABCDEF";
+
+static void pcre_keyvalue_burl_percent_high_UTF8 (buffer *b, buffer *t)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ unsigned char *p;
+ const int used = (int)buffer_string_length(b);
+ unsigned int count = 0, j = 0;
+ for (int i = 0; i < used; ++i) {
+ if (s[i] > 0x7F) ++count;
+ }
+ if (0 == count) return;
+
+ p = (unsigned char *)buffer_string_prepare_copy(t, used+(count*2));
+ for (int i = 0; i < used; ++i, ++j) {
+ if (s[i] <= 0x7F)
+ p[j] = s[i];
+ else {
+ p[j] = '%';
+ p[++j] = hex_chars_uc[(s[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[s[i] & 0xF];
+ }
+ }
+ buffer_commit(t, j);
+ buffer_copy_buffer(b, t);
+}
+
+static void pcre_keyvalue_burl_percent_percent_high_UTF8 (buffer *b, buffer *t)
+{
+ const unsigned char * const s = (unsigned char *)b->ptr;
+ unsigned char *p;
+ const int used = (int)buffer_string_length(b);
+ unsigned int count = 0, j = 0;
+ for (int i = 0; i < used; ++i) {
+ if (s[i] > 0x7F) ++count;
+ }
+ if (0 == count) return;
+
+ p = (unsigned char *)buffer_string_prepare_copy(t, used+(count*3));
+ for (int i = 0; i < used; ++i, ++j) {
+ if (s[i] <= 0x7F)
+ p[j] = s[i];
+ else {
+ p[j] = '%';
+ p[++j] = '%';
+ p[++j] = hex_chars_uc[(s[i] >> 4) & 0xF];
+ p[++j] = hex_chars_uc[s[i] & 0xF];
+ }
+ }
+ buffer_commit(t, j);
+ buffer_copy_buffer(b, t);
+}
+
+/* Basic normalization of regex and regex replacement to mirror some of
+ * the normalizations performed on request URI (for better compatibility).
+ * Note: not currently attempting to replace unnecessary percent-encoding
+ * (would need to know if regex was intended to match url-path or
+ * query-string or both, and then would have to regex-escape if those
+ * chars where special regex chars such as . * + ? ( ) [ ] | and more)
+ * Not attempting to percent-encode chars which should be encoded, again
+ * since regex might target url-path, query-string, or both, and we would
+ * have to avoid percent-encoding special regex chars.
+ * Also not attempting to detect unnecessarily regex-escape in, e.g. %\x\x
+ * Preserve improper %-encoded sequences which are not %XX (using hex chars)
+ * Intentionally not performing path simplification (e.g. ./ ../)
+ * If regex-specific normalizations begin to be made to k here,
+ * must revisit callers, e.g. one configfile.c use on non-regex string.
+ * "%%" (percent_percent) is used in regex replacement strings since
+ * otherwise "%n" is used to indicate regex backreference where n is number.
+ */
+
+void pcre_keyvalue_burl_normalize_key (buffer *k, buffer *t)
+{
+ pcre_keyvalue_burl_percent_toupper(k);
+ pcre_keyvalue_burl_percent_high_UTF8(k, t);
+}
+
+void pcre_keyvalue_burl_normalize_value (buffer *v, buffer *t)
+{
+ pcre_keyvalue_burl_percent_percent_toupper(v);
+ pcre_keyvalue_burl_percent_percent_high_UTF8(v, t);
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/keyvalue.h b/data/lighttpd/lighttpd-1.4.53/src/keyvalue.h
new file mode 100644
index 000000000..0a7854845
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/keyvalue.h
@@ -0,0 +1,31 @@
+#ifndef _KEY_VALUE_H_
+#define _KEY_VALUE_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+struct burl_parts_t; /* declaration */
+struct cond_cache_t; /* declaration */
+struct pcre_keyvalue; /* declaration */
+
+typedef struct pcre_keyvalue_ctx {
+ struct cond_cache_t *cache;
+ struct burl_parts_t *burl;
+ int m;
+} pcre_keyvalue_ctx;
+
+typedef struct {
+ struct pcre_keyvalue **kv;
+ size_t used;
+ size_t size;
+} pcre_keyvalue_buffer;
+
+pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void);
+int pcre_keyvalue_buffer_append(struct server *srv, pcre_keyvalue_buffer *kvb, buffer *key, buffer *value);
+void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb);
+handler_t pcre_keyvalue_buffer_process(pcre_keyvalue_buffer *kvb, pcre_keyvalue_ctx *ctx, buffer *input, buffer *result);
+void pcre_keyvalue_burl_normalize_key(buffer *k, buffer *t);
+void pcre_keyvalue_burl_normalize_value(buffer *v, buffer *t);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/lemon.c b/data/lighttpd/lighttpd-1.4.53/src/lemon.c
new file mode 100644
index 000000000..ad86cee2c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/lemon.c
@@ -0,0 +1,4436 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifdef __COVERITY__
+#define _Float128 long double
+#define _Float64x long double
+#define _Float64 double
+#define _Float32x double
+#define _Float32 float
+#endif
+
+/*
+** This file contains all sources (including headers) to the LEMON
+** LALR(1) parser generator. The sources have been combined into a
+** single file to make it easy to include LEMON in the source tree
+** and Makefile of another program.
+**
+** The author of this program disclaims copyright.
+*/
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h> /* access() */
+
+#define UNUSED(x) ( (void)(x) )
+
+#ifndef __WIN32__
+# if defined(_WIN32) || defined(WIN32)
+# define __WIN32__
+# endif
+#endif
+
+#if __GNUC__ > 2
+#define NORETURN __attribute__ ((__noreturn__))
+#else
+#define NORETURN
+#endif
+
+/* #define PRIVATE static */
+#define PRIVATE static
+
+#ifdef TEST
+#define MAXRHS 5 /* Set low to exercise exception code */
+#else
+#define MAXRHS 1000
+#endif
+
+void *msort(void *list, void **next, int(*cmp)(void *, void *));
+
+static void memory_error() NORETURN;
+
+/******** From the file "action.h" *************************************/
+struct action *Action_new();
+struct action *Action_sort();
+void Action_add();
+
+/********* From the file "assert.h" ************************************/
+void myassert() NORETURN;
+#ifndef NDEBUG
+# define assert(X) if(!(X))myassert(__FILE__,__LINE__)
+#else
+# define assert(X)
+#endif
+
+/********** From the file "build.h" ************************************/
+void FindRulePrecedences();
+void FindFirstSets();
+void FindStates();
+void FindLinks();
+void FindFollowSets();
+void FindActions();
+
+/********* From the file "configlist.h" *********************************/
+void Configlist_init(/* void */);
+struct config *Configlist_add(/* struct rule *, int */);
+struct config *Configlist_addbasis(/* struct rule *, int */);
+void Configlist_closure(/* void */);
+void Configlist_sort(/* void */);
+void Configlist_sortbasis(/* void */);
+struct config *Configlist_return(/* void */);
+struct config *Configlist_basis(/* void */);
+void Configlist_eat(/* struct config * */);
+void Configlist_reset(/* void */);
+
+/********* From the file "error.h" ***************************************/
+void ErrorMsg(const char *, int,const char *, ...);
+
+/****** From the file "option.h" ******************************************/
+struct s_options {
+ enum { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR,
+ OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type;
+ char *label;
+ void *arg;
+ const char *message;
+};
+int OptInit(/* char**,struct s_options*,FILE* */);
+int OptNArgs(/* void */);
+char *OptArg(/* int */);
+void OptErr(/* int */);
+void OptPrint(/* void */);
+
+/******** From the file "parse.h" *****************************************/
+void Parse(/* struct lemon *lemp */);
+
+/********* From the file "plink.h" ***************************************/
+struct plink *Plink_new(/* void */);
+void Plink_add(/* struct plink **, struct config * */);
+void Plink_copy(/* struct plink **, struct plink * */);
+void Plink_delete(/* struct plink * */);
+
+/********** From the file "report.h" *************************************/
+void Reprint(/* struct lemon * */);
+void ReportOutput(/* struct lemon * */);
+void ReportTable(/* struct lemon * */);
+void ReportHeader(/* struct lemon * */);
+void CompressTables(/* struct lemon * */);
+
+/********** From the file "set.h" ****************************************/
+void SetSize(/* int N */); /* All sets will be of size N */
+char *SetNew(/* void */); /* A new set for element 0..N */
+void SetFree(/* char* */); /* Deallocate a set */
+
+int SetAdd(/* char*,int */); /* Add element to a set */
+int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */
+
+#define SetFind(X,Y) (X[Y]) /* True if Y is in set X */
+
+/********** From the file "struct.h" *************************************/
+/*
+** Principal data structures for the LEMON parser generator.
+*/
+
+typedef enum {Bo_FALSE=0, Bo_TRUE} Boolean;
+
+/* Symbols (terminals and nonterminals) of the grammar are stored
+** in the following: */
+struct symbol {
+ char *name; /* Name of the symbol */
+ int index; /* Index number for this symbol */
+ enum {
+ TERMINAL,
+ NONTERMINAL
+ } type; /* Symbols are all either TERMINALS or NTs */
+ struct rule *rule; /* Linked list of rules of this (if an NT) */
+ struct symbol *fallback; /* fallback token in case this token doesn't parse */
+ int prec; /* Precedence if defined (-1 otherwise) */
+ enum e_assoc {
+ LEFT,
+ RIGHT,
+ NONE,
+ UNK
+ } assoc; /* Associativity if predecence is defined */
+ char *firstset; /* First-set for all rules of this symbol */
+ Boolean lambda; /* True if NT and can generate an empty string */
+ char *destructor; /* Code which executes whenever this symbol is
+ ** popped from the stack during error processing */
+ int destructorln; /* Line number of destructor code */
+ char *datatype; /* The data type of information held by this
+ ** object. Only used if type==NONTERMINAL */
+ int dtnum; /* The data type number. In the parser, the value
+ ** stack is a union. The .yy%d element of this
+ ** union is the correct data type for this object */
+};
+
+/* Each production rule in the grammar is stored in the following
+** structure. */
+struct rule {
+ struct symbol *lhs; /* Left-hand side of the rule */
+ char *lhsalias; /* Alias for the LHS (NULL if none) */
+ int ruleline; /* Line number for the rule */
+ int nrhs; /* Number of RHS symbols */
+ struct symbol **rhs; /* The RHS symbols */
+ char **rhsalias; /* An alias for each RHS symbol (NULL if none) */
+ int line; /* Line number at which code begins */
+ char *code; /* The code executed when this rule is reduced */
+ struct symbol *precsym; /* Precedence symbol for this rule */
+ int index; /* An index number for this rule */
+ Boolean canReduce; /* True if this rule is ever reduced */
+ struct rule *nextlhs; /* Next rule with the same LHS */
+ struct rule *next; /* Next rule in the global list */
+};
+
+/* A configuration is a production rule of the grammar together with
+** a mark (dot) showing how much of that rule has been processed so far.
+** Configurations also contain a follow-set which is a list of terminal
+** symbols which are allowed to immediately follow the end of the rule.
+** Every configuration is recorded as an instance of the following: */
+struct config {
+ struct rule *rp; /* The rule upon which the configuration is based */
+ int dot; /* The parse point */
+ char *fws; /* Follow-set for this configuration only */
+ struct plink *fplp; /* Follow-set forward propagation links */
+ struct plink *bplp; /* Follow-set backwards propagation links */
+ struct state *stp; /* Pointer to state which contains this */
+ enum {
+ COMPLETE, /* The status is used during followset and */
+ INCOMPLETE /* shift computations */
+ } status;
+ struct config *next; /* Next configuration in the state */
+ struct config *bp; /* The next basis configuration */
+};
+
+/* Every shift or reduce operation is stored as one of the following */
+struct action {
+ struct symbol *sp; /* The look-ahead symbol */
+ enum e_action {
+ SHIFT,
+ ACCEPT,
+ REDUCE,
+ ERROR,
+ CONFLICT, /* Was a reduce, but part of a conflict */
+ SH_RESOLVED, /* Was a shift. Precedence resolved conflict */
+ RD_RESOLVED, /* Was reduce. Precedence resolved conflict */
+ NOT_USED /* Deleted by compression */
+ } type;
+ union {
+ struct state *stp; /* The new state, if a shift */
+ struct rule *rp; /* The rule, if a reduce */
+ } x;
+ struct action *next; /* Next action for this state */
+ struct action *collide; /* Next action with the same hash */
+};
+
+/* Each state of the generated parser's finite state machine
+** is encoded as an instance of the following structure. */
+struct state {
+ struct config *bp; /* The basis configurations for this state */
+ struct config *cfp; /* All configurations in this set */
+ int index; /* Sequencial number for this state */
+ struct action *ap; /* Array of actions for this state */
+ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */
+ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */
+ int iDflt; /* Default action */
+};
+#define NO_OFFSET (-2147483647)
+
+/* A followset propagation link indicates that the contents of one
+** configuration followset should be propagated to another whenever
+** the first changes. */
+struct plink {
+ struct config *cfp; /* The configuration to which linked */
+ struct plink *next; /* The next propagate link */
+};
+
+/* The state vector for the entire parser generator is recorded as
+** follows. (LEMON uses no global variables and makes little use of
+** static variables. Fields in the following structure can be thought
+** of as begin global variables in the program.) */
+struct lemon {
+ struct state **sorted; /* Table of states sorted by state number */
+ struct rule *rule; /* List of all rules */
+ int nstate; /* Number of states */
+ int nrule; /* Number of rules */
+ int nsymbol; /* Number of terminal and nonterminal symbols */
+ int nterminal; /* Number of terminal symbols */
+ struct symbol **symbols; /* Sorted array of pointers to symbols */
+ int errorcnt; /* Number of errors */
+ struct symbol *errsym; /* The error symbol */
+ char *name; /* Name of the generated parser */
+ char *arg; /* Declaration of the 3th argument to parser */
+ char *tokentype; /* Type of terminal symbols in the parser stack */
+ char *vartype; /* The default type of non-terminal symbols */
+ char *start; /* Name of the start symbol for the grammar */
+ char *stacksize; /* Size of the parser stack */
+ char *include; /* Code to put at the start of the C file */
+ int includeln; /* Line number for start of include code */
+ char *error; /* Code to execute when an error is seen */
+ int errorln; /* Line number for start of error code */
+ char *overflow; /* Code to execute on a stack overflow */
+ int overflowln; /* Line number for start of overflow code */
+ char *failure; /* Code to execute on parser failure */
+ int failureln; /* Line number for start of failure code */
+ char *accept; /* Code to execute when the parser excepts */
+ int acceptln; /* Line number for the start of accept code */
+ char *extracode; /* Code appended to the generated file */
+ int extracodeln; /* Line number for the start of the extra code */
+ char *tokendest; /* Code to execute to destroy token data */
+ int tokendestln; /* Line number for token destroyer code */
+ char *vardest; /* Code for the default non-terminal destructor */
+ int vardestln; /* Line number for default non-term destructor code*/
+ char *filename; /* Name of the input file */
+ char *tmplname; /* Name of the template file */
+ char *outname; /* Name of the current output file */
+ char *tokenprefix; /* A prefix added to token names in the .h file */
+ int nconflict; /* Number of parsing conflicts */
+ int tablesize; /* Size of the parse tables */
+ int basisflag; /* Print only basis configurations */
+ int has_fallback; /* True if any %fallback is seen in the grammer */
+ char *argv0; /* Name of the program */
+};
+
+#define MemoryCheck(X) if((X)==0){ \
+ memory_error(); \
+}
+
+/**************** From the file "table.h" *********************************/
+/*
+** All code in this file has been automatically generated
+** from a specification in the file
+** "table.q"
+** by the associative array code building program "aagen".
+** Do not edit this file! Instead, edit the specification
+** file, then rerun aagen.
+*/
+/*
+** Code for processing tables in the LEMON parser generator.
+*/
+
+/* Routines for handling a strings */
+
+char *Strsafe();
+
+void Strsafe_init(/* void */);
+int Strsafe_insert(/* char * */);
+char *Strsafe_find(/* char * */);
+
+/* Routines for handling symbols of the grammar */
+
+struct symbol *Symbol_new();
+int Symbolcmpp(/* struct symbol **, struct symbol ** */);
+void Symbol_init(/* void */);
+int Symbol_insert(/* struct symbol *, char * */);
+struct symbol *Symbol_find(/* char * */);
+struct symbol *Symbol_Nth(/* int */);
+int Symbol_count(/* */);
+int State_count(void);
+struct symbol **Symbol_arrayof(/* */);
+
+/* Routines to manage the state table */
+
+int Configcmp(/* struct config *, struct config * */);
+struct state *State_new();
+void State_init(/* void */);
+int State_insert(/* struct state *, struct config * */);
+struct state *State_find(/* struct config * */);
+struct state **State_arrayof(/* */);
+
+/* Routines used for efficiency in Configlist_add */
+
+void Configtable_init(/* void */);
+int Configtable_insert(/* struct config * */);
+struct config *Configtable_find(/* struct config * */);
+void Configtable_clear(/* int(*)(struct config *) */);
+/****************** From the file "action.c" *******************************/
+/*
+** Routines processing parser actions in the LEMON parser generator.
+*/
+
+/* Allocate a new parser action */
+struct action *Action_new(){
+ static struct action *freelist = NULL;
+ struct action *new;
+
+ if( freelist==NULL ){
+ int i;
+ int amt = 100;
+ freelist = (struct action *)malloc( sizeof(struct action)*amt );
+ if( freelist==0 ){
+ fprintf(stderr,"Unable to allocate memory for a new parser action.");
+ exit(1);
+ }
+ for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
+ freelist[amt-1].next = 0;
+ }
+ new = freelist;
+ freelist = freelist->next;
+ return new;
+}
+
+/* Compare two actions */
+static int actioncmp(ap1,ap2)
+struct action *ap1;
+struct action *ap2;
+{
+ int rc;
+ rc = ap1->sp->index - ap2->sp->index;
+ if( rc==0 ) rc = (int)ap1->type - (int)ap2->type;
+ if( rc==0 ){
+ assert( ap1->type==REDUCE || ap1->type==RD_RESOLVED || ap1->type==CONFLICT);
+ assert( ap2->type==REDUCE || ap2->type==RD_RESOLVED || ap2->type==CONFLICT);
+ rc = ap1->x.rp->index - ap2->x.rp->index;
+ }
+ return rc;
+}
+
+/* Sort parser actions */
+struct action *Action_sort(ap)
+struct action *ap;
+{
+ ap = (struct action *)msort(ap,(void **)&ap->next,actioncmp);
+ return ap;
+}
+
+void Action_add(app,type,sp,arg)
+struct action **app;
+enum e_action type;
+struct symbol *sp;
+void *arg;
+{
+ struct action *new;
+ new = Action_new();
+ new->next = *app;
+ *app = new;
+ new->type = type;
+ new->sp = sp;
+ if( type==SHIFT ){
+ new->x.stp = (struct state *)arg;
+ }else{
+ new->x.rp = (struct rule *)arg;
+ }
+}
+/********************** New code to implement the "acttab" module ***********/
+/*
+** This module implements routines use to construct the yy_action[] table.
+*/
+
+/*
+** The state of the yy_action table under construction is an instance of
+** the following structure
+*/
+typedef struct acttab acttab;
+struct acttab {
+ int nAction; /* Number of used slots in aAction[] */
+ int nActionAlloc; /* Slots allocated for aAction[] */
+ struct {
+ int lookahead; /* Value of the lookahead token */
+ int action; /* Action to take on the given lookahead */
+ } *aAction, /* The yy_action[] table under construction */
+ *aLookahead; /* A single new transaction set */
+ int mnLookahead; /* Minimum aLookahead[].lookahead */
+ int mnAction; /* Action associated with mnLookahead */
+ int mxLookahead; /* Maximum aLookahead[].lookahead */
+ int nLookahead; /* Used slots in aLookahead[] */
+ int nLookaheadAlloc; /* Slots allocated in aLookahead[] */
+};
+
+/* Return the number of entries in the yy_action table */
+#define acttab_size(X) ((X)->nAction)
+
+/* The value for the N-th entry in yy_action */
+#define acttab_yyaction(X,N) ((X)->aAction[N].action)
+
+/* The value for the N-th entry in yy_lookahead */
+#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead)
+
+/* Free all memory associated with the given acttab */
+/*
+PRIVATE void acttab_free(acttab *p){
+ free( p->aAction );
+ free( p->aLookahead );
+ free( p );
+}
+*/
+
+/* Allocate a new acttab structure */
+PRIVATE acttab *acttab_alloc(void){
+ acttab *p = malloc( sizeof(*p) );
+ if( p==0 ){
+ fprintf(stderr,"Unable to allocate memory for a new acttab.");
+ exit(1);
+ }
+ memset(p, 0, sizeof(*p));
+ return p;
+}
+
+/* Add a new action to the current transaction set
+*/
+PRIVATE void acttab_action(acttab *p, int lookahead, int action){
+ if( p->nLookahead>=p->nLookaheadAlloc ){
+ p->nLookaheadAlloc += 25;
+ p->aLookahead = realloc( p->aLookahead,
+ sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
+ if( p->aLookahead==0 ){
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ }
+ if( p->nLookahead==0 ){
+ p->mxLookahead = lookahead;
+ p->mnLookahead = lookahead;
+ p->mnAction = action;
+ }else{
+ if( p->mxLookahead<lookahead ) p->mxLookahead = lookahead;
+ if( p->mnLookahead>lookahead ){
+ p->mnLookahead = lookahead;
+ p->mnAction = action;
+ }
+ }
+ p->aLookahead[p->nLookahead].lookahead = lookahead;
+ p->aLookahead[p->nLookahead].action = action;
+ p->nLookahead++;
+}
+
+/*
+** Add the transaction set built up with prior calls to acttab_action()
+** into the current action table. Then reset the transaction set back
+** to an empty set in preparation for a new round of acttab_action() calls.
+**
+** Return the offset into the action table of the new transaction.
+*/
+PRIVATE int acttab_insert(acttab *p){
+ int i, j, k, n;
+ assert( p->nLookahead>0 );
+
+ /* Make sure we have enough space to hold the expanded action table
+ ** in the worst case. The worst case occurs if the transaction set
+ ** must be appended to the current action table
+ */
+ n = p->mxLookahead + 1;
+ if( p->nAction + n >= p->nActionAlloc ){
+ int oldAlloc = p->nActionAlloc;
+ p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
+ p->aAction = realloc( p->aAction,
+ sizeof(p->aAction[0])*p->nActionAlloc);
+ if( p->aAction==0 ){
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ for(i=oldAlloc; i<p->nActionAlloc; i++){
+ p->aAction[i].lookahead = -1;
+ p->aAction[i].action = -1;
+ }
+ }
+
+ /* Scan the existing action table looking for an offset where we can
+ ** insert the current transaction set. Fall out of the loop when that
+ ** offset is found. In the worst case, we fall out of the loop when
+ ** i reaches p->nAction, which means we append the new transaction set.
+ **
+ ** i is the index in p->aAction[] where p->mnLookahead is inserted.
+ */
+ for(i=0; i<p->nAction+p->mnLookahead; i++){
+ if( p->aAction[i].lookahead<0 ){
+ for(j=0; j<p->nLookahead; j++){
+ k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+ if( k<0 ) break;
+ if( p->aAction[k].lookahead>=0 ) break;
+ }
+ if( j<p->nLookahead ) continue;
+ for(j=0; j<p->nAction; j++){
+ if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break;
+ }
+ if( j==p->nAction ){
+ break; /* Fits in empty slots */
+ }
+ }else if( p->aAction[i].lookahead==p->mnLookahead ){
+ if( p->aAction[i].action!=p->mnAction ) continue;
+ for(j=0; j<p->nLookahead; j++){
+ k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+ if( k<0 || k>=p->nAction ) break;
+ if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break;
+ if( p->aLookahead[j].action!=p->aAction[k].action ) break;
+ }
+ if( j<p->nLookahead ) continue;
+ n = 0;
+ for(j=0; j<p->nAction; j++){
+ if( p->aAction[j].lookahead<0 ) continue;
+ if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++;
+ }
+ if( n==p->nLookahead ){
+ break; /* Same as a prior transaction set */
+ }
+ }
+ }
+ /* Insert transaction set at index i. */
+ for(j=0; j<p->nLookahead; j++){
+ k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+ p->aAction[k] = p->aLookahead[j];
+ if( k>=p->nAction ) p->nAction = k+1;
+ }
+ p->nLookahead = 0;
+
+ /* Return the offset that is added to the lookahead in order to get the
+ ** index into yy_action of the action */
+ return i - p->mnLookahead;
+}
+
+/********************** From the file "assert.c" ****************************/
+/*
+** A more efficient way of handling assertions.
+*/
+void myassert(file,line)
+char *file;
+int line;
+{
+ fprintf(stderr,"Assertion failed on line %d of file \"%s\"\n",line,file);
+ exit(1);
+}
+/********************** From the file "build.c" *****************************/
+/*
+** Routines to construction the finite state machine for the LEMON
+** parser generator.
+*/
+
+/* Find a precedence symbol of every rule in the grammar.
+**
+** Those rules which have a precedence symbol coded in the input
+** grammar using the "[symbol]" construct will already have the
+** rp->precsym field filled. Other rules take as their precedence
+** symbol the first RHS symbol with a defined precedence. If there
+** are not RHS symbols with a defined precedence, the precedence
+** symbol field is left blank.
+*/
+void FindRulePrecedences(xp)
+struct lemon *xp;
+{
+ struct rule *rp;
+ for(rp=xp->rule; rp; rp=rp->next){
+ if( rp->precsym==0 ){
+ int i;
+ for(i=0; i<rp->nrhs; i++){
+ if( rp->rhs[i]->prec>=0 ){
+ rp->precsym = rp->rhs[i];
+ break;
+ }
+ }
+ }
+ }
+ return;
+}
+
+/* Find all nonterminals which will generate the empty string.
+** Then go back and compute the first sets of every nonterminal.
+** The first set is the set of all terminal symbols which can begin
+** a string generated by that nonterminal.
+*/
+void FindFirstSets(lemp)
+struct lemon *lemp;
+{
+ int i;
+ struct rule *rp;
+ int progress;
+
+ for(i=0; i<lemp->nsymbol; i++){
+ lemp->symbols[i]->lambda = Bo_FALSE;
+ }
+ for(i=lemp->nterminal; i<lemp->nsymbol; i++){
+ lemp->symbols[i]->firstset = SetNew();
+ }
+
+ /* First compute all lambdas */
+ do{
+ progress = 0;
+ for(rp=lemp->rule; rp; rp=rp->next){
+ if( rp->lhs->lambda ) continue;
+ for(i=0; i<rp->nrhs; i++){
+ if( rp->rhs[i]->lambda==Bo_FALSE ) break;
+ }
+ if( i==rp->nrhs ){
+ rp->lhs->lambda = Bo_TRUE;
+ progress = 1;
+ }
+ }
+ }while( progress );
+
+ /* Now compute all first sets */
+ do{
+ struct symbol *s1, *s2;
+ progress = 0;
+ for(rp=lemp->rule; rp; rp=rp->next){
+ s1 = rp->lhs;
+ for(i=0; i<rp->nrhs; i++){
+ s2 = rp->rhs[i];
+ if( s2->type==TERMINAL ){
+ progress += SetAdd(s1->firstset,s2->index);
+ break;
+ }else if( s1==s2 ){
+ if( s1->lambda==Bo_FALSE ) break;
+ }else{
+ progress += SetUnion(s1->firstset,s2->firstset);
+ if( s2->lambda==Bo_FALSE ) break;
+ }
+ }
+ }
+ }while( progress );
+ return;
+}
+
+/* Compute all LR(0) states for the grammar. Links
+** are added to between some states so that the LR(1) follow sets
+** can be computed later.
+*/
+PRIVATE struct state *getstate(/* struct lemon * */); /* forward reference */
+void FindStates(lemp)
+struct lemon *lemp;
+{
+ struct symbol *sp;
+ struct rule *rp;
+
+ Configlist_init();
+
+ /* Find the start symbol */
+ if( lemp->start ){
+ sp = Symbol_find(lemp->start);
+ if( sp==0 ){
+ ErrorMsg(lemp->filename,0,
+"The specified start symbol \"%s\" is not \
+in a nonterminal of the grammar. \"%s\" will be used as the start \
+symbol instead.",lemp->start,lemp->rule->lhs->name);
+ lemp->errorcnt++;
+ sp = lemp->rule->lhs;
+ }
+ }else{
+ sp = lemp->rule->lhs;
+ }
+
+ /* Make sure the start symbol doesn't occur on the right-hand side of
+ ** any rule. Report an error if it does. (YACC would generate a new
+ ** start symbol in this case.) */
+ for(rp=lemp->rule; rp; rp=rp->next){
+ int i;
+ for(i=0; i<rp->nrhs; i++){
+ if( rp->rhs[i]==sp ){
+ ErrorMsg(lemp->filename,0,
+"The start symbol \"%s\" occurs on the \
+right-hand side of a rule. This will result in a parser which \
+does not work properly.",sp->name);
+ lemp->errorcnt++;
+ }
+ }
+ }
+
+ /* The basis configuration set for the first state
+ ** is all rules which have the start symbol as their
+ ** left-hand side */
+ for(rp=sp->rule; rp; rp=rp->nextlhs){
+ struct config *newcfp;
+ newcfp = Configlist_addbasis(rp,0);
+ SetAdd(newcfp->fws,0);
+ }
+
+ /* Compute the first state. All other states will be
+ ** computed automatically during the computation of the first one.
+ ** The returned pointer to the first state is not used. */
+ (void)getstate(lemp);
+ return;
+}
+
+/* Return a pointer to a state which is described by the configuration
+** list which has been built from calls to Configlist_add.
+*/
+PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */
+PRIVATE struct state *getstate(lemp)
+struct lemon *lemp;
+{
+ struct config *cfp, *bp;
+ struct state *stp;
+
+ /* Extract the sorted basis of the new state. The basis was constructed
+ ** by prior calls to "Configlist_addbasis()". */
+ Configlist_sortbasis();
+ bp = Configlist_basis();
+
+ /* Get a state with the same basis */
+ stp = State_find(bp);
+ if( stp ){
+ /* A state with the same basis already exists! Copy all the follow-set
+ ** propagation links from the state under construction into the
+ ** preexisting state, then return a pointer to the preexisting state */
+ struct config *x, *y;
+ for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){
+ Plink_copy(&y->bplp,x->bplp);
+ Plink_delete(x->fplp);
+ x->fplp = x->bplp = 0;
+ }
+ cfp = Configlist_return();
+ Configlist_eat(cfp);
+ }else{
+ /* This really is a new state. Construct all the details */
+ Configlist_closure(lemp); /* Compute the configuration closure */
+ Configlist_sort(); /* Sort the configuration closure */
+ cfp = Configlist_return(); /* Get a pointer to the config list */
+ stp = State_new(); /* A new state structure */
+ MemoryCheck(stp);
+ stp->bp = bp; /* Remember the configuration basis */
+ stp->cfp = cfp; /* Remember the configuration closure */
+ stp->index = lemp->nstate++; /* Every state gets a sequence number */
+ stp->ap = 0; /* No actions, yet. */
+ State_insert(stp,stp->bp); /* Add to the state table */
+ buildshifts(lemp,stp); /* Recursively compute successor states */
+ }
+ return stp;
+}
+
+/* Construct all successor states to the given state. A "successor"
+** state is any state which can be reached by a shift action.
+*/
+PRIVATE void buildshifts(lemp,stp)
+struct lemon *lemp;
+struct state *stp; /* The state from which successors are computed */
+{
+ struct config *cfp; /* For looping thru the config closure of "stp" */
+ struct config *bcfp; /* For the inner loop on config closure of "stp" */
+ struct config *new; /* */
+ struct symbol *sp; /* Symbol following the dot in configuration "cfp" */
+ struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */
+ struct state *newstp; /* A pointer to a successor state */
+
+ /* Each configuration becomes complete after it contibutes to a successor
+ ** state. Initially, all configurations are incomplete */
+ for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE;
+
+ /* Loop through all configurations of the state "stp" */
+ for(cfp=stp->cfp; cfp; cfp=cfp->next){
+ if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */
+ if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */
+ Configlist_reset(); /* Reset the new config set */
+ sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */
+
+ /* For every configuration in the state "stp" which has the symbol "sp"
+ ** following its dot, add the same configuration to the basis set under
+ ** construction but with the dot shifted one symbol to the right. */
+ for(bcfp=cfp; bcfp; bcfp=bcfp->next){
+ if( bcfp->status==COMPLETE ) continue; /* Already used */
+ if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */
+ bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */
+ if( bsp!=sp ) continue; /* Must be same as for "cfp" */
+ bcfp->status = COMPLETE; /* Mark this config as used */
+ new = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
+ Plink_add(&new->bplp,bcfp);
+ }
+
+ /* Get a pointer to the state described by the basis configuration set
+ ** constructed in the preceding loop */
+ newstp = getstate(lemp);
+
+ /* The state "newstp" is reached from the state "stp" by a shift action
+ ** on the symbol "sp" */
+ Action_add(&stp->ap,SHIFT,sp,newstp);
+ }
+}
+
+/*
+** Construct the propagation links
+*/
+void FindLinks(lemp)
+struct lemon *lemp;
+{
+ int i;
+ struct config *cfp, *other;
+ struct state *stp;
+ struct plink *plp;
+
+ /* Housekeeping detail:
+ ** Add to every propagate link a pointer back to the state to
+ ** which the link is attached. */
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ for(cfp=stp->cfp; cfp; cfp=cfp->next){
+ cfp->stp = stp;
+ }
+ }
+
+ /* Convert all backlinks into forward links. Only the forward
+ ** links are used in the follow-set computation. */
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ for(cfp=stp->cfp; cfp; cfp=cfp->next){
+ for(plp=cfp->bplp; plp; plp=plp->next){
+ other = plp->cfp;
+ Plink_add(&other->fplp,cfp);
+ }
+ }
+ }
+}
+
+/* Compute all followsets.
+**
+** A followset is the set of all symbols which can come immediately
+** after a configuration.
+*/
+void FindFollowSets(lemp)
+struct lemon *lemp;
+{
+ int i;
+ struct config *cfp;
+ struct state *stp;
+ struct plink *plp;
+ int progress;
+ int change;
+
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ for(cfp=stp->cfp; cfp; cfp=cfp->next){
+ cfp->status = INCOMPLETE;
+ }
+ }
+
+ do{
+ progress = 0;
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ for(cfp=stp->cfp; cfp; cfp=cfp->next){
+ if( cfp->status==COMPLETE ) continue;
+ for(plp=cfp->fplp; plp; plp=plp->next){
+ change = SetUnion(plp->cfp->fws,cfp->fws);
+ if( change ){
+ plp->cfp->status = INCOMPLETE;
+ progress = 1;
+ }
+ }
+ cfp->status = COMPLETE;
+ }
+ }
+ }while( progress );
+}
+
+static int resolve_conflict();
+
+/* Compute the reduce actions, and resolve conflicts.
+*/
+void FindActions(lemp)
+struct lemon *lemp;
+{
+ int i,j;
+ struct config *cfp;
+ struct symbol *sp;
+ struct rule *rp;
+
+ /* Add all of the reduce actions
+ ** A reduce action is added for each element of the followset of
+ ** a configuration which has its dot at the extreme right.
+ */
+ for(i=0; i<lemp->nstate; i++){ /* Loop over all states */
+ struct state *stp;
+ stp = lemp->sorted[i];
+ for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */
+ if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */
+ for(j=0; j<lemp->nterminal; j++){
+ if( SetFind(cfp->fws,j) ){
+ /* Add a reduce action to the state "stp" which will reduce by the
+ ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */
+ Action_add(&stp->ap,REDUCE,lemp->symbols[j],cfp->rp);
+ }
+ }
+ }
+ }
+ }
+
+ /* Add the accepting token */
+ if( lemp->start ){
+ sp = Symbol_find(lemp->start);
+ if( sp==0 ) sp = lemp->rule->lhs;
+ }else{
+ sp = lemp->rule->lhs;
+ }
+ /* Add to the first state (which is always the starting state of the
+ ** finite state machine) an action to ACCEPT if the lookahead is the
+ ** start nonterminal. */
+ if (lemp->nstate) { /*(should always be true)*/
+ struct state *stp;
+ stp = lemp->sorted[0];
+ Action_add(&stp->ap,ACCEPT,sp,0);
+ }
+
+ /* Resolve conflicts */
+ for(i=0; i<lemp->nstate; i++){
+ struct action *ap, *nap;
+ struct state *stp;
+ stp = lemp->sorted[i];
+ assert( stp->ap );
+ stp->ap = Action_sort(stp->ap);
+ for(ap=stp->ap; ap && ap->next; ap=ap->next){
+ for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
+ /* The two actions "ap" and "nap" have the same lookahead.
+ ** Figure out which one should be used */
+ lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym);
+ }
+ }
+ }
+
+ /* Report an error for each rule that can never be reduced. */
+ for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = Bo_FALSE;
+ for(i=0; i<lemp->nstate; i++){
+ struct action *ap;
+ for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
+ if( ap->type==REDUCE ) ap->x.rp->canReduce = Bo_TRUE;
+ }
+ }
+ for(rp=lemp->rule; rp; rp=rp->next){
+ if( rp->canReduce ) continue;
+ ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n");
+ lemp->errorcnt++;
+ }
+}
+
+/* Resolve a conflict between the two given actions. If the
+** conflict can't be resolve, return non-zero.
+**
+** NO LONGER TRUE:
+** To resolve a conflict, first look to see if either action
+** is on an error rule. In that case, take the action which
+** is not associated with the error rule. If neither or both
+** actions are associated with an error rule, then try to
+** use precedence to resolve the conflict.
+**
+** If either action is a SHIFT, then it must be apx. This
+** function won't work if apx->type==REDUCE and apy->type==SHIFT.
+*/
+static int resolve_conflict(apx,apy,errsym)
+struct action *apx;
+struct action *apy;
+struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
+{
+ struct symbol *spx, *spy;
+ int errcnt = 0;
+ UNUSED(errsym);
+ assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */
+ if( apx->type==SHIFT && apy->type==REDUCE ){
+ spx = apx->sp;
+ spy = apy->x.rp->precsym;
+ if( spy==0 || spx->prec<0 || spy->prec<0 ){
+ /* Not enough precedence information. */
+ apy->type = CONFLICT;
+ errcnt++;
+ }else if( spx->prec>spy->prec ){ /* Lower precedence wins */
+ apy->type = RD_RESOLVED;
+ }else if( spx->prec<spy->prec ){
+ apx->type = SH_RESOLVED;
+ }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */
+ apy->type = RD_RESOLVED; /* associativity */
+ }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */
+ apx->type = SH_RESOLVED;
+ }else{
+ assert( spx->prec==spy->prec && spx->assoc==NONE );
+ apy->type = CONFLICT;
+ errcnt++;
+ }
+ }else if( apx->type==REDUCE && apy->type==REDUCE ){
+ spx = apx->x.rp->precsym;
+ spy = apy->x.rp->precsym;
+ if( spx==0 || spy==0 || spx->prec<0 ||
+ spy->prec<0 || spx->prec==spy->prec ){
+ apy->type = CONFLICT;
+ errcnt++;
+ }else if( spx->prec>spy->prec ){
+ apy->type = RD_RESOLVED;
+ }else if( spx->prec<spy->prec ){
+ apx->type = RD_RESOLVED;
+ }
+ }else{
+ assert(
+ apx->type==SH_RESOLVED ||
+ apx->type==RD_RESOLVED ||
+ apx->type==CONFLICT ||
+ apy->type==SH_RESOLVED ||
+ apy->type==RD_RESOLVED ||
+ apy->type==CONFLICT
+ );
+ /* The REDUCE/SHIFT case cannot happen because SHIFTs come before
+ ** REDUCEs on the list. If we reach this point it must be because
+ ** the parser conflict had already been resolved. */
+ }
+ return errcnt;
+}
+/********************* From the file "configlist.c" *************************/
+/*
+** Routines to processing a configuration list and building a state
+** in the LEMON parser generator.
+*/
+
+static struct config *freelist = 0; /* List of free configurations */
+static struct config *current = 0; /* Top of list of configurations */
+static struct config **currentend = 0; /* Last on list of configs */
+static struct config *basis = 0; /* Top of list of basis configs */
+static struct config **basisend = 0; /* End of list of basis configs */
+
+/* Return a pointer to a new configuration */
+PRIVATE struct config *newconfig(){
+ struct config *new;
+ if( freelist==0 ){
+ int i;
+ int amt = 3;
+ freelist = (struct config *)malloc( sizeof(struct config)*amt );
+ if( freelist==0 ){
+ fprintf(stderr,"Unable to allocate memory for a new configuration.");
+ exit(1);
+ }
+ for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
+ freelist[amt-1].next = 0;
+ }
+ new = freelist;
+ freelist = freelist->next;
+ return new;
+}
+
+/* The configuration "old" is no longer used */
+PRIVATE void deleteconfig(old)
+struct config *old;
+{
+ old->next = freelist;
+ freelist = old;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_init(){
+ current = 0;
+ currentend = &current;
+ basis = 0;
+ basisend = &basis;
+ Configtable_init();
+ return;
+}
+
+/* Initialized the configuration list builder */
+void Configlist_reset(){
+ current = 0;
+ currentend = &current;
+ basis = 0;
+ basisend = &basis;
+ Configtable_clear(0);
+ return;
+}
+
+/* Add another configuration to the configuration list */
+struct config *Configlist_add(rp,dot)
+struct rule *rp; /* The rule */
+int dot; /* Index into the RHS of the rule where the dot goes */
+{
+ struct config *cfp, model;
+
+ assert( currentend!=0 );
+ model.rp = rp;
+ model.dot = dot;
+ cfp = Configtable_find(&model);
+ if( cfp==0 ){
+ cfp = newconfig();
+ cfp->rp = rp;
+ cfp->dot = dot;
+ cfp->fws = SetNew();
+ cfp->stp = 0;
+ cfp->fplp = cfp->bplp = 0;
+ cfp->next = 0;
+ cfp->bp = 0;
+ *currentend = cfp;
+ currentend = &cfp->next;
+ Configtable_insert(cfp);
+ }
+ return cfp;
+}
+
+/* Add a basis configuration to the configuration list */
+struct config *Configlist_addbasis(rp,dot)
+struct rule *rp;
+int dot;
+{
+ struct config *cfp, model;
+
+ assert( basisend!=0 );
+ assert( currentend!=0 );
+ model.rp = rp;
+ model.dot = dot;
+ cfp = Configtable_find(&model);
+ if( cfp==0 ){
+ cfp = newconfig();
+ cfp->rp = rp;
+ cfp->dot = dot;
+ cfp->fws = SetNew();
+ cfp->stp = 0;
+ cfp->fplp = cfp->bplp = 0;
+ cfp->next = 0;
+ cfp->bp = 0;
+ *currentend = cfp;
+ currentend = &cfp->next;
+ *basisend = cfp;
+ basisend = &cfp->bp;
+ Configtable_insert(cfp);
+ }
+ return cfp;
+}
+
+/* Compute the closure of the configuration list */
+void Configlist_closure(lemp)
+struct lemon *lemp;
+{
+ struct config *cfp, *newcfp;
+ struct rule *rp, *newrp;
+ struct symbol *sp, *xsp;
+ int i, dot;
+
+ assert( currentend!=0 );
+ for(cfp=current; cfp; cfp=cfp->next){
+ rp = cfp->rp;
+ dot = cfp->dot;
+ if( dot>=rp->nrhs ) continue;
+ sp = rp->rhs[dot];
+ if( sp->type==NONTERMINAL ){
+ if( sp->rule==0 && sp!=lemp->errsym ){
+ ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.",
+ sp->name);
+ lemp->errorcnt++;
+ }
+ for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){
+ newcfp = Configlist_add(newrp,0);
+ for(i=dot+1; i<rp->nrhs; i++){
+ xsp = rp->rhs[i];
+ if( xsp->type==TERMINAL ){
+ SetAdd(newcfp->fws,xsp->index);
+ break;
+ }else{
+ SetUnion(newcfp->fws,xsp->firstset);
+ if( xsp->lambda==Bo_FALSE ) break;
+ }
+ }
+ if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
+ }
+ }
+ }
+ return;
+}
+
+/* Sort the configuration list */
+void Configlist_sort(){
+ current = (struct config *)msort(current,(void **)&(current->next),Configcmp);
+ currentend = 0;
+ return;
+}
+
+/* Sort the basis configuration list */
+void Configlist_sortbasis(){
+ basis = (struct config *)msort(current,(void **)&(current->bp),Configcmp);
+ basisend = 0;
+ return;
+}
+
+/* Return a pointer to the head of the configuration list and
+** reset the list */
+struct config *Configlist_return(){
+ struct config *old;
+ old = current;
+ current = 0;
+ currentend = 0;
+ return old;
+}
+
+/* Return a pointer to the head of the configuration list and
+** reset the list */
+struct config *Configlist_basis(){
+ struct config *old;
+ old = basis;
+ basis = 0;
+ basisend = 0;
+ return old;
+}
+
+/* Free all elements of the given configuration list */
+void Configlist_eat(cfp)
+struct config *cfp;
+{
+ struct config *nextcfp;
+ for(; cfp; cfp=nextcfp){
+ nextcfp = cfp->next;
+ assert( cfp->fplp==0 );
+ assert( cfp->bplp==0 );
+ if( cfp->fws ) SetFree(cfp->fws);
+ deleteconfig(cfp);
+ }
+ return;
+}
+/***************** From the file "error.c" *********************************/
+/*
+** Code for printing error message.
+*/
+
+/* Find a good place to break "msg" so that its length is at least "min"
+** but no more than "max". Make the point as close to max as possible.
+*/
+static int findbreak(msg,min,max)
+char *msg;
+int min;
+int max;
+{
+ int i,spot;
+ char c;
+ for(i=spot=min; i<=max; i++){
+ c = msg[i];
+ if( c=='\t' ) msg[i] = ' ';
+ if( c=='\n' ){ msg[i] = ' '; spot = i; break; }
+ if( c==0 ){ spot = i; break; }
+ if( c=='-' && i<max-1 ) spot = i+1;
+ if( c==' ' ) spot = i;
+ }
+ return spot;
+}
+
+/*
+** The error message is split across multiple lines if necessary. The
+** splits occur at a space, if there is a space available near the end
+** of the line.
+*/
+#define ERRMSGSIZE 10000 /* Hope this is big enough. No way to error check */
+#define LINEWIDTH 79 /* Max width of any output line */
+#define PREFIXLIMIT 30 /* Max width of the prefix on each line */
+void ErrorMsg(const char *filename, int lineno, const char *format, ...){
+ char errmsg[ERRMSGSIZE];
+ char prefix[PREFIXLIMIT+10];
+ int errmsgsize;
+ int prefixsize;
+ int availablewidth;
+ va_list ap;
+ int end, restart, base;
+
+ va_start(ap, format);
+ /* Prepare a prefix to be prepended to every output line */
+ if( lineno>0 ){
+ sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno);
+ }else{
+ sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename);
+ }
+ prefixsize = strlen(prefix);
+ availablewidth = LINEWIDTH - prefixsize;
+
+ /* Generate the error message */
+ vsprintf(errmsg,format,ap);
+ va_end(ap);
+ errmsgsize = strlen(errmsg);
+ /* Remove trailing '\n's from the error message. */
+ while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){
+ errmsg[--errmsgsize] = 0;
+ }
+
+ /* Print the error message */
+ base = 0;
+ while( errmsg[base]!=0 ){
+ end = restart = findbreak(&errmsg[base],0,availablewidth);
+ restart += base;
+ while( errmsg[restart]==' ' ) restart++;
+ fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]);
+ base = restart;
+ }
+}
+/**************** From the file "main.c" ************************************/
+/*
+** Main program file for the LEMON parser generator.
+*/
+
+/* Report an out-of-memory condition and abort. This function
+** is used mostly by the "MemoryCheck" macro in struct.h
+*/
+void memory_error() {
+ fprintf(stderr,"Out of memory. Aborting...\n");
+ exit(1);
+}
+
+static const char* out_dir = ".";
+/* The main program. Parse the command line and do it... */
+int main(argc,argv)
+int argc;
+char **argv;
+{
+ static int version = 0;
+ static int rpflag = 0;
+ static int basisflag = 0;
+ static int compress = 0;
+ static int quiet = 0;
+ static int statistics = 0;
+ static int mhflag = 0;
+ static struct s_options options[] = {
+ {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
+ {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
+ {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
+ {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"},
+ {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."},
+ {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."},
+ {OPT_FLAG, "x", (char*)&version, "Print the version number."},
+ {OPT_STR, "o", (char*)&out_dir, "Customize output directory."},
+ {OPT_FLAG,0,0,0}
+ };
+ int i;
+ struct lemon lem;
+ char *def_tmpl_name = "lempar.c";
+
+ UNUSED(argc);
+ OptInit(argv,options,stderr);
+ if( version ){
+ printf("Lemon version 1.0\n");
+ exit(0);
+ }
+ if( OptNArgs() < 1 ){
+ fprintf(stderr,"Exactly one filename argument is required.\n");
+ exit(1);
+ }
+ lem.errorcnt = 0;
+
+ /* Initialize the machine */
+ Strsafe_init();
+ Symbol_init();
+ State_init();
+ lem.argv0 = argv[0];
+ lem.filename = OptArg(0);
+ lem.tmplname = (OptNArgs() == 2) ? OptArg(1) : def_tmpl_name;
+ lem.basisflag = basisflag;
+ lem.has_fallback = 0;
+ lem.nconflict = 0;
+ lem.name = lem.include = lem.arg = lem.tokentype = lem.start = 0;
+ lem.vartype = 0;
+ lem.stacksize = 0;
+ lem.error = lem.overflow = lem.failure = lem.accept = lem.tokendest =
+ lem.tokenprefix = lem.outname = lem.extracode = 0;
+ lem.vardest = 0;
+ lem.tablesize = 0;
+ Symbol_new("$");
+ lem.errsym = Symbol_new("error");
+
+ /* Parse the input file */
+ Parse(&lem);
+ if( lem.errorcnt ) exit(lem.errorcnt);
+ if( lem.rule==0 ){
+ fprintf(stderr,"Empty grammar.\n");
+ exit(1);
+ }
+
+ /* Count and index the symbols of the grammar */
+ Symbol_new("{default}");
+ lem.nsymbol = Symbol_count();
+ lem.symbols = Symbol_arrayof();
+ for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
+ qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*),
+ (int(*)())Symbolcmpp);
+ for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
+ for(i=1; i<lem.nsymbol && isupper(lem.symbols[i]->name[0]); i++);
+ lem.nsymbol--; /*(do not count "{default}")*/
+ lem.nterminal = i;
+
+ /* Generate a reprint of the grammar, if requested on the command line */
+ if( rpflag ){
+ Reprint(&lem);
+ }else{
+ /* Initialize the size for all follow and first sets */
+ SetSize(lem.nterminal);
+
+ /* Find the precedence for every production rule (that has one) */
+ FindRulePrecedences(&lem);
+
+ /* Compute the lambda-nonterminals and the first-sets for every
+ ** nonterminal */
+ FindFirstSets(&lem);
+
+ /* Compute all LR(0) states. Also record follow-set propagation
+ ** links so that the follow-set can be computed later */
+ lem.nstate = 0;
+ FindStates(&lem);
+ lem.nstate = State_count();
+ lem.sorted = State_arrayof();
+
+ /* Tie up loose ends on the propagation links */
+ FindLinks(&lem);
+
+ /* Compute the follow set of every reducible configuration */
+ FindFollowSets(&lem);
+
+ /* Compute the action tables */
+ FindActions(&lem);
+
+ /* Compress the action tables */
+ if( compress==0 ) CompressTables(&lem);
+
+ /* Generate a report of the parser generated. (the "y.output" file) */
+ if( !quiet ) ReportOutput(&lem);
+
+ /* Generate the source code for the parser */
+ ReportTable(&lem, mhflag);
+
+ /* Produce a header file for use by the scanner. (This step is
+ ** omitted if the "-m" option is used because makeheaders will
+ ** generate the file for us.) */
+ if( !mhflag ) ReportHeader(&lem);
+ }
+ if( statistics ){
+ printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
+ lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule);
+ printf(" %d states, %d parser table entries, %d conflicts\n",
+ lem.nstate, lem.tablesize, lem.nconflict);
+ }
+ if( lem.nconflict ){
+ fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict);
+ }
+ exit(lem.errorcnt + lem.nconflict);
+}
+/******************** From the file "msort.c" *******************************/
+/*
+** A generic merge-sort program.
+**
+** USAGE:
+** Let "ptr" be a pointer to some structure which is at the head of
+** a null-terminated list. Then to sort the list call:
+**
+** ptr = msort(ptr,&(ptr->next),cmpfnc);
+**
+** In the above, "cmpfnc" is a pointer to a function which compares
+** two instances of the structure and returns an integer, as in
+** strcmp. The second argument is a pointer to the pointer to the
+** second element of the linked list. This address is used to compute
+** the offset to the "next" field within the structure. The offset to
+** the "next" field must be constant for all structures in the list.
+**
+** The function returns a new pointer which is the head of the list
+** after sorting.
+**
+** ALGORITHM:
+** Merge-sort.
+*/
+
+/*
+** Return a pointer to the next structure in the linked list.
+*/
+#define NEXT(A) (*(char**)(((unsigned long)A)+offset))
+
+/*
+** Inputs:
+** a: A sorted, null-terminated linked list. (May be null).
+** b: A sorted, null-terminated linked list. (May be null).
+** cmp: A pointer to the comparison function.
+** offset: Offset in the structure to the "next" field.
+**
+** Return Value:
+** A pointer to the head of a sorted list containing the elements
+** of both a and b.
+**
+** Side effects:
+** The "next" pointers for elements in the lists a and b are
+** changed.
+*/
+static char *merge(a,b,cmp,offset)
+char *a;
+char *b;
+int (*cmp)();
+int offset;
+{
+ char *ptr, *head;
+
+ if( a==0 ){
+ head = b;
+ }else if( b==0 ){
+ head = a;
+ }else{
+ if( (*cmp)(a,b)<0 ){
+ ptr = a;
+ a = NEXT(a);
+ }else{
+ ptr = b;
+ b = NEXT(b);
+ }
+ head = ptr;
+ while( a && b ){
+ if( (*cmp)(a,b)<0 ){
+ NEXT(ptr) = a;
+ ptr = a;
+ a = NEXT(a);
+ }else{
+ NEXT(ptr) = b;
+ ptr = b;
+ b = NEXT(b);
+ }
+ }
+ if( a ) NEXT(ptr) = a;
+ else NEXT(ptr) = b;
+ }
+ return head;
+}
+
+/*
+** Inputs:
+** list: Pointer to a singly-linked list of structures.
+** next: Pointer to pointer to the second element of the list.
+** cmp: A comparison function.
+**
+** Return Value:
+** A pointer to the head of a sorted list containing the elements
+** orginally in list.
+**
+** Side effects:
+** The "next" pointers for elements in list are changed.
+*/
+#define LISTSIZE 30
+void *msort(void *list, void **next, int(*cmp)(void *, void *))
+{
+ unsigned long offset;
+ char *ep;
+ char *set[LISTSIZE];
+ int i;
+ offset = (unsigned long)next - (unsigned long)list;
+ for(i=0; i<LISTSIZE; i++) set[i] = 0;
+ while( list ){
+ ep = list;
+ list = NEXT(list);
+ NEXT(ep) = 0;
+ for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){
+ ep = merge(ep,set[i],cmp,offset);
+ set[i] = 0;
+ }
+ set[i] = ep;
+ }
+ ep = 0;
+ for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(ep,set[i],cmp,offset);
+ return ep;
+}
+/************************ From the file "option.c" **************************/
+static char **argv;
+static struct s_options *op;
+static FILE *errstream;
+
+#define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0)
+
+/*
+** Print the command line with a carrot pointing to the k-th character
+** of the n-th field.
+*/
+static void errline(n,k,err)
+int n;
+int k;
+FILE *err;
+{
+ int spcnt = 0, i;
+ if( argv[0] ) {
+ fprintf(err,"%s",argv[0]);
+ spcnt += strlen(argv[0]) + 1;
+ }
+ for(i=1; i<n && argv[i]; i++){
+ fprintf(err," %s",argv[i]);
+ spcnt += strlen(argv[i]) + 1;
+ }
+ spcnt += k;
+ for(; argv[i]; i++) fprintf(err," %s",argv[i]);
+ if( spcnt<20 ){
+ fprintf(err,"\n%*s^-- here\n",spcnt,"");
+ }else{
+ fprintf(err,"\n%*shere --^\n",spcnt-7,"");
+ }
+}
+
+/*
+** Return the index of the N-th non-switch argument. Return -1
+** if N is out of range.
+*/
+static int argindex(n)
+int n;
+{
+ int i;
+ int dashdash = 0;
+ if( argv!=0 && *argv!=0 ){
+ for(i=1; argv[i]; i++){
+ if( dashdash || !ISOPT(argv[i]) ){
+ if( n==0 ) return i;
+ n--;
+ }
+ if( strcmp(argv[i],"--")==0 ) dashdash = 1;
+ }
+ }
+ return -1;
+}
+
+static char emsg[] = "Command line syntax error: ";
+
+/*
+** Process a flag command line argument.
+*/
+static int handleflags(i,err)
+int i;
+FILE *err;
+{
+ int v;
+ int errcnt = 0;
+ int j;
+ for(j=0; op[j].label; j++){
+ if( strcmp(&argv[i][1],op[j].label)==0 ) break;
+ }
+ v = argv[i][0]=='-' ? 1 : 0;
+ if( op[j].label==0 ){
+ if( err ){
+ fprintf(err,"%sundefined option.\n",emsg);
+ errline(i,1,err);
+ }
+ errcnt++;
+ }else if( op[j].type==OPT_FLAG ){
+ *((int*)op[j].arg) = v;
+ }else if( op[j].type==OPT_FFLAG ){
+ (*(void(*)())(intptr_t)(op[j].arg))(v);
+ }else{
+ if( err ){
+ fprintf(err,"%smissing argument on switch.\n",emsg);
+ errline(i,1,err);
+ }
+ errcnt++;
+ }
+ return errcnt;
+}
+
+/*
+** Process a command line switch which has an argument.
+*/
+static int handleswitch(i,err)
+int i;
+FILE *err;
+{
+ int lv = 0;
+ double dv = 0.0;
+ char *sv = 0, *end;
+ char *cp;
+ int j;
+ int errcnt = 0;
+ cp = strchr(argv[i],'=');
+ *cp = 0;
+ for(j=0; op[j].label; j++){
+ if( strcmp(argv[i],op[j].label)==0 ) break;
+ }
+ *cp = '=';
+ if( op[j].label==0 ){
+ if( err ){
+ fprintf(err,"%sundefined option.\n",emsg);
+ errline(i,0,err);
+ }
+ errcnt++;
+ }else{
+ cp++;
+ switch( op[j].type ){
+ case OPT_FLAG:
+ case OPT_FFLAG:
+ if( err ){
+ fprintf(err,"%soption requires an argument.\n",emsg);
+ errline(i,0,err);
+ }
+ errcnt++;
+ break;
+ case OPT_DBL:
+ case OPT_FDBL:
+ dv = strtod(cp,&end);
+ if( *end ){
+ if( err ){
+ fprintf(err,"%sillegal character in floating-point argument.\n",emsg);
+ errline(i,((unsigned long)end)-(unsigned long)argv[i],err);
+ }
+ errcnt++;
+ }
+ break;
+ case OPT_INT:
+ case OPT_FINT:
+ lv = strtol(cp,&end,0);
+ if( *end ){
+ if( err ){
+ fprintf(err,"%sillegal character in integer argument.\n",emsg);
+ errline(i,((unsigned long)end)-(unsigned long)argv[i],err);
+ }
+ errcnt++;
+ }
+ break;
+ case OPT_STR:
+ case OPT_FSTR:
+ sv = cp;
+ break;
+ }
+ switch( op[j].type ){
+ case OPT_FLAG:
+ case OPT_FFLAG:
+ break;
+ case OPT_DBL:
+ *(double*)(op[j].arg) = dv;
+ break;
+ case OPT_FDBL:
+ (*(void(*)())(intptr_t)(op[j].arg))(dv);
+ break;
+ case OPT_INT:
+ *(int*)(op[j].arg) = lv;
+ break;
+ case OPT_FINT:
+ (*(void(*)())(intptr_t)(op[j].arg))((int)lv);
+ break;
+ case OPT_STR:
+ *(char**)(op[j].arg) = sv;
+ break;
+ case OPT_FSTR:
+ (*(void(*)())(intptr_t)(op[j].arg))(sv);
+ break;
+ }
+ }
+ return errcnt;
+}
+
+int OptInit(a,o,err)
+char **a;
+struct s_options *o;
+FILE *err;
+{
+ int errcnt = 0;
+ argv = a;
+ op = o;
+ errstream = err;
+ if( argv && *argv && op ){
+ int i;
+ for(i=1; argv[i]; i++){
+ if( argv[i][0]=='+' || argv[i][0]=='-' ){
+ errcnt += handleflags(i,err);
+ }else if( strchr(argv[i],'=') ){
+ errcnt += handleswitch(i,err);
+ }
+ }
+ }
+ if( errcnt>0 ){
+ fprintf(err,"Valid command line options for \"%s\" are:\n",*a);
+ OptPrint();
+ exit(1);
+ }
+ return 0;
+}
+
+int OptNArgs(){
+ int cnt = 0;
+ int dashdash = 0;
+ int i;
+ if( argv!=0 && argv[0]!=0 ){
+ for(i=1; argv[i]; i++){
+ if( dashdash || !ISOPT(argv[i]) ) cnt++;
+ if( strcmp(argv[i],"--")==0 ) dashdash = 1;
+ }
+ }
+ return cnt;
+}
+
+char *OptArg(n)
+int n;
+{
+ int i;
+ i = argindex(n);
+ return i>=0 ? argv[i] : 0;
+}
+
+void OptErr(n)
+int n;
+{
+ int i;
+ i = argindex(n);
+ if( i>=0 ) errline(i,0,errstream);
+}
+
+void OptPrint(){
+ int i;
+ int max, len;
+ max = 0;
+ for(i=0; op[i].label; i++){
+ len = strlen(op[i].label) + 1;
+ switch( op[i].type ){
+ case OPT_FLAG:
+ case OPT_FFLAG:
+ break;
+ case OPT_INT:
+ case OPT_FINT:
+ len += 9; /* length of "<integer>" */
+ break;
+ case OPT_DBL:
+ case OPT_FDBL:
+ len += 6; /* length of "<real>" */
+ break;
+ case OPT_STR:
+ case OPT_FSTR:
+ len += 8; /* length of "<string>" */
+ break;
+ }
+ if( len>max ) max = len;
+ }
+ for(i=0; op[i].label; i++){
+ switch( op[i].type ){
+ case OPT_FLAG:
+ case OPT_FFLAG:
+ fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message);
+ break;
+ case OPT_INT:
+ case OPT_FINT:
+ fprintf(errstream," %s=<integer>%*s %s\n",op[i].label,
+ (int)(max-strlen(op[i].label)-9),"",op[i].message);
+ break;
+ case OPT_DBL:
+ case OPT_FDBL:
+ fprintf(errstream," %s=<real>%*s %s\n",op[i].label,
+ (int)(max-strlen(op[i].label)-6),"",op[i].message);
+ break;
+ case OPT_STR:
+ case OPT_FSTR:
+ fprintf(errstream," %s=<string>%*s %s\n",op[i].label,
+ (int)(max-strlen(op[i].label)-8),"",op[i].message);
+ break;
+ }
+ }
+}
+/*********************** From the file "parse.c" ****************************/
+/*
+** Input file parser for the LEMON parser generator.
+*/
+
+/* The state of the parser */
+struct pstate {
+ char *filename; /* Name of the input file */
+ int tokenlineno; /* Linenumber at which current token starts */
+ int errorcnt; /* Number of errors so far */
+ char *tokenstart; /* Text of current token */
+ struct lemon *gp; /* Global state vector */
+ enum e_state {
+ INITIALIZE,
+ WAITING_FOR_DECL_OR_RULE,
+ WAITING_FOR_DECL_KEYWORD,
+ WAITING_FOR_DECL_ARG,
+ WAITING_FOR_PRECEDENCE_SYMBOL,
+ WAITING_FOR_ARROW,
+ IN_RHS,
+ LHS_ALIAS_1,
+ LHS_ALIAS_2,
+ LHS_ALIAS_3,
+ RHS_ALIAS_1,
+ RHS_ALIAS_2,
+ PRECEDENCE_MARK_1,
+ PRECEDENCE_MARK_2,
+ RESYNC_AFTER_RULE_ERROR,
+ RESYNC_AFTER_DECL_ERROR,
+ WAITING_FOR_DESTRUCTOR_SYMBOL,
+ WAITING_FOR_DATATYPE_SYMBOL,
+ WAITING_FOR_FALLBACK_ID
+ } state; /* The state of the parser */
+ struct symbol *fallback; /* The fallback token */
+ struct symbol *lhs; /* Left-hand side of current rule */
+ char *lhsalias; /* Alias for the LHS */
+ int nrhs; /* Number of right-hand side symbols seen */
+ struct symbol *rhs[MAXRHS]; /* RHS symbols */
+ char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */
+ struct rule *prevrule; /* Previous rule parsed */
+ char *declkeyword; /* Keyword of a declaration */
+ char **declargslot; /* Where the declaration argument should be put */
+ int *decllnslot; /* Where the declaration linenumber is put */
+ enum e_assoc declassoc; /* Assign this association to decl arguments */
+ int preccounter; /* Assign this precedence to decl arguments */
+ struct rule *firstrule; /* Pointer to first rule in the grammar */
+ struct rule *lastrule; /* Pointer to the most recently parsed rule */
+};
+
+/* Parse a single token */
+static void parseonetoken(psp)
+struct pstate *psp;
+{
+ char *x;
+ x = Strsafe(psp->tokenstart); /* Save the token permanently */
+#if 0
+ printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno,
+ x,psp->state);
+#endif
+ switch( psp->state ){
+ case INITIALIZE:
+ psp->prevrule = 0;
+ psp->preccounter = 0;
+ psp->firstrule = psp->lastrule = 0;
+ psp->gp->nrule = 0;
+ /* Fall through */
+ case WAITING_FOR_DECL_OR_RULE:
+ if( x[0]=='%' ){
+ psp->state = WAITING_FOR_DECL_KEYWORD;
+ }else if( islower(x[0]) ){
+ psp->lhs = Symbol_new(x);
+ psp->nrhs = 0;
+ psp->lhsalias = 0;
+ psp->state = WAITING_FOR_ARROW;
+ }else if( x[0]=='{' ){
+ if( psp->prevrule==0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+"There is not prior rule opon which to attach the code \
+fragment which begins on this line.");
+ psp->errorcnt++;
+ }else if( psp->prevrule->code!=0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+"Code fragment beginning on this line is not the first \
+to follow the previous rule.");
+ psp->errorcnt++;
+ }else{
+ psp->prevrule->line = psp->tokenlineno;
+ psp->prevrule->code = &x[1];
+ }
+ }else if( x[0]=='[' ){
+ psp->state = PRECEDENCE_MARK_1;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Token \"%s\" should be either \"%%\" or a nonterminal name.",
+ x);
+ psp->errorcnt++;
+ }
+ break;
+ case PRECEDENCE_MARK_1:
+ if( !isupper(x[0]) ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "The precedence symbol must be a terminal.");
+ psp->errorcnt++;
+ }else if( psp->prevrule==0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "There is no prior rule to assign precedence \"[%s]\".",x);
+ psp->errorcnt++;
+ }else if( psp->prevrule->precsym!=0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+"Precedence mark on this line is not the first \
+to follow the previous rule.");
+ psp->errorcnt++;
+ }else{
+ psp->prevrule->precsym = Symbol_new(x);
+ }
+ psp->state = PRECEDENCE_MARK_2;
+ break;
+ case PRECEDENCE_MARK_2:
+ if( x[0]!=']' ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Missing \"]\" on precedence mark.");
+ psp->errorcnt++;
+ }
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ break;
+ case WAITING_FOR_ARROW:
+ if( x[0]==':' && x[1]==':' && x[2]=='=' ){
+ psp->state = IN_RHS;
+ }else if( x[0]=='(' ){
+ psp->state = LHS_ALIAS_1;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Expected to see a \":\" following the LHS symbol \"%s\".",
+ psp->lhs->name);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case LHS_ALIAS_1:
+ if( isalpha(x[0]) ){
+ psp->lhsalias = x;
+ psp->state = LHS_ALIAS_2;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "\"%s\" is not a valid alias for the LHS \"%s\"\n",
+ x,psp->lhs->name);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case LHS_ALIAS_2:
+ if( x[0]==')' ){
+ psp->state = LHS_ALIAS_3;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case LHS_ALIAS_3:
+ if( x[0]==':' && x[1]==':' && x[2]=='=' ){
+ psp->state = IN_RHS;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Missing \"->\" following: \"%s(%s)\".",
+ psp->lhs->name,psp->lhsalias);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case IN_RHS:
+ if( x[0]=='.' ){
+ struct rule *rp;
+ rp = (struct rule *)malloc( sizeof(struct rule) +
+ sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
+ if( rp==0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Can't allocate enough memory for this rule.");
+ psp->errorcnt++;
+ psp->prevrule = 0;
+ }else{
+ int i;
+ rp->ruleline = psp->tokenlineno;
+ rp->rhs = (struct symbol**)&rp[1];
+ rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]);
+ for(i=0; i<psp->nrhs; i++){
+ rp->rhs[i] = psp->rhs[i];
+ rp->rhsalias[i] = psp->alias[i];
+ }
+ rp->lhs = psp->lhs;
+ rp->lhsalias = psp->lhsalias;
+ rp->nrhs = psp->nrhs;
+ rp->code = 0;
+ rp->precsym = 0;
+ rp->index = psp->gp->nrule++;
+ rp->nextlhs = rp->lhs->rule;
+ rp->lhs->rule = rp;
+ rp->next = 0;
+ if( psp->firstrule==0 ){
+ psp->firstrule = psp->lastrule = rp;
+ }else{
+ psp->lastrule->next = rp;
+ psp->lastrule = rp;
+ }
+ psp->prevrule = rp;
+ }
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ }else if( isalpha(x[0]) ){
+ if( psp->nrhs>=MAXRHS ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Too many symbol on RHS or rule beginning at \"%s\".",
+ x);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }else{
+ psp->rhs[psp->nrhs] = Symbol_new(x);
+ psp->alias[psp->nrhs] = 0;
+ psp->nrhs++;
+ }
+ }else if( x[0]=='(' && psp->nrhs>0 ){
+ psp->state = RHS_ALIAS_1;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Illegal character on RHS of rule: \"%s\".",x);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case RHS_ALIAS_1:
+ if( isalpha(x[0]) ){
+ psp->alias[psp->nrhs-1] = x;
+ psp->state = RHS_ALIAS_2;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
+ x,psp->rhs[psp->nrhs-1]->name);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case RHS_ALIAS_2:
+ if( x[0]==')' ){
+ psp->state = IN_RHS;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_RULE_ERROR;
+ }
+ break;
+ case WAITING_FOR_DECL_KEYWORD:
+ if( isalpha(x[0]) ){
+ psp->declkeyword = x;
+ psp->declargslot = 0;
+ psp->decllnslot = 0;
+ psp->state = WAITING_FOR_DECL_ARG;
+ if( strcmp(x,"name")==0 ){
+ psp->declargslot = &(psp->gp->name);
+ }else if( strcmp(x,"include")==0 ){
+ psp->declargslot = &(psp->gp->include);
+ psp->decllnslot = &psp->gp->includeln;
+ }else if( strcmp(x,"code")==0 ){
+ psp->declargslot = &(psp->gp->extracode);
+ psp->decllnslot = &psp->gp->extracodeln;
+ }else if( strcmp(x,"token_destructor")==0 ){
+ psp->declargslot = &psp->gp->tokendest;
+ psp->decllnslot = &psp->gp->tokendestln;
+ }else if( strcmp(x,"default_destructor")==0 ){
+ psp->declargslot = &psp->gp->vardest;
+ psp->decllnslot = &psp->gp->vardestln;
+ }else if( strcmp(x,"token_prefix")==0 ){
+ psp->declargslot = &psp->gp->tokenprefix;
+ }else if( strcmp(x,"syntax_error")==0 ){
+ psp->declargslot = &(psp->gp->error);
+ psp->decllnslot = &psp->gp->errorln;
+ }else if( strcmp(x,"parse_accept")==0 ){
+ psp->declargslot = &(psp->gp->accept);
+ psp->decllnslot = &psp->gp->acceptln;
+ }else if( strcmp(x,"parse_failure")==0 ){
+ psp->declargslot = &(psp->gp->failure);
+ psp->decllnslot = &psp->gp->failureln;
+ }else if( strcmp(x,"stack_overflow")==0 ){
+ psp->declargslot = &(psp->gp->overflow);
+ psp->decllnslot = &psp->gp->overflowln;
+ }else if( strcmp(x,"extra_argument")==0 ){
+ psp->declargslot = &(psp->gp->arg);
+ }else if( strcmp(x,"token_type")==0 ){
+ psp->declargslot = &(psp->gp->tokentype);
+ }else if( strcmp(x,"default_type")==0 ){
+ psp->declargslot = &(psp->gp->vartype);
+ }else if( strcmp(x,"stack_size")==0 ){
+ psp->declargslot = &(psp->gp->stacksize);
+ }else if( strcmp(x,"start_symbol")==0 ){
+ psp->declargslot = &(psp->gp->start);
+ }else if( strcmp(x,"left")==0 ){
+ psp->preccounter++;
+ psp->declassoc = LEFT;
+ psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+ }else if( strcmp(x,"right")==0 ){
+ psp->preccounter++;
+ psp->declassoc = RIGHT;
+ psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+ }else if( strcmp(x,"nonassoc")==0 ){
+ psp->preccounter++;
+ psp->declassoc = NONE;
+ psp->state = WAITING_FOR_PRECEDENCE_SYMBOL;
+ }else if( strcmp(x,"destructor")==0 ){
+ psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL;
+ }else if( strcmp(x,"type")==0 ){
+ psp->state = WAITING_FOR_DATATYPE_SYMBOL;
+ }else if( strcmp(x,"fallback")==0 ){
+ psp->fallback = 0;
+ psp->state = WAITING_FOR_FALLBACK_ID;
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Unknown declaration keyword: \"%%%s\".",x);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_DECL_ERROR;
+ }
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Illegal declaration keyword: \"%s\".",x);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_DECL_ERROR;
+ }
+ break;
+ case WAITING_FOR_DESTRUCTOR_SYMBOL:
+ if( !isalpha(x[0]) ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Symbol name missing after %destructor keyword");
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_DECL_ERROR;
+ }else{
+ struct symbol *sp = Symbol_new(x);
+ psp->declargslot = &sp->destructor;
+ psp->decllnslot = &sp->destructorln;
+ psp->state = WAITING_FOR_DECL_ARG;
+ }
+ break;
+ case WAITING_FOR_DATATYPE_SYMBOL:
+ if( !isalpha(x[0]) ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Symbol name missing after %destructor keyword");
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_DECL_ERROR;
+ }else{
+ struct symbol *sp = Symbol_new(x);
+ psp->declargslot = &sp->datatype;
+ psp->decllnslot = 0;
+ psp->state = WAITING_FOR_DECL_ARG;
+ }
+ break;
+ case WAITING_FOR_PRECEDENCE_SYMBOL:
+ if( x[0]=='.' ){
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ }else if( isupper(x[0]) ){
+ struct symbol *sp;
+ sp = Symbol_new(x);
+ if( sp->prec>=0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Symbol \"%s\" has already be given a precedence.",x);
+ psp->errorcnt++;
+ }else{
+ sp->prec = psp->preccounter;
+ sp->assoc = psp->declassoc;
+ }
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Can't assign a precedence to \"%s\".",x);
+ psp->errorcnt++;
+ }
+ break;
+ case WAITING_FOR_DECL_ARG:
+ if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){
+ if( *(psp->declargslot)!=0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "The argument \"%s\" to declaration \"%%%s\" is not the first.",
+ x[0]=='\"' ? &x[1] : x,psp->declkeyword);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_DECL_ERROR;
+ }else{
+ *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x;
+ if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno;
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ }
+ }else{
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Illegal argument to %%%s: %s",psp->declkeyword,x);
+ psp->errorcnt++;
+ psp->state = RESYNC_AFTER_DECL_ERROR;
+ }
+ break;
+ case WAITING_FOR_FALLBACK_ID:
+ if( x[0]=='.' ){
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ }else if( !isupper(x[0]) ){
+ ErrorMsg(psp->filename, psp->tokenlineno,
+ "%%fallback argument \"%s\" should be a token", x);
+ psp->errorcnt++;
+ }else{
+ struct symbol *sp = Symbol_new(x);
+ if( psp->fallback==0 ){
+ psp->fallback = sp;
+ }else if( sp->fallback ){
+ ErrorMsg(psp->filename, psp->tokenlineno,
+ "More than one fallback assigned to token %s", x);
+ psp->errorcnt++;
+ }else{
+ sp->fallback = psp->fallback;
+ psp->gp->has_fallback = 1;
+ }
+ }
+ break;
+ case RESYNC_AFTER_RULE_ERROR:
+/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
+** break; */
+ case RESYNC_AFTER_DECL_ERROR:
+ if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
+ if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD;
+ break;
+ }
+}
+
+/* In spite of its name, this function is really a scanner. It read
+** in the entire input file (all at once) then tokenizes it. Each
+** token is passed to the function "parseonetoken" which builds all
+** the appropriate data structures in the global state vector "gp".
+*/
+struct pstate ps;
+void Parse(gp)
+struct lemon *gp;
+{
+ FILE *fp;
+ char *filebuf;
+ size_t filesize;
+ int lineno;
+ int c;
+ char *cp, *nextcp;
+ int startline = 0;
+
+ ps.gp = gp;
+ ps.filename = gp->filename;
+ ps.errorcnt = 0;
+ ps.state = INITIALIZE;
+
+ /* Begin by reading the input file */
+ fp = fopen(ps.filename,"rb");
+ if( fp==0 ){
+ ErrorMsg(ps.filename,0,"Can't open this file for reading.");
+ gp->errorcnt++;
+ return;
+ }
+ fseek(fp,0,2);
+ filesize = ftell(fp);
+ rewind(fp);
+ filebuf = (char *)malloc( filesize+1 );
+ if( filebuf==0 ){
+ ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.",
+ filesize+1);
+ fclose(fp);
+ gp->errorcnt++;
+ return;
+ }
+ if( fread(filebuf,1,filesize,fp)!=filesize ){
+ ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
+ filesize);
+ free(filebuf);
+ fclose(fp);
+ gp->errorcnt++;
+ return;
+ }
+ fclose(fp);
+ filebuf[filesize] = 0;
+
+ /* Now scan the text of the input file */
+ lineno = 1;
+ for(cp=filebuf; (c= *cp)!=0; ){
+ if( c=='\n' ) lineno++; /* Keep track of the line number */
+ if( isspace(c) ){ cp++; continue; } /* Skip all white space */
+ if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */
+ cp+=2;
+ while( (c= *cp)!=0 && c!='\n' ) cp++;
+ continue;
+ }
+ if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */
+ cp+=2;
+ while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){
+ if( c=='\n' ) lineno++;
+ cp++;
+ }
+ if( c ) cp++;
+ continue;
+ }
+ ps.tokenstart = cp; /* Mark the beginning of the token */
+ ps.tokenlineno = lineno; /* Linenumber on which token begins */
+ if( c=='\"' ){ /* String literals */
+ cp++;
+ while( (c= *cp)!=0 && c!='\"' ){
+ if( c=='\n' ) lineno++;
+ cp++;
+ }
+ if( c==0 ){
+ ErrorMsg(ps.filename,startline,
+"String starting on this line is not terminated before the end of the file.");
+ ps.errorcnt++;
+ nextcp = cp;
+ }else{
+ nextcp = cp+1;
+ }
+ }else if( c=='{' ){ /* A block of C code */
+ int level;
+ cp++;
+ for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){
+ if( c=='\n' ) lineno++;
+ else if( c=='{' ) level++;
+ else if( c=='}' ) level--;
+ else if( c=='/' && cp[1]=='*' ){ /* Skip comments */
+ int prevc;
+ cp = &cp[2];
+ prevc = 0;
+ while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){
+ if( c=='\n' ) lineno++;
+ prevc = c;
+ cp++;
+ }
+ }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */
+ cp = &cp[2];
+ while( (c= *cp)!=0 && c!='\n' ) cp++;
+ if( c ) lineno++;
+ }else if( c=='\'' || c=='\"' ){ /* String a character literals */
+ int startchar, prevc;
+ startchar = c;
+ prevc = 0;
+ for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){
+ if( c=='\n' ) lineno++;
+ if( prevc=='\\' ) prevc = 0;
+ else prevc = c;
+ }
+ }
+ }
+ if( c==0 ){
+ ErrorMsg(ps.filename,ps.tokenlineno,
+"C code starting on this line is not terminated before the end of the file.");
+ ps.errorcnt++;
+ nextcp = cp;
+ }else{
+ nextcp = cp+1;
+ }
+ }else if( isalnum(c) ){ /* Identifiers */
+ while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
+ nextcp = cp;
+ }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */
+ cp += 3;
+ nextcp = cp;
+ }else{ /* All other (one character) operators */
+ cp++;
+ nextcp = cp;
+ }
+ c = *cp;
+ *cp = 0; /* Null terminate the token */
+ parseonetoken(&ps); /* Parse the token */
+ *cp = c; /* Restore the buffer */
+ cp = nextcp;
+ }
+ free(filebuf); /* Release the buffer after parsing */
+ gp->rule = ps.firstrule;
+ gp->errorcnt = ps.errorcnt;
+}
+/*************************** From the file "plink.c" *********************/
+/*
+** Routines processing configuration follow-set propagation links
+** in the LEMON parser generator.
+*/
+static struct plink *plink_freelist = 0;
+
+/* Allocate a new plink */
+struct plink *Plink_new(){
+ struct plink *new;
+
+ if( plink_freelist==0 ){
+ int i;
+ int amt = 100;
+ plink_freelist = (struct plink *)malloc( sizeof(struct plink)*amt );
+ if( plink_freelist==0 ){
+ fprintf(stderr,
+ "Unable to allocate memory for a new follow-set propagation link.\n");
+ exit(1);
+ }
+ for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1];
+ plink_freelist[amt-1].next = 0;
+ }
+ new = plink_freelist;
+ plink_freelist = plink_freelist->next;
+ return new;
+}
+
+/* Add a plink to a plink list */
+void Plink_add(plpp,cfp)
+struct plink **plpp;
+struct config *cfp;
+{
+ struct plink *new;
+ new = Plink_new();
+ new->next = *plpp;
+ *plpp = new;
+ new->cfp = cfp;
+}
+
+/* Transfer every plink on the list "from" to the list "to" */
+void Plink_copy(to,from)
+struct plink **to;
+struct plink *from;
+{
+ struct plink *nextpl;
+ while( from ){
+ nextpl = from->next;
+ from->next = *to;
+ *to = from;
+ from = nextpl;
+ }
+}
+
+/* Delete every plink on the list */
+void Plink_delete(plp)
+struct plink *plp;
+{
+ struct plink *nextpl;
+
+ while( plp ){
+ nextpl = plp->next;
+ plp->next = plink_freelist;
+ plink_freelist = plp;
+ plp = nextpl;
+ }
+}
+/*********************** From the file "report.c" **************************/
+/*
+** Procedures for generating reports and tables in the LEMON parser generator.
+*/
+
+/* Generate a filename with the given suffix. Space to hold the
+** name comes from malloc() and must be freed by the calling
+** function.
+*/
+PRIVATE char *file_makename(lemp,suffix)
+struct lemon *lemp;
+char *suffix;
+{
+ char *name;
+ char *cp;
+
+ name = malloc( strlen(out_dir) + strlen(lemp->filename) + strlen(suffix) + 6 );
+ if( name==0 ){
+ fprintf(stderr,"Can't allocate space for a filename.\n");
+ exit(1);
+ }
+ /* skip directory, JK */
+ if (NULL == (cp = strrchr(lemp->filename, '/'))) {
+ cp = lemp->filename;
+ } else {
+ cp++;
+ }
+ strcpy(name,out_dir);
+ strcat(name,"/");
+ strcat(name,cp);
+ cp = strrchr(name,'.');
+ if( cp ) *cp = 0;
+ strcat(name,suffix);
+ return name;
+}
+
+/* Open a file with a name based on the name of the input file,
+** but with a different (specified) suffix, and return a pointer
+** to the stream */
+PRIVATE FILE *file_open(lemp,suffix,mode)
+struct lemon *lemp;
+char *suffix;
+char *mode;
+{
+ FILE *fp;
+
+ if( lemp->outname ) free(lemp->outname);
+ lemp->outname = file_makename(lemp, suffix);
+ fp = fopen(lemp->outname,mode);
+ if( fp==0 && *mode=='w' ){
+ fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname);
+ lemp->errorcnt++;
+ return 0;
+ }
+ return fp;
+}
+
+/* Duplicate the input file without comments and without actions
+** on rules */
+void Reprint(lemp)
+struct lemon *lemp;
+{
+ struct rule *rp;
+ struct symbol *sp;
+ int i, j, maxlen, len, ncolumns, skip;
+ printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename);
+ maxlen = 10;
+ for(i=0; i<lemp->nsymbol; i++){
+ sp = lemp->symbols[i];
+ len = strlen(sp->name);
+ if( len>maxlen ) maxlen = len;
+ }
+ ncolumns = 76/(maxlen+5);
+ if( ncolumns<1 ) ncolumns = 1;
+ skip = (lemp->nsymbol + ncolumns - 1)/ncolumns;
+ for(i=0; i<skip; i++){
+ printf("//");
+ for(j=i; j<lemp->nsymbol; j+=skip){
+ sp = lemp->symbols[j];
+ assert( sp->index==j );
+ printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name);
+ }
+ printf("\n");
+ }
+ for(rp=lemp->rule; rp; rp=rp->next){
+ printf("%s",rp->lhs->name);
+/* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
+ printf(" ::=");
+ for(i=0; i<rp->nrhs; i++){
+ printf(" %s",rp->rhs[i]->name);
+/* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
+ }
+ printf(".");
+ if( rp->precsym ) printf(" [%s]",rp->precsym->name);
+/* if( rp->code ) printf("\n %s",rp->code); */
+ printf("\n");
+ }
+}
+
+PRIVATE void ConfigPrint(fp,cfp)
+FILE *fp;
+struct config *cfp;
+{
+ struct rule *rp;
+ int i;
+ rp = cfp->rp;
+ fprintf(fp,"%s ::=",rp->lhs->name);
+ for(i=0; i<=rp->nrhs; i++){
+ if( i==cfp->dot ) fprintf(fp," *");
+ if( i==rp->nrhs ) break;
+ fprintf(fp," %s",rp->rhs[i]->name);
+ }
+}
+
+/* #define TEST */
+#ifdef TEST
+/* Print a set */
+PRIVATE void SetPrint(out,set,lemp)
+FILE *out;
+char *set;
+struct lemon *lemp;
+{
+ int i;
+ char *spacer;
+ spacer = "";
+ fprintf(out,"%12s[","");
+ for(i=0; i<lemp->nterminal; i++){
+ if( SetFind(set,i) ){
+ fprintf(out,"%s%s",spacer,lemp->symbols[i]->name);
+ spacer = " ";
+ }
+ }
+ fprintf(out,"]\n");
+}
+
+/* Print a plink chain */
+void PlinkPrint(out,plp,tag)
+FILE *out;
+struct plink *plp;
+char *tag;
+{
+ while( plp ){
+ fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->index);
+ ConfigPrint(out,plp->cfp);
+ fprintf(out,"\n");
+ plp = plp->next;
+ }
+}
+#endif
+
+/* Print an action to the given file descriptor. Return FALSE if
+** nothing was actually printed.
+*/
+PRIVATE int PrintAction(struct action *ap, FILE *fp, int indent){
+ int result = 1;
+ switch( ap->type ){
+ case SHIFT:
+ fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->index);
+ break;
+ case REDUCE:
+ fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index);
+ break;
+ case ACCEPT:
+ fprintf(fp,"%*s accept",indent,ap->sp->name);
+ break;
+ case ERROR:
+ fprintf(fp,"%*s error",indent,ap->sp->name);
+ break;
+ case CONFLICT:
+ fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
+ indent,ap->sp->name,ap->x.rp->index);
+ break;
+ case SH_RESOLVED:
+ case RD_RESOLVED:
+ case NOT_USED:
+ result = 0;
+ break;
+ }
+ return result;
+}
+
+/* Generate the "y.output" log file */
+void ReportOutput(lemp)
+struct lemon *lemp;
+{
+ int i;
+ struct state *stp;
+ struct config *cfp;
+ struct action *ap;
+ FILE *fp;
+
+ fp = file_open(lemp,".out","w");
+ if( fp==0 ) return;
+ fprintf(fp," \b");
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ fprintf(fp,"State %d:\n",stp->index);
+ if( lemp->basisflag ) cfp=stp->bp;
+ else cfp=stp->cfp;
+ while( cfp ){
+ char buf[20];
+ if( cfp->dot==cfp->rp->nrhs ){
+ sprintf(buf,"(%d)",cfp->rp->index);
+ fprintf(fp," %5s ",buf);
+ }else{
+ fprintf(fp," ");
+ }
+ ConfigPrint(fp,cfp);
+ fprintf(fp,"\n");
+#ifdef TEST
+ SetPrint(fp,cfp->fws,lemp);
+ PlinkPrint(fp,cfp->fplp,"To ");
+ PlinkPrint(fp,cfp->bplp,"From");
+#endif
+ if( lemp->basisflag ) cfp=cfp->bp;
+ else cfp=cfp->next;
+ }
+ fprintf(fp,"\n");
+ for(ap=stp->ap; ap; ap=ap->next){
+ if( PrintAction(ap,fp,30) ) fprintf(fp,"\n");
+ }
+ fprintf(fp,"\n");
+ }
+ fclose(fp);
+ return;
+}
+
+/* Search for the file "name" which is in the same directory as
+** the exacutable */
+PRIVATE char *pathsearch(argv0,name,modemask)
+char *argv0;
+char *name;
+int modemask;
+{
+ char *pathlist;
+ char *path,*cp;
+ char c;
+
+#ifdef __WIN32__
+ cp = strrchr(argv0,'\\');
+#else
+ cp = strrchr(argv0,'/');
+#endif
+ if( cp ){
+ c = *cp;
+ *cp = 0;
+ path = (char *)malloc( strlen(argv0) + strlen(name) + 2 );
+ if( path ) sprintf(path,"%s/%s",argv0,name);
+ *cp = c;
+ }else{
+ pathlist = getenv("PATH");
+ if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
+ path = (char *)malloc( strlen(pathlist)+strlen(name)+2 );
+ if( path!=0 ){
+ while( *pathlist ){
+ cp = strchr(pathlist,':');
+ if( cp==0 ) cp = &pathlist[strlen(pathlist)];
+ c = *cp;
+ *cp = 0;
+ sprintf(path,"%s/%s",pathlist,name);
+ *cp = c;
+ if( c==0 ) pathlist = "";
+ else pathlist = &cp[1];
+ if( access(path,modemask)==0 ) break;
+ }
+ }
+ }
+ return path;
+}
+
+/* Given an action, compute the integer value for that action
+** which is to be put in the action table of the generated machine.
+** Return negative if no action should be generated.
+*/
+PRIVATE int compute_action(lemp,ap)
+struct lemon *lemp;
+struct action *ap;
+{
+ int act;
+ switch( ap->type ){
+ case SHIFT: act = ap->x.stp->index; break;
+ case REDUCE: act = ap->x.rp->index + lemp->nstate; break;
+ case ERROR: act = lemp->nstate + lemp->nrule; break;
+ case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break;
+ default: act = -1; break;
+ }
+ return act;
+}
+
+#define LINESIZE 1000
+/* The next cluster of routines are for reading the template file
+** and writing the results to the generated parser */
+/* The first function transfers data from "in" to "out" until
+** a line is seen which begins with "%%". The line number is
+** tracked.
+**
+** if name!=0, then any word that begin with "Parse" is changed to
+** begin with *name instead.
+*/
+PRIVATE void tplt_xfer(name,in,out,lineno)
+char *name;
+FILE *in;
+FILE *out;
+int *lineno;
+{
+ int i, iStart;
+ char line[LINESIZE];
+ while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){
+ (*lineno)++;
+ iStart = 0;
+ if( name ){
+ for(i=0; line[i]; i++){
+ if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0
+ && (i==0 || !isalpha(line[i-1]))
+ ){
+ if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]);
+ fprintf(out,"%s",name);
+ i += 4;
+ iStart = i+1;
+ }
+ }
+ }
+ fprintf(out,"%s",&line[iStart]);
+ }
+}
+
+/* The next function finds the template file and opens it, returning
+** a pointer to the opened file. */
+PRIVATE FILE *tplt_open(lemp)
+struct lemon *lemp;
+{
+
+ char buf[1000];
+ FILE *in;
+ char *tpltname;
+ char *tpltname_alloc = NULL;
+ char *cp;
+
+ cp = strrchr(lemp->filename,'.');
+ if( cp ){
+ sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
+ }else{
+ sprintf(buf,"%s.lt",lemp->filename);
+ }
+ if( access(buf,004)==0 ){
+ tpltname = buf;
+ }else if( access(lemp->tmplname,004)==0 ){
+ tpltname = lemp->tmplname;
+ }else{
+ tpltname = tpltname_alloc = pathsearch(lemp->argv0,lemp->tmplname,0);
+ }
+ if( tpltname==0 ){
+ fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
+ lemp->tmplname);
+ lemp->errorcnt++;
+ return 0;
+ }
+ in = fopen(tpltname,"r");
+ if( in==0 ){
+ fprintf(stderr,"Can't open the template file \"%s\".\n",tpltname);
+ lemp->errorcnt++;
+ }
+ if (tpltname_alloc) free(tpltname_alloc);
+ return in;
+}
+
+/* Print a string to the file and keep the linenumber up to date */
+PRIVATE void tplt_print(out,lemp,str,strln,lineno)
+FILE *out;
+struct lemon *lemp;
+char *str;
+int strln;
+int *lineno;
+{
+ if( str==0 ) return;
+ fprintf(out,"#line %d \"%s\"\n",strln,lemp->filename); (*lineno)++;
+ while( *str ){
+ if( *str=='\n' ) (*lineno)++;
+ putc(*str,out);
+ str++;
+ }
+ fprintf(out,"\n#line %d \"%s\"\n",*lineno+2,lemp->outname); (*lineno)+=2;
+ return;
+}
+
+/*
+** The following routine emits code for the destructor for the
+** symbol sp
+*/
+PRIVATE void emit_destructor_code(out,sp,lemp,lineno)
+FILE *out;
+struct symbol *sp;
+struct lemon *lemp;
+int *lineno;
+{
+ char *cp = 0;
+
+ int linecnt = 0;
+ if( sp->type==TERMINAL ){
+ cp = lemp->tokendest;
+ if( cp==0 ) return;
+ fprintf(out,"#line %d \"%s\"\n{",lemp->tokendestln,lemp->filename);
+ }else if( sp->destructor ){
+ cp = sp->destructor;
+ fprintf(out,"#line %d \"%s\"\n{",sp->destructorln,lemp->filename);
+ }else{
+ cp = lemp->vardest;
+ if( cp==0 ) return;
+ fprintf(out,"#line %d \"%s\"\n{",lemp->vardestln,lemp->filename);
+ }
+ for(; *cp; cp++){
+ if( *cp=='$' && cp[1]=='$' ){
+ fprintf(out,"(yypminor->yy%d)",sp->dtnum);
+ cp++;
+ continue;
+ }
+ if( *cp=='\n' ) linecnt++;
+ fputc(*cp,out);
+ }
+ (*lineno) += 3 + linecnt;
+ fprintf(out,"}\n#line %d \"%s\"\n",*lineno,lemp->outname);
+ return;
+}
+
+/*
+** Return TRUE (non-zero) if the given symbol has a destructor.
+*/
+PRIVATE int has_destructor(sp, lemp)
+struct symbol *sp;
+struct lemon *lemp;
+{
+ int ret;
+ if( sp->type==TERMINAL ){
+ ret = lemp->tokendest!=0;
+ }else{
+ ret = lemp->vardest!=0 || sp->destructor!=0;
+ }
+ return ret;
+}
+
+/*
+** Generate code which executes when the rule "rp" is reduced. Write
+** the code to "out". Make sure lineno stays up-to-date.
+*/
+PRIVATE void emit_code(out,rp,lemp,lineno)
+FILE *out;
+struct rule *rp;
+struct lemon *lemp;
+int *lineno;
+{
+ char *cp, *xp;
+ int linecnt = 0;
+ int i;
+ char lhsused = 0; /* True if the LHS element has been used */
+ char used[MAXRHS]; /* True for each RHS element which is used */
+
+ for(i=0; i<rp->nrhs; i++) used[i] = 0;
+ lhsused = 0;
+
+ /* Generate code to do the reduce action */
+ if( rp->code ){
+ fprintf(out,"#line %d \"%s\"\n{",rp->line,lemp->filename);
+ for(cp=rp->code; *cp; cp++){
+ if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){
+ char saved;
+ for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++);
+ saved = *xp;
+ *xp = 0;
+ if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
+ fprintf(out,"yygotominor.yy%d",rp->lhs->dtnum);
+ cp = xp;
+ lhsused = 1;
+ }else{
+ for(i=0; i<rp->nrhs; i++){
+ if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
+ fprintf(out,"yymsp[%d].minor.yy%d",i-rp->nrhs+1,rp->rhs[i]->dtnum);
+ cp = xp;
+ used[i] = 1;
+ break;
+ }
+ }
+ }
+ *xp = saved;
+ }
+ if( *cp=='\n' ) linecnt++;
+ fputc(*cp,out);
+ } /* End loop */
+ (*lineno) += 3 + linecnt;
+ fprintf(out,"}\n#line %d \"%s\"\n",*lineno,lemp->outname);
+ } /* End if( rp->code ) */
+
+ /* Check to make sure the LHS has been used */
+ if( rp->lhsalias && !lhsused ){
+ ErrorMsg(lemp->filename,rp->ruleline,
+ "Label \"%s\" for \"%s(%s)\" is never used.",
+ rp->lhsalias,rp->lhs->name,rp->lhsalias);
+ lemp->errorcnt++;
+ }
+
+ /* Generate destructor code for RHS symbols which are not used in the
+ ** reduce code */
+ for(i=0; i<rp->nrhs; i++){
+ if( rp->rhsalias[i] && !used[i] ){
+ ErrorMsg(lemp->filename,rp->ruleline,
+ "Label %s for \"%s(%s)\" is never used.",
+ rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
+ lemp->errorcnt++;
+ }else if( rp->rhsalias[i]==0 ){
+ if( has_destructor(rp->rhs[i],lemp) ){
+ fprintf(out," yy_destructor(%d,&yymsp[%d].minor);\n",
+ rp->rhs[i]->index,i-rp->nrhs+1); (*lineno)++;
+ }else{
+ fprintf(out," /* No destructor defined for %s */\n",
+ rp->rhs[i]->name);
+ (*lineno)++;
+ }
+ }
+ }
+ return;
+}
+
+/*
+** Print the definition of the union used for the parser's data stack.
+** This union contains fields for every possible data type for tokens
+** and nonterminals. In the process of computing and printing this
+** union, also set the ".dtnum" field of every terminal and nonterminal
+** symbol.
+*/
+PRIVATE void print_stack_union(out,lemp,plineno,mhflag)
+FILE *out; /* The output stream */
+struct lemon *lemp; /* The main info structure for this parser */
+int *plineno; /* Pointer to the line number */
+int mhflag; /* True if generating makeheaders output */
+{
+ int lineno; /* The line number of the output */
+ char **types; /* A hash table of datatypes */
+ int arraysize; /* Size of the "types" array */
+ int maxdtlength; /* Maximum length of any ".datatype" field. */
+ char *stddt; /* Standardized name for a datatype */
+ int i,j; /* Loop counters */
+ int hash; /* For hashing the name of a type */
+ char *name; /* Name of the parser */
+
+ /* Allocate and initialize types[] and allocate stddt[] */
+ arraysize = lemp->nsymbol * 2;
+ types = (char**)malloc( arraysize * sizeof(char*) );
+ for(i=0; i<arraysize; i++) types[i] = 0;
+ maxdtlength = 0;
+ if( lemp->vartype ){
+ maxdtlength = strlen(lemp->vartype);
+ }
+ for(i=0; i<lemp->nsymbol; i++){
+ int len;
+ struct symbol *sp = lemp->symbols[i];
+ if( sp->datatype==0 ) continue;
+ len = strlen(sp->datatype);
+ if( len>maxdtlength ) maxdtlength = len;
+ }
+ stddt = (char*)malloc( maxdtlength*2 + 1 );
+ if( types==0 || stddt==0 ){
+ fprintf(stderr,"Out of memory.\n");
+ exit(1);
+ }
+
+ /* Build a hash table of datatypes. The ".dtnum" field of each symbol
+ ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is
+ ** used for terminal symbols. If there is no %default_type defined then
+ ** 0 is also used as the .dtnum value for nonterminals which do not specify
+ ** a datatype using the %type directive.
+ */
+ for(i=0; i<lemp->nsymbol; i++){
+ struct symbol *sp = lemp->symbols[i];
+ char *cp;
+ if( sp==lemp->errsym ){
+ sp->dtnum = arraysize+1;
+ continue;
+ }
+ if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){
+ sp->dtnum = 0;
+ continue;
+ }
+ cp = sp->datatype;
+ if( cp==0 ) cp = lemp->vartype;
+ j = 0;
+ while( isspace(*cp) ) cp++;
+ while( *cp ) stddt[j++] = *cp++;
+ while( j>0 && isspace(stddt[j-1]) ) j--;
+ stddt[j] = 0;
+ hash = 0;
+ for(j=0; stddt[j]; j++){
+ hash = (unsigned int)hash*53u + (unsigned int) stddt[j];
+ }
+ hash = (hash & 0x7fffffff)%arraysize;
+ while( types[hash] ){
+ if( strcmp(types[hash],stddt)==0 ){
+ sp->dtnum = hash + 1;
+ break;
+ }
+ hash++;
+ if( hash>=arraysize ) hash = 0;
+ }
+ if( types[hash]==0 ){
+ sp->dtnum = hash + 1;
+ types[hash] = (char*)malloc( strlen(stddt)+1 );
+ if( types[hash]==0 ){
+ fprintf(stderr,"Out of memory.\n");
+ exit(1);
+ }
+ strcpy(types[hash],stddt);
+ }
+ }
+
+ /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
+ name = lemp->name ? lemp->name : "Parse";
+ lineno = *plineno;
+ if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; }
+ fprintf(out,"#define %sTOKENTYPE %s\n",name,
+ lemp->tokentype?lemp->tokentype:"void*"); lineno++;
+ if( mhflag ){ fprintf(out,"#endif\n"); lineno++; }
+ fprintf(out,"typedef union {\n"); lineno++;
+ fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++;
+ for(i=0; i<arraysize; i++){
+ if( types[i]==0 ) continue;
+ fprintf(out," %s yy%d;\n",types[i],i+1); lineno++;
+ free(types[i]);
+ }
+ fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
+ free(stddt);
+ free(types);
+ fprintf(out,"} YYMINORTYPE;\n"); lineno++;
+ *plineno = lineno;
+}
+
+/*
+** Return the name of a C datatype able to represent values between
+** lwr and upr, inclusive.
+*/
+static const char *minimum_size_type(int lwr, int upr){
+ if( lwr>=0 ){
+ if( upr<=255 ){
+ return "unsigned char";
+ }else if( upr<65535 ){
+ return "unsigned short int";
+ }else{
+ return "unsigned int";
+ }
+ }else if( lwr>=-127 && upr<=127 ){
+ return "signed char";
+ }else if( lwr>=-32767 && upr<32767 ){
+ return "short";
+ }else{
+ return "int";
+ }
+}
+
+/*
+** Each state contains a set of token transaction and a set of
+** nonterminal transactions. Each of these sets makes an instance
+** of the following structure. An array of these structures is used
+** to order the creation of entries in the yy_action[] table.
+*/
+struct axset {
+ struct state *stp; /* A pointer to a state */
+ int isTkn; /* True to use tokens. False for non-terminals */
+ int nAction; /* Number of actions */
+};
+
+/*
+** Compare to axset structures for sorting purposes
+*/
+static int axset_compare(const void *a, const void *b){
+ struct axset *p1 = (struct axset*)a;
+ struct axset *p2 = (struct axset*)b;
+ return p2->nAction - p1->nAction;
+}
+
+/* Generate C source code for the parser */
+void ReportTable(lemp, mhflag)
+struct lemon *lemp;
+int mhflag; /* Output in makeheaders format if true */
+{
+ FILE *out, *in;
+ char line[LINESIZE];
+ int lineno;
+ struct state *stp;
+ struct action *ap;
+ struct rule *rp;
+ struct acttab *pActtab;
+ int i, j, n;
+ int mnTknOfst, mxTknOfst;
+ int mnNtOfst, mxNtOfst;
+ struct axset *ax;
+ char *name;
+
+ in = tplt_open(lemp);
+ if( in==0 ) return;
+ out = file_open(lemp,".c","w");
+ if( out==0 ){
+ fclose(in);
+ return;
+ }
+ lineno = 1;
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate the include code, if any */
+ tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno);
+ if( mhflag ){
+ name = file_makename(lemp, ".h");
+ fprintf(out,"#include \"%s\"\n", name); lineno++;
+ free(name);
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate #defines for all tokens */
+ if( mhflag ){
+ char *prefix;
+ fprintf(out,"#if INTERFACE\n"); lineno++;
+ if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
+ else prefix = "";
+ for(i=1; i<lemp->nterminal; i++){
+ fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+ lineno++;
+ }
+ fprintf(out,"#endif\n"); lineno++;
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate the defines */
+ fprintf(out,"/* \001 */\n");
+ fprintf(out,"#define YYCODETYPE %s\n",
+ minimum_size_type(0, lemp->nsymbol+5)); lineno++;
+ fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++;
+ fprintf(out,"#define YYACTIONTYPE %s\n",
+ minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++;
+ print_stack_union(out,lemp,&lineno,mhflag);
+ if( lemp->stacksize ){
+ if( atoi(lemp->stacksize)<=0 ){
+ ErrorMsg(lemp->filename,0,
+"Illegal stack size: [%s]. The stack size should be an integer constant.",
+ lemp->stacksize);
+ lemp->errorcnt++;
+ lemp->stacksize = "100";
+ }
+ fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++;
+ }else{
+ fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++;
+ }
+ if( mhflag ){
+ fprintf(out,"#if INTERFACE\n"); lineno++;
+ }
+ name = lemp->name ? lemp->name : "Parse";
+ if( lemp->arg && lemp->arg[0] ){
+ i = strlen(lemp->arg);
+ while( i>=1 && isspace(lemp->arg[i-1]) ) i--;
+ while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--;
+ fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++;
+ fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++;
+ fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n",
+ name,lemp->arg,&lemp->arg[i]); lineno++;
+ fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n",
+ name,&lemp->arg[i],&lemp->arg[i]); lineno++;
+ }else{
+ fprintf(out,"#define %sARG_SDECL\n",name); lineno++;
+ fprintf(out,"#define %sARG_PDECL\n",name); lineno++;
+ fprintf(out,"#define %sARG_FETCH\n",name); lineno++;
+ fprintf(out,"#define %sARG_STORE\n",name); lineno++;
+ }
+ if( mhflag ){
+ fprintf(out,"#endif\n"); lineno++;
+ }
+ fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++;
+ fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
+ fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
+ fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+ if( lemp->has_fallback ){
+ fprintf(out,"#define YYFALLBACK 1\n"); lineno++;
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate the action table and its associates:
+ **
+ ** yy_action[] A single table containing all actions.
+ ** yy_lookahead[] A table containing the lookahead for each entry in
+ ** yy_action. Used to detect hash collisions.
+ ** yy_shift_ofst[] For each state, the offset into yy_action for
+ ** shifting terminals.
+ ** yy_reduce_ofst[] For each state, the offset into yy_action for
+ ** shifting non-terminals after a reduce.
+ ** yy_default[] Default action for each state.
+ */
+
+ /* Compute the actions on all states and count them up */
+ ax = malloc( sizeof(ax[0])*lemp->nstate*2 );
+ if( ax==0 ){
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ stp->nTknAct = stp->nNtAct = 0;
+ stp->iDflt = lemp->nstate + lemp->nrule;
+ stp->iTknOfst = NO_OFFSET;
+ stp->iNtOfst = NO_OFFSET;
+ for(ap=stp->ap; ap; ap=ap->next){
+ if( compute_action(lemp,ap)>=0 ){
+ if( ap->sp->index<lemp->nterminal ){
+ stp->nTknAct++;
+ }else if( ap->sp->index<lemp->nsymbol ){
+ stp->nNtAct++;
+ }else{
+ stp->iDflt = compute_action(lemp, ap);
+ }
+ }
+ }
+ ax[i*2].stp = stp;
+ ax[i*2].isTkn = 1;
+ ax[i*2].nAction = stp->nTknAct;
+ ax[i*2+1].stp = stp;
+ ax[i*2+1].isTkn = 0;
+ ax[i*2+1].nAction = stp->nNtAct;
+ }
+ mxTknOfst = mnTknOfst = 0;
+ mxNtOfst = mnNtOfst = 0;
+
+ /* Compute the action table. In order to try to keep the size of the
+ ** action table to a minimum, the heuristic of placing the largest action
+ ** sets first is used.
+ */
+ qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare);
+ pActtab = acttab_alloc();
+ for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){
+ stp = ax[i].stp;
+ if( ax[i].isTkn ){
+ for(ap=stp->ap; ap; ap=ap->next){
+ int action;
+ if( ap->sp->index>=lemp->nterminal ) continue;
+ action = compute_action(lemp, ap);
+ if( action<0 ) continue;
+ acttab_action(pActtab, ap->sp->index, action);
+ }
+ stp->iTknOfst = acttab_insert(pActtab);
+ if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst;
+ if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst;
+ }else{
+ for(ap=stp->ap; ap; ap=ap->next){
+ int action;
+ if( ap->sp->index<lemp->nterminal ) continue;
+ if( ap->sp->index==lemp->nsymbol ) continue;
+ action = compute_action(lemp, ap);
+ if( action<0 ) continue;
+ acttab_action(pActtab, ap->sp->index, action);
+ }
+ stp->iNtOfst = acttab_insert(pActtab);
+ if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst;
+ if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst;
+ }
+ }
+ free(ax);
+
+ /* Output the yy_action table */
+ fprintf(out,"static YYACTIONTYPE yy_action[] = {\n"); lineno++;
+ n = acttab_size(pActtab);
+ for(i=j=0; i<n; i++){
+ int action = acttab_yyaction(pActtab, i);
+ if( action<0 ) action = lemp->nsymbol + lemp->nrule + 2;
+ if( j==0 ) fprintf(out," /* %5d */ ", i);
+ fprintf(out, " %4d,", action);
+ if( j==9 || i==n-1 ){
+ fprintf(out, "\n"); lineno++;
+ j = 0;
+ }else{
+ j++;
+ }
+ }
+ fprintf(out, "};\n"); lineno++;
+
+ /* Output the yy_lookahead table */
+ fprintf(out,"static YYCODETYPE yy_lookahead[] = {\n"); lineno++;
+ for(i=j=0; i<n; i++){
+ int la = acttab_yylookahead(pActtab, i);
+ if( la<0 ) la = lemp->nsymbol;
+ if( j==0 ) fprintf(out," /* %5d */ ", i);
+ fprintf(out, " %4d,", la);
+ if( j==9 || i==n-1 ){
+ fprintf(out, "\n"); lineno++;
+ j = 0;
+ }else{
+ j++;
+ }
+ }
+ fprintf(out, "};\n"); lineno++;
+
+ /* Output the yy_shift_ofst[] table */
+ fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
+ fprintf(out, "static %s yy_shift_ofst[] = {\n",
+ minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
+ n = lemp->nstate;
+ for(i=j=0; i<n; i++){
+ int ofst;
+ stp = lemp->sorted[i];
+ ofst = stp->iTknOfst;
+ if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1;
+ if( j==0 ) fprintf(out," /* %5d */ ", i);
+ fprintf(out, " %4d,", ofst);
+ if( j==9 || i==n-1 ){
+ fprintf(out, "\n"); lineno++;
+ j = 0;
+ }else{
+ j++;
+ }
+ }
+ fprintf(out, "};\n"); lineno++;
+
+ /* Output the yy_reduce_ofst[] table */
+ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
+ fprintf(out, "static %s yy_reduce_ofst[] = {\n",
+ minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
+ n = lemp->nstate;
+ for(i=j=0; i<n; i++){
+ int ofst;
+ stp = lemp->sorted[i];
+ ofst = stp->iNtOfst;
+ if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1;
+ if( j==0 ) fprintf(out," /* %5d */ ", i);
+ fprintf(out, " %4d,", ofst);
+ if( j==9 || i==n-1 ){
+ fprintf(out, "\n"); lineno++;
+ j = 0;
+ }else{
+ j++;
+ }
+ }
+ fprintf(out, "};\n"); lineno++;
+
+ /* Output the default action table */
+ fprintf(out, "static YYACTIONTYPE yy_default[] = {\n"); lineno++;
+ n = lemp->nstate;
+ for(i=j=0; i<n; i++){
+ stp = lemp->sorted[i];
+ if( j==0 ) fprintf(out," /* %5d */ ", i);
+ fprintf(out, " %4d,", stp->iDflt);
+ if( j==9 || i==n-1 ){
+ fprintf(out, "\n"); lineno++;
+ j = 0;
+ }else{
+ j++;
+ }
+ }
+ fprintf(out, "};\n"); lineno++;
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate the table of fallback tokens.
+ */
+ if( lemp->has_fallback ){
+ for(i=0; i<lemp->nterminal; i++){
+ struct symbol *p = lemp->symbols[i];
+ if( p->fallback==0 ){
+ fprintf(out, " 0, /* %10s => nothing */\n", p->name);
+ }else{
+ fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index,
+ p->name, p->fallback->name);
+ }
+ lineno++;
+ }
+ }
+ tplt_xfer(lemp->name, in, out, &lineno);
+
+ /* Generate a table containing the symbolic name of every symbol
+ */
+ for(i=0; i<lemp->nsymbol; i++){
+ sprintf(line,"\"%s\",",lemp->symbols[i]->name);
+ fprintf(out," %-15s",line);
+ if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; }
+ }
+ if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate a table containing a text string that describes every
+ ** rule in the rule set of the grammer. This information is used
+ ** when tracing REDUCE actions.
+ */
+ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
+ assert( rp->index==i );
+ fprintf(out," /* %3d */ \"%s ::=", i, rp->lhs->name);
+ for(j=0; j<rp->nrhs; j++) fprintf(out," %s",rp->rhs[j]->name);
+ fprintf(out,"\",\n"); lineno++;
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate code which executes every time a symbol is popped from
+ ** the stack while processing errors or while destroying the parser.
+ ** (In other words, generate the %destructor actions)
+ */
+ if( lemp->tokendest ){
+ for(i=0; i<lemp->nsymbol; i++){
+ struct symbol *sp = lemp->symbols[i];
+ if( sp==0 || sp->type!=TERMINAL ) continue;
+ fprintf(out," case %d:\n",sp->index); lineno++;
+ }
+ for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++);
+ if( i<lemp->nsymbol ){
+ emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
+ fprintf(out," break;\n"); lineno++;
+ }
+ }
+ for(i=0; i<lemp->nsymbol; i++){
+ struct symbol *sp = lemp->symbols[i];
+ if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
+ fprintf(out," case %d:\n",sp->index); lineno++;
+ emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
+ fprintf(out," break;\n"); lineno++;
+ }
+ if( lemp->vardest ){
+ struct symbol *dflt_sp = 0;
+ for(i=0; i<lemp->nsymbol; i++){
+ struct symbol *sp = lemp->symbols[i];
+ if( sp==0 || sp->type==TERMINAL ||
+ sp->index<=0 || sp->destructor!=0 ) continue;
+ fprintf(out," case %d:\n",sp->index); lineno++;
+ dflt_sp = sp;
+ }
+ if( dflt_sp!=0 ){
+ emit_destructor_code(out,dflt_sp,lemp,&lineno);
+ fprintf(out," break;\n"); lineno++;
+ }
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate code which executes whenever the parser stack overflows */
+ tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate the table of rule information
+ **
+ ** Note: This code depends on the fact that rules are number
+ ** sequentually beginning with 0.
+ */
+ for(rp=lemp->rule; rp; rp=rp->next){
+ fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++;
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate code which execution during each REDUCE action */
+ for(rp=lemp->rule; rp; rp=rp->next){
+ fprintf(out," case %d:\n",rp->index); lineno++;
+ emit_code(out,rp,lemp,&lineno);
+ fprintf(out," break;\n"); lineno++;
+ }
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate code which executes if a parse fails */
+ tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno);
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate code which executes when a syntax error occurs */
+ tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno);
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Generate code which executes when the parser accepts its input */
+ tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno);
+ tplt_xfer(lemp->name,in,out,&lineno);
+
+ /* Append any addition code the user desires */
+ tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno);
+
+ fclose(in);
+ fclose(out);
+ return;
+}
+
+/* Generate a header file for the parser */
+void ReportHeader(lemp)
+struct lemon *lemp;
+{
+ FILE *out, *in;
+ char *prefix;
+ char line[LINESIZE];
+ char pattern[LINESIZE];
+ int i;
+
+ if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
+ else prefix = "";
+ in = file_open(lemp,".h","r");
+ if( in ){
+ for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){
+ sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+ if( strcmp(line,pattern) ) break;
+ }
+ fclose(in);
+ if( i==lemp->nterminal ){
+ /* No change in the file. Don't rewrite it. */
+ return;
+ }
+ }
+ out = file_open(lemp,".h","w");
+ if( out ){
+ for(i=1; i<lemp->nterminal; i++){
+ fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
+ }
+ fclose(out);
+ }
+ return;
+}
+
+/* Reduce the size of the action tables, if possible, by making use
+** of defaults.
+**
+** In this version, we take the most frequent REDUCE action and make
+** it the default. Only default a reduce if there are more than one.
+*/
+void CompressTables(lemp)
+struct lemon *lemp;
+{
+ struct state *stp;
+ struct action *ap, *ap2;
+ struct rule *rp, *rp2, *rbest;
+ int nbest, n;
+ int i;
+
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ nbest = 0;
+ rbest = 0;
+
+ for(ap=stp->ap; ap; ap=ap->next){
+ if( ap->type!=REDUCE ) continue;
+ rp = ap->x.rp;
+ if( rp==rbest ) continue;
+ n = 1;
+ for(ap2=ap->next; ap2; ap2=ap2->next){
+ if( ap2->type!=REDUCE ) continue;
+ rp2 = ap2->x.rp;
+ if( rp2==rbest ) continue;
+ if( rp2==rp ) n++;
+ }
+ if( n>nbest ){
+ nbest = n;
+ rbest = rp;
+ }
+ }
+
+ /* Do not make a default if the number of rules to default
+ ** is not at least 2 */
+ if( nbest<2 ) continue;
+
+
+ /* Combine matching REDUCE actions into a single default */
+ for(ap=stp->ap; ap; ap=ap->next){
+ if( ap->type==REDUCE && ap->x.rp==rbest ) break;
+ }
+ assert( ap );
+ ap->sp = Symbol_new("{default}");
+ for(ap=ap->next; ap; ap=ap->next){
+ if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED;
+ }
+ stp->ap = Action_sort(stp->ap);
+ }
+}
+
+/***************** From the file "set.c" ************************************/
+/*
+** Set manipulation routines for the LEMON parser generator.
+*/
+
+static int global_size = 0;
+
+/* Set the set size */
+void SetSize(n)
+int n;
+{
+ global_size = n+1;
+}
+
+/* Allocate a new set */
+char *SetNew(){
+ char *s;
+ int i;
+ s = (char*)malloc( global_size );
+ if( s==0 ){
+ memory_error();
+ }
+ for(i=0; i<global_size; i++) s[i] = 0;
+ return s;
+}
+
+/* Deallocate a set */
+void SetFree(s)
+char *s;
+{
+ free(s);
+}
+
+/* Add a new element to the set. Return TRUE if the element was added
+** and FALSE if it was already there. */
+int SetAdd(s,e)
+char *s;
+int e;
+{
+ int rv;
+ rv = s[e];
+ s[e] = 1;
+ return !rv;
+}
+
+/* Add every element of s2 to s1. Return TRUE if s1 changes. */
+int SetUnion(s1,s2)
+char *s1;
+char *s2;
+{
+ int i, progress;
+ progress = 0;
+ for(i=0; i<global_size; i++){
+ if( s2[i]==0 ) continue;
+ if( s1[i]==0 ){
+ progress = 1;
+ s1[i] = 1;
+ }
+ }
+ return progress;
+}
+/********************** From the file "table.c" ****************************/
+/*
+** All code in this file has been automatically generated
+** from a specification in the file
+** "table.q"
+** by the associative array code building program "aagen".
+** Do not edit this file! Instead, edit the specification
+** file, then rerun aagen.
+*/
+/*
+** Code for processing tables in the LEMON parser generator.
+*/
+
+PRIVATE int strhash(x)
+char *x;
+{
+ unsigned int h = 0;
+ while( *x) h = h*13u + (unsigned int) *(x++);
+ return h;
+}
+
+/* Works like strdup, sort of. Save a string in malloced memory, but
+** keep strings in a table so that the same string is not in more
+** than one place.
+*/
+char *Strsafe(y)
+char *y;
+{
+ char *z;
+
+ z = Strsafe_find(y);
+ if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){
+ strcpy(z,y);
+ Strsafe_insert(z);
+ }
+ MemoryCheck(z);
+ return z;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x1".
+*/
+struct s_x1 {
+ int size; /* The number of available slots. */
+ /* Must be a power of 2 greater than or */
+ /* equal to 1 */
+ int count; /* Number of currently slots filled */
+ struct s_x1node *tbl; /* The data stored here */
+ struct s_x1node **ht; /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x1".
+*/
+typedef struct s_x1node {
+ char *data; /* The data */
+ struct s_x1node *next; /* Next entry with the same hash */
+ struct s_x1node **from; /* Previous link */
+} x1node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x1 *x1a;
+
+/* Allocate a new associative array */
+void Strsafe_init(){
+ if( x1a ) return;
+ x1a = (struct s_x1*)malloc( sizeof(struct s_x1) );
+ if( x1a ){
+ x1a->size = 1024;
+ x1a->count = 0;
+ x1a->tbl = (x1node*)malloc(
+ (sizeof(x1node) + sizeof(x1node*))*1024 );
+ if( x1a->tbl==0 ){
+ free(x1a);
+ x1a = 0;
+ }else{
+ int i;
+ x1a->ht = (x1node**)&(x1a->tbl[1024]);
+ for(i=0; i<1024; i++) x1a->ht[i] = 0;
+ }
+ }
+}
+/* Insert a new record into the array. Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Strsafe_insert(data)
+char *data;
+{
+ x1node *np;
+ int h;
+ int ph;
+
+ if( x1a==0 ) return 0;
+ ph = strhash(data);
+ h = ph & (x1a->size-1);
+ np = x1a->ht[h];
+ while( np ){
+ if( strcmp(np->data,data)==0 ){
+ /* An existing entry with the same key is found. */
+ /* Fail because overwrite is not allows. */
+ return 0;
+ }
+ np = np->next;
+ }
+ if( x1a->count>=x1a->size ){
+ /* Need to make the hash table bigger */
+ int i,size;
+ struct s_x1 array;
+ array.size = size = x1a->size*2;
+ array.count = x1a->count;
+ array.tbl = (x1node*)malloc(
+ (sizeof(x1node) + sizeof(x1node*))*size );
+ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
+ array.ht = (x1node**)&(array.tbl[size]);
+ for(i=0; i<size; i++) array.ht[i] = 0;
+ for(i=0; i<x1a->count; i++){
+ x1node *oldnp, *newnp;
+ oldnp = &(x1a->tbl[i]);
+ h = strhash(oldnp->data) & (size-1);
+ newnp = &(array.tbl[i]);
+ if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+ newnp->next = array.ht[h];
+ newnp->data = oldnp->data;
+ newnp->from = &(array.ht[h]);
+ array.ht[h] = newnp;
+ }
+ free(x1a->tbl);
+ /* *x1a = array; *//* copy 'array' */
+ memcpy(x1a, &array, sizeof(array));
+ }
+ /* Insert the new data */
+ h = ph & (x1a->size-1);
+ np = &(x1a->tbl[x1a->count++]);
+ np->data = data;
+ if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next);
+ np->next = x1a->ht[h];
+ x1a->ht[h] = np;
+ np->from = &(x1a->ht[h]);
+ return 1;
+}
+
+/* Return a pointer to data assigned to the given key. Return NULL
+** if no such key. */
+char *Strsafe_find(key)
+char *key;
+{
+ int h;
+ x1node *np;
+
+ if( x1a==0 ) return 0;
+ h = strhash(key) & (x1a->size-1);
+ np = x1a->ht[h];
+ while( np ){
+ if( strcmp(np->data,key)==0 ) break;
+ np = np->next;
+ }
+ return np ? np->data : 0;
+}
+
+/* Return a pointer to the (terminal or nonterminal) symbol "x".
+** Create a new symbol if this is the first time "x" has been seen.
+*/
+struct symbol *Symbol_new(x)
+char *x;
+{
+ struct symbol *sp;
+
+ sp = Symbol_find(x);
+ if( sp==0 ){
+ sp = (struct symbol *)malloc( sizeof(struct symbol) );
+ MemoryCheck(sp);
+ sp->name = Strsafe(x);
+ sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
+ sp->rule = 0;
+ sp->fallback = 0;
+ sp->prec = -1;
+ sp->assoc = UNK;
+ sp->firstset = 0;
+ sp->lambda = Bo_FALSE;
+ sp->destructor = 0;
+ sp->datatype = 0;
+ Symbol_insert(sp,sp->name);
+ }
+ return sp;
+}
+
+/* Compare two symbols for working purposes
+**
+** Symbols that begin with upper case letters (terminals or tokens)
+** must sort before symbols that begin with lower case letters
+** (non-terminals). Other than that, the order does not matter.
+**
+** We find experimentally that leaving the symbols in their original
+** order (the order they appeared in the grammar file) gives the
+** smallest parser tables in SQLite.
+*/
+int Symbolcmpp(struct symbol **a, struct symbol **b){
+ int i1 = (**a).index + 10000000*((**a).name[0]>'Z');
+ int i2 = (**b).index + 10000000*((**b).name[0]>'Z');
+ return i1-i2;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x2".
+*/
+struct s_x2 {
+ int size; /* The number of available slots. */
+ /* Must be a power of 2 greater than or */
+ /* equal to 1 */
+ int count; /* Number of currently slots filled */
+ struct s_x2node *tbl; /* The data stored here */
+ struct s_x2node **ht; /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x2".
+*/
+typedef struct s_x2node {
+ struct symbol *data; /* The data */
+ char *key; /* The key */
+ struct s_x2node *next; /* Next entry with the same hash */
+ struct s_x2node **from; /* Previous link */
+} x2node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x2 *x2a;
+
+/* Allocate a new associative array */
+void Symbol_init(){
+ if( x2a ) return;
+ x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
+ if( x2a ){
+ x2a->size = 128;
+ x2a->count = 0;
+ x2a->tbl = (x2node*)malloc(
+ (sizeof(x2node) + sizeof(x2node*))*128 );
+ if( x2a->tbl==0 ){
+ free(x2a);
+ x2a = 0;
+ }else{
+ int i;
+ x2a->ht = (x2node**)&(x2a->tbl[128]);
+ for(i=0; i<128; i++) x2a->ht[i] = 0;
+ }
+ }
+}
+/* Insert a new record into the array. Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Symbol_insert(data,key)
+struct symbol *data;
+char *key;
+{
+ x2node *np;
+ int h;
+ int ph;
+
+ if( x2a==0 ) return 0;
+ ph = strhash(key);
+ h = ph & (x2a->size-1);
+ np = x2a->ht[h];
+ while( np ){
+ if( strcmp(np->key,key)==0 ){
+ /* An existing entry with the same key is found. */
+ /* Fail because overwrite is not allows. */
+ return 0;
+ }
+ np = np->next;
+ }
+ if( x2a->count>=x2a->size ){
+ /* Need to make the hash table bigger */
+ int i,size;
+ struct s_x2 array;
+ array.size = size = x2a->size*2;
+ array.count = x2a->count;
+ array.tbl = (x2node*)malloc(
+ (sizeof(x2node) + sizeof(x2node*))*size );
+ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
+ array.ht = (x2node**)&(array.tbl[size]);
+ for(i=0; i<size; i++) array.ht[i] = 0;
+ for(i=0; i<x2a->count; i++){
+ x2node *oldnp, *newnp;
+ oldnp = &(x2a->tbl[i]);
+ h = strhash(oldnp->key) & (size-1);
+ newnp = &(array.tbl[i]);
+ if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+ newnp->next = array.ht[h];
+ newnp->key = oldnp->key;
+ newnp->data = oldnp->data;
+ newnp->from = &(array.ht[h]);
+ array.ht[h] = newnp;
+ }
+ free(x2a->tbl);
+ /* *x2a = array; *//* copy 'array' */
+ memcpy(x2a, &array, sizeof(array));
+ }
+ /* Insert the new data */
+ h = ph & (x2a->size-1);
+ np = &(x2a->tbl[x2a->count++]);
+ np->key = key;
+ np->data = data;
+ if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next);
+ np->next = x2a->ht[h];
+ x2a->ht[h] = np;
+ np->from = &(x2a->ht[h]);
+ return 1;
+}
+
+/* Return a pointer to data assigned to the given key. Return NULL
+** if no such key. */
+struct symbol *Symbol_find(key)
+char *key;
+{
+ int h;
+ x2node *np;
+
+ if( x2a==0 ) return 0;
+ h = strhash(key) & (x2a->size-1);
+ np = x2a->ht[h];
+ while( np ){
+ if( strcmp(np->key,key)==0 ) break;
+ np = np->next;
+ }
+ return np ? np->data : 0;
+}
+
+/* Return the n-th data. Return NULL if n is out of range. */
+struct symbol *Symbol_Nth(n)
+int n;
+{
+ struct symbol *data;
+ if( x2a && n>0 && n<=x2a->count ){
+ data = x2a->tbl[n-1].data;
+ }else{
+ data = 0;
+ }
+ return data;
+}
+
+/* Return the size of the array */
+int Symbol_count()
+{
+ return x2a ? x2a->count : 0;
+}
+
+/* Return an array of pointers to all data in the table.
+** The array is obtained from malloc. Return NULL if memory allocation
+** problems, or if the array is empty. */
+struct symbol **Symbol_arrayof()
+{
+ struct symbol **array;
+ int i,size;
+ if( x2a==0 ) return 0;
+ size = x2a->count;
+ array = (struct symbol **)malloc( sizeof(struct symbol *)*size );
+ if( array ){
+ for(i=0; i<size; i++) array[i] = x2a->tbl[i].data;
+ }
+ return array;
+}
+
+/* Compare two configurations */
+int Configcmp(a,b)
+struct config *a;
+struct config *b;
+{
+ int x;
+ x = a->rp->index - b->rp->index;
+ if( x==0 ) x = a->dot - b->dot;
+ return x;
+}
+
+/* Compare two states */
+PRIVATE int statecmp(a,b)
+struct config *a;
+struct config *b;
+{
+ int rc;
+ for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){
+ rc = a->rp->index - b->rp->index;
+ if( rc==0 ) rc = a->dot - b->dot;
+ }
+ if( rc==0 ){
+ if( a ) rc = 1;
+ if( b ) rc = -1;
+ }
+ return rc;
+}
+
+/* Hash a state */
+PRIVATE int statehash(a)
+struct config *a;
+{
+ unsigned int h=0;
+ while( a ){
+ h = h*571u + (unsigned int)a->rp->index*37u + (unsigned int)a->dot;
+ a = a->bp;
+ }
+ return h;
+}
+
+/* Allocate a new state structure */
+struct state *State_new()
+{
+ struct state *new;
+ new = (struct state *)malloc( sizeof(struct state) );
+ MemoryCheck(new);
+ return new;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x3".
+*/
+struct s_x3 {
+ int size; /* The number of available slots. */
+ /* Must be a power of 2 greater than or */
+ /* equal to 1 */
+ int count; /* Number of currently slots filled */
+ struct s_x3node *tbl; /* The data stored here */
+ struct s_x3node **ht; /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x3".
+*/
+typedef struct s_x3node {
+ struct state *data; /* The data */
+ struct config *key; /* The key */
+ struct s_x3node *next; /* Next entry with the same hash */
+ struct s_x3node **from; /* Previous link */
+} x3node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x3 *x3a;
+
+/* Allocate a new associative array */
+void State_init(){
+ if( x3a ) return;
+ x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
+ if( x3a ){
+ x3a->size = 128;
+ x3a->count = 0;
+ x3a->tbl = (x3node*)malloc(
+ (sizeof(x3node) + sizeof(x3node*))*128 );
+ if( x3a->tbl==0 ){
+ free(x3a);
+ x3a = 0;
+ }else{
+ int i;
+ x3a->ht = (x3node**)&(x3a->tbl[128]);
+ for(i=0; i<128; i++) x3a->ht[i] = 0;
+ }
+ }
+}
+/* Insert a new record into the array. Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int State_insert(data,key)
+struct state *data;
+struct config *key;
+{
+ x3node *np;
+ int h;
+ int ph;
+
+ if( x3a==0 ) return 0;
+ ph = statehash(key);
+ h = ph & (x3a->size-1);
+ np = x3a->ht[h];
+ while( np ){
+ if( statecmp(np->key,key)==0 ){
+ /* An existing entry with the same key is found. */
+ /* Fail because overwrite is not allows. */
+ return 0;
+ }
+ np = np->next;
+ }
+ if( x3a->count>=x3a->size ){
+ /* Need to make the hash table bigger */
+ int i,size;
+ struct s_x3 array;
+ array.size = size = x3a->size*2;
+ array.count = x3a->count;
+ array.tbl = (x3node*)malloc(
+ (sizeof(x3node) + sizeof(x3node*))*size );
+ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
+ array.ht = (x3node**)&(array.tbl[size]);
+ for(i=0; i<size; i++) array.ht[i] = 0;
+ for(i=0; i<x3a->count; i++){
+ x3node *oldnp, *newnp;
+ oldnp = &(x3a->tbl[i]);
+ h = statehash(oldnp->key) & (size-1);
+ newnp = &(array.tbl[i]);
+ if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+ newnp->next = array.ht[h];
+ newnp->key = oldnp->key;
+ newnp->data = oldnp->data;
+ newnp->from = &(array.ht[h]);
+ array.ht[h] = newnp;
+ }
+ free(x3a->tbl);
+ /* *x3a = array; *//* copy 'array' */
+ memcpy(x3a, &array, sizeof(array));
+ }
+ /* Insert the new data */
+ h = ph & (x3a->size-1);
+ np = &(x3a->tbl[x3a->count++]);
+ np->key = key;
+ np->data = data;
+ if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next);
+ np->next = x3a->ht[h];
+ x3a->ht[h] = np;
+ np->from = &(x3a->ht[h]);
+ return 1;
+}
+
+/* Return a pointer to data assigned to the given key. Return NULL
+** if no such key. */
+struct state *State_find(key)
+struct config *key;
+{
+ int h;
+ x3node *np;
+
+ if( x3a==0 ) return 0;
+ h = statehash(key) & (x3a->size-1);
+ np = x3a->ht[h];
+ while( np ){
+ if( statecmp(np->key,key)==0 ) break;
+ np = np->next;
+ }
+ return np ? np->data : 0;
+}
+
+/* Return the size of the array */
+int State_count(void)
+{
+ return x3a ? x3a->count : 0;
+}
+
+/* Return an array of pointers to all data in the table.
+** The array is obtained from malloc. Return NULL if memory allocation
+** problems, or if the array is empty. */
+struct state **State_arrayof()
+{
+ struct state **array;
+ int i,size;
+ if( x3a==0 ) return 0;
+ size = x3a->count;
+ array = (struct state **)malloc( sizeof(struct state *)*size );
+ if( array ){
+ for(i=0; i<size; i++) array[i] = x3a->tbl[i].data;
+ }
+ return array;
+}
+
+/* Hash a configuration */
+PRIVATE int confighash(a)
+struct config *a;
+{
+ int h=0;
+ h = h*571 + a->rp->index*37 + a->dot;
+ return h;
+}
+
+/* There is one instance of the following structure for each
+** associative array of type "x4".
+*/
+struct s_x4 {
+ int size; /* The number of available slots. */
+ /* Must be a power of 2 greater than or */
+ /* equal to 1 */
+ int count; /* Number of currently slots filled */
+ struct s_x4node *tbl; /* The data stored here */
+ struct s_x4node **ht; /* Hash table for lookups */
+};
+
+/* There is one instance of this structure for every data element
+** in an associative array of type "x4".
+*/
+typedef struct s_x4node {
+ struct config *data; /* The data */
+ struct s_x4node *next; /* Next entry with the same hash */
+ struct s_x4node **from; /* Previous link */
+} x4node;
+
+/* There is only one instance of the array, which is the following */
+static struct s_x4 *x4a;
+
+/* Allocate a new associative array */
+void Configtable_init(){
+ if( x4a ) return;
+ x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
+ if( x4a ){
+ x4a->size = 64;
+ x4a->count = 0;
+ x4a->tbl = (x4node*)malloc(
+ (sizeof(x4node) + sizeof(x4node*))*64 );
+ if( x4a->tbl==0 ){
+ free(x4a);
+ x4a = 0;
+ }else{
+ int i;
+ x4a->ht = (x4node**)&(x4a->tbl[64]);
+ for(i=0; i<64; i++) x4a->ht[i] = 0;
+ }
+ }
+}
+/* Insert a new record into the array. Return TRUE if successful.
+** Prior data with the same key is NOT overwritten */
+int Configtable_insert(data)
+struct config *data;
+{
+ x4node *np;
+ int h;
+ int ph;
+
+ if( x4a==0 ) return 0;
+ ph = confighash(data);
+ h = ph & (x4a->size-1);
+ np = x4a->ht[h];
+ while( np ){
+ if( Configcmp(np->data,data)==0 ){
+ /* An existing entry with the same key is found. */
+ /* Fail because overwrite is not allows. */
+ return 0;
+ }
+ np = np->next;
+ }
+ if( x4a->count>=x4a->size ){
+ /* Need to make the hash table bigger */
+ int i,size;
+ struct s_x4 array;
+ array.size = size = x4a->size*2;
+ array.count = x4a->count;
+ array.tbl = (x4node*)malloc(
+ (sizeof(x4node) + sizeof(x4node*))*size );
+ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
+ array.ht = (x4node**)&(array.tbl[size]);
+ for(i=0; i<size; i++) array.ht[i] = 0;
+ for(i=0; i<x4a->count; i++){
+ x4node *oldnp, *newnp;
+ oldnp = &(x4a->tbl[i]);
+ h = confighash(oldnp->data) & (size-1);
+ newnp = &(array.tbl[i]);
+ if( array.ht[h] ) array.ht[h]->from = &(newnp->next);
+ newnp->next = array.ht[h];
+ newnp->data = oldnp->data;
+ newnp->from = &(array.ht[h]);
+ array.ht[h] = newnp;
+ }
+ free(x4a->tbl);
+ /* *x4a = array; *//* copy 'array' */
+ memcpy(x4a, &array, sizeof(array));
+ }
+ /* Insert the new data */
+ h = ph & (x4a->size-1);
+ np = &(x4a->tbl[x4a->count++]);
+ np->data = data;
+ if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next);
+ np->next = x4a->ht[h];
+ x4a->ht[h] = np;
+ np->from = &(x4a->ht[h]);
+ return 1;
+}
+
+/* Return a pointer to data assigned to the given key. Return NULL
+** if no such key. */
+struct config *Configtable_find(key)
+struct config *key;
+{
+ int h;
+ x4node *np;
+
+ if( x4a==0 ) return 0;
+ h = confighash(key) & (x4a->size-1);
+ np = x4a->ht[h];
+ while( np ){
+ if( Configcmp(np->data,key)==0 ) break;
+ np = np->next;
+ }
+ return np ? np->data : 0;
+}
+
+/* Remove all data from the table. Pass each data to the function "f"
+** as it is removed. ("f" may be null to avoid this step.) */
+void Configtable_clear(f)
+int(*f)(/* struct config * */);
+{
+ int i;
+ if( x4a==0 || x4a->count==0 ) return;
+ if( f ) for(i=0; i<x4a->count; i++) (*f)(x4a->tbl[i].data);
+ for(i=0; i<x4a->size; i++) x4a->ht[i] = 0;
+ x4a->count = 0;
+ return;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/lempar.c b/data/lighttpd/lighttpd-1.4.53/src/lempar.c
new file mode 100644
index 000000000..309967c49
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/lempar.c
@@ -0,0 +1,699 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+*/
+/* First off, code is include which follows the "include" declaration
+** in the input file. */
+#include "first.h"
+#include <stdio.h>
+%%
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+%%
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** ParseTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
+** This is typically a union of many types, one of
+** which is ParseTOKENTYPE. The entry in the union
+** for base tokens is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** ParseARG_SDECL A static variable declaration for the %extra_argument
+** ParseARG_PDECL A parameter declaration for the %extra_argument
+** ParseARG_STORE Code to store %extra_argument into yypParser
+** ParseARG_FETCH Code to extract %extra_argument from yypParser
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+*/
+%%
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+/* Next are that tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
+**
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
+**
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
+**
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+** yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+*/
+%%
+#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
+
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammer, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+%%
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+ int stateno; /* The state-number */
+ int major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ int yyidx; /* Index of top element in stack */
+ int yyerrcnt; /* Shifts left before out of the error */
+ ParseARG_SDECL /* A place to hold %extra_argument */
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = NULL;
+static char *yyTracePrompt = NULL;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+#if 0
+void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *yyTokenName[] = {
+%%
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *yyRuleName[] = {
+%%
+};
+#endif /* NDEBUG */
+
+/*
+** This function returns the symbolic name associated with a token
+** value.
+*/
+#if 0
+const char *ParseTokenName(int tokenType){
+#ifndef NDEBUG
+ if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
+ return yyTokenName[tokenType];
+ }else{
+ return "Unknown";
+ }
+#else
+ return "";
+#endif
+}
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to Parse and ParseFree.
+*/
+void *ParseAlloc(void *(*mallocProc)(size_t)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ if( pParser ){
+ pParser->yyidx = -1;
+ }
+ return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are not used
+ ** inside the C code.
+ */
+%%
+ default: break; /* If no destructor action specified: do nothing */
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos;
+
+ if( pParser->yyidx<0 ) return 0;
+ yytos = &pParser->yystack[pParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE && pParser->yyidx>=0 ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yymajor = yytos->major;
+ yy_destructor( yymajor, &yytos->minor);
+ pParser->yyidx--;
+ return yymajor;
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from ParseAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
+*/
+void ParseFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+ if( pParser==NULL ) return;
+ while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ int iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+
+ /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
+ i = yy_shift_ofst[stateno];
+ if( i==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ if( iLookAhead==YYNOCODE ){
+ return YY_NO_ACTION;
+ }
+ i += iLookAhead;
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+ int iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+ yyParser *pParser, /* The parser */
+ int iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+
+ i = yy_reduce_ofst[stateno];
+ if( i==YY_REDUCE_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ if( iLookAhead==YYNOCODE ){
+ return YY_NO_ACTION;
+ }
+ i += iLookAhead;
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yyidx++;
+ if( yypParser->yyidx>=YYSTACKDEPTH ){
+ ParseARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
+ return;
+ }
+ yytos = &yypParser->yystack[yypParser->yyidx];
+ yytos->stateno = yyNewState;
+ yytos->major = yyMajor;
+ yytos->minor = *yypMinor;
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+%%
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ ParseARG_FETCH;
+ yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE ) {
+ if (yyruleno>=0
+ && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
+ } else {
+ return; /*(should not happen)*/
+ }
+ }
+#endif /* NDEBUG */
+
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+%%
+ };
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ yypParser->yyidx -= yysize;
+ yyact = yy_find_reduce_action(yypParser,yygoto);
+ if( yyact < YYNSTATE ){
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ ParseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
+){
+ ParseARG_FETCH;
+ UNUSED(yymajor);
+ UNUSED(yyminor);
+#define TOKEN (yyminor.yy0)
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ ParseARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "ParseAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void Parse(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ ParseTOKENTYPE yyminor /* The value for the token */
+ ParseARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ int yyact; /* The parser action. */
+ int yyendofinput; /* True if we are at the end of input */
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+ yyParser *yypParser; /* The parser */
+
+ /* (re)initialize the parser, if necessary */
+ yypParser = (yyParser*)yyp;
+ if( yypParser->yyidx<0 ){
+ if( yymajor==0 ) return;
+ yypParser->yyidx = 0;
+ yypParser->yyerrcnt = -1;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+ }
+ yyminorunion.yy0 = yyminor;
+ yyendofinput = (yymajor==0);
+ ParseARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,yymajor);
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yypParser->yyerrcnt--;
+ if( yyendofinput && yypParser->yyidx>=0 ){
+ yymajor = 0;
+ }else{
+ yymajor = YYNOCODE;
+ }
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
+ }else if( yyact == YY_ERROR_ACTION ){
+ int yymx;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yymx = yypParser->yystack[yypParser->yyidx].major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while(
+ yypParser->yyidx >= 0 &&
+ yymx != YYERRORSYMBOL &&
+ (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yyidx < 0 || yymajor==0 ){
+ yy_destructor(yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ }
+ }
+ yypParser->yyerrcnt = 3;
+ yyerrorhit = 1;
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yypParser->yyerrcnt = 3;
+ yy_destructor(yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+ }
+ yymajor = YYNOCODE;
+#endif
+ }else{
+ yy_accept(yypParser);
+ yymajor = YYNOCODE;
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ return;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c b/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c
new file mode 100644
index 000000000..189c1b92a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c
@@ -0,0 +1,167 @@
+#include "first.h"
+
+/**
+ * angel process for lighttpd
+ *
+ * the purpose is the run as root all the time and handle:
+ * - restart on crash
+ * - spawn on HUP to allow graceful restart
+ * - ...
+ *
+ * it has to stay safe and small to be trustable
+ */
+
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+
+#define BINPATH SBIN_DIR"/lighttpd"
+
+static siginfo_t last_sigterm_info;
+static siginfo_t last_sighup_info;
+
+static volatile sig_atomic_t start_process = 1;
+static volatile pid_t pid = -1;
+
+#define UNUSED(x) ( (void)(x) )
+
+static void sigaction_handler(int sig, siginfo_t *si, void *context) {
+ int exitcode;
+
+ UNUSED(context);
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGUSR1:
+ if (pid <= 0) break;
+ memcpy(&last_sigterm_info, si, sizeof(*si));
+
+ /** forward the sig to the child */
+ kill(pid, sig);
+ break;
+ case SIGHUP: /** do a graceful restart */
+ if (pid <= 0) break;
+ memcpy(&last_sighup_info, si, sizeof(*si));
+
+ /** do a graceful shutdown on the main process and start a new child */
+ kill(pid, SIGINT);
+
+ usleep(5 * 1000); /** wait 5 microsec */
+
+ start_process = 1;
+ break;
+ case SIGCHLD:
+ /** a child died, de-combie it */
+ wait(&exitcode);
+ break;
+ }
+}
+
+int main(int argc, char **argv) {
+ int is_shutdown = 0;
+ struct sigaction act;
+
+ UNUSED(argc);
+ *(const char **)&argv[0] = BINPATH;
+ #ifdef __COVERITY__
+ __coverity_tainted_data_sanitize__(argv);
+ #endif
+
+ /**
+ * we are running as root BEWARE
+ */
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+
+ act.sa_sigaction = sigaction_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGALRM, &act, NULL);
+ sigaction(SIGCHLD, &act, NULL);
+
+ /* check that the compiled in path has the right user,
+ *
+ * BEWARE: there is a race between the check here and the exec later
+ */
+
+ while (!is_shutdown) {
+ int exitcode = 0;
+
+ if (start_process) {
+ pid = fork();
+
+ if (0 == pid) {
+ /* i'm the child */
+
+ /* intentionally pass argv params */
+ /* coverity[tainted_string : FALSE] */
+ execvp(argv[0], argv);
+ _exit(1);
+ } else if (-1 == pid) {
+ /** error */
+
+ return -1;
+ }
+
+ /* I'm the angel */
+ start_process = 0;
+ }
+
+ if ((pid_t)-1 == waitpid(pid, &exitcode, 0)) {
+ switch (errno) {
+ case EINTR:
+ /* someone sent a signal ...
+ * do we have to shutdown or restart the process */
+ break;
+ case ECHILD:
+ /**
+ * make sure we are not in a race between the signal handler
+ * and the process restart */
+ if (!start_process) is_shutdown = 1;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /** process went away */
+
+ if (WIFEXITED(exitcode)) {
+ /** normal exit */
+
+ is_shutdown = 1;
+
+ fprintf(stderr, "%s.%d: child (pid=%d) exited normally with exitcode: %d\n",
+ __FILE__, __LINE__,
+ pid,
+ WEXITSTATUS(exitcode));
+
+ } else if (WIFSIGNALED(exitcode)) {
+ /** got a signal */
+
+ fprintf(stderr, "%s.%d: child (pid=%d) exited unexpectedly with signal %d, restarting\n",
+ __FILE__, __LINE__,
+ pid,
+ WTERMSIG(exitcode));
+
+ start_process = 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/data/lighttpd/lighttpd-1.4.53/src/log.c b/data/lighttpd/lighttpd-1.4.53/src/log.c
new file mode 100644
index 000000000..866ade394
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/log.c
@@ -0,0 +1,216 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#ifndef HAVE_CLOCK_GETTIME
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h> /* gettimeofday() */
+#endif
+#endif
+
+int log_clock_gettime_realtime (struct timespec *ts) {
+ #ifdef HAVE_CLOCK_GETTIME
+ return clock_gettime(CLOCK_REALTIME, ts);
+ #else
+ /* Mac OSX does not provide clock_gettime()
+ * e.g. defined(__APPLE__) && defined(__MACH__) */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+ return 0;
+ #endif
+}
+
+/* retry write on EINTR or when not all data was written */
+ssize_t write_all(int fd, const void* buf, size_t count) {
+ ssize_t written = 0;
+
+ while (count > 0) {
+ ssize_t r = write(fd, buf, count);
+ if (r < 0) {
+ switch (errno) {
+ case EINTR:
+ /* try again */
+ break;
+ default:
+ /* fail - repeating probably won't help */
+ return -1;
+ }
+ } else if (0 == r) {
+ /* really shouldn't happen... */
+ errno = EIO;
+ return -1;
+ } else {
+ force_assert(r <= (ssize_t) count);
+ written += r;
+ buf = r + (char const*) buf;
+ count -= r;
+ }
+ }
+
+ return written;
+}
+
+/* lowercase: append space, uppercase: don't */
+static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
+ for(; *fmt; fmt++) {
+ int d;
+ char *s;
+ buffer *b;
+ off_t o;
+
+ switch(*fmt) {
+ case 'S': /* string */
+ case 's': /* string */
+ s = va_arg(ap, char *);
+ buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
+ break;
+ case 'B': /* buffer */
+ case 'b': /* buffer */
+ b = va_arg(ap, buffer *);
+ buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
+ break;
+ case 'D': /* int */
+ case 'd': /* int */
+ d = va_arg(ap, int);
+ buffer_append_int(out, d);
+ break;
+ case 'O': /* off_t */
+ case 'o': /* off_t */
+ o = va_arg(ap, off_t);
+ buffer_append_int(out, o);
+ break;
+ case 'X': /* int (hex) */
+ case 'x': /* int (hex) */
+ d = va_arg(ap, int);
+ buffer_append_string_len(out, CONST_STR_LEN("0x"));
+ buffer_append_uint_hex(out, d);
+ break;
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case ',':
+ case ' ':
+ buffer_append_string_len(out, fmt, 1);
+ break;
+ }
+
+ if (*fmt >= 'a') { /* 's' 'b' 'd' 'o' 'x' */
+ buffer_append_string_len(out, CONST_STR_LEN(" "));
+ }
+ }
+}
+
+static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
+ switch(srv->errorlog_mode) {
+ case ERRORLOG_PIPE:
+ case ERRORLOG_FILE:
+ case ERRORLOG_FD:
+ if (-1 == srv->errorlog_fd) return -1;
+ /* cache the generated timestamp */
+ if (srv->cur_ts != srv->last_generated_debug_ts) {
+ buffer_clear(srv->ts_debug_str);
+ buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
+
+ srv->last_generated_debug_ts = srv->cur_ts;
+ }
+
+ buffer_copy_buffer(b, srv->ts_debug_str);
+ buffer_append_string_len(b, CONST_STR_LEN(": ("));
+ break;
+ case ERRORLOG_SYSLOG:
+ /* syslog is generating its own timestamps */
+ buffer_copy_string_len(b, CONST_STR_LEN("("));
+ break;
+ }
+
+ buffer_append_string(b, filename);
+ buffer_append_string_len(b, CONST_STR_LEN("."));
+ buffer_append_int(b, line);
+ buffer_append_string_len(b, CONST_STR_LEN(") "));
+
+ return 0;
+}
+
+static void log_write(server *srv, buffer *b) {
+ switch(srv->errorlog_mode) {
+ case ERRORLOG_PIPE:
+ case ERRORLOG_FILE:
+ case ERRORLOG_FD:
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ write_all(srv->errorlog_fd, CONST_BUF_LEN(b));
+ break;
+ case ERRORLOG_SYSLOG:
+ syslog(LOG_ERR, "%s", b->ptr);
+ break;
+ }
+}
+
+int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
+ va_list ap;
+
+ if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
+
+ va_start(ap, fmt);
+ log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
+ va_end(ap);
+
+ log_write(srv, srv->errorlog_buf);
+
+ return 0;
+}
+
+int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
+ va_list ap;
+ size_t prefix_len;
+ buffer *b = srv->errorlog_buf;
+ char *pos, *end, *current_line;
+
+ if (buffer_string_is_empty(multiline)) return 0;
+
+ if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
+
+ va_start(ap, fmt);
+ log_buffer_append_printf(b, fmt, ap);
+ va_end(ap);
+
+ prefix_len = buffer_string_length(b);
+
+ current_line = pos = multiline->ptr;
+ end = multiline->ptr + buffer_string_length(multiline);
+
+ for ( ; pos <= end ; ++pos) {
+ switch (*pos) {
+ case '\n':
+ case '\r':
+ case '\0': /* handles end of string */
+ if (current_line < pos) {
+ /* truncate to prefix */
+ buffer_string_set_length(b, prefix_len);
+
+ buffer_append_string_len(b, current_line, pos - current_line);
+ log_write(srv, b);
+ }
+ current_line = pos + 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/log.h b/data/lighttpd/lighttpd-1.4.53/src/log.h
new file mode 100644
index 000000000..815b6ab1a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/log.h
@@ -0,0 +1,16 @@
+#ifndef _LOG_H_
+#define _LOG_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+struct timespec; /* declaration */
+int log_clock_gettime_realtime (struct timespec *ts);
+
+ssize_t write_all(int fd, const void* buf, size_t count);
+
+int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
+int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/md5.c b/data/lighttpd/lighttpd-1.4.53/src/md5.c
new file mode 100644
index 000000000..42fe466d4
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/md5.c
@@ -0,0 +1,343 @@
+#include "first.h"
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+
+#include "md5.h"
+
+#define UINT4 uint32_t
+#define UINT2 uint16_t
+#define POINTER unsigned char *
+
+#if 0 /* Note: not defined here or in lighttpd local "md5.h" */
+#include "sys-crypto.h" /* USE_OPENSSL_CRYPTO */
+#endif
+
+#ifndef USE_OPENSSL_CRYPTO
+#include <string.h>
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void li_MD5Transform (UINT4 [4], const unsigned char [64]);
+static void Encode (unsigned char *, UINT4 *, unsigned int);
+static void Decode (UINT4 *, const unsigned char *, unsigned int);
+
+#ifdef HAVE_MEMCPY
+#define MD5_memcpy(output, input, len) memcpy((output), (input), (len))
+#else
+static void MD5_memcpy (POINTER, POINTER, unsigned int);
+#endif
+#ifdef HAVE_MEMSET
+#define MD5_memset(output, value, len) memset((output), (value), (len))
+#else
+static void MD5_memset (POINTER, int, unsigned int);
+#endif
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void li_MD5_Init (li_MD5_CTX *context)
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void li_MD5_Update (li_MD5_CTX *context, const void *_input, unsigned int inputLen)
+{
+ unsigned int i, ndx, partLen;
+ const unsigned char *input = (const unsigned char*) _input;
+
+ /* Compute number of bytes mod 64 */
+ ndx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - ndx;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[ndx], (POINTER)input, partLen);
+ li_MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ li_MD5Transform (context->state, &input[i]);
+
+ ndx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[ndx], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void li_MD5_Final (unsigned char digest[16], li_MD5_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int ndx, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ ndx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (ndx < 56) ? (56 - ndx) : (120 - ndx);
+ li_MD5_Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ li_MD5_Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void li_MD5Transform (UINT4 state[4], const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (UINT4 *output, const unsigned char *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+#ifndef HAVE_MEMCPY
+static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+#endif
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+#ifndef HAVE_MEMSET
+static void MD5_memset (POINTER output, int value, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/md5.h b/data/lighttpd/lighttpd-1.4.53/src/md5.h
new file mode 100644
index 000000000..b8cb70039
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/md5.h
@@ -0,0 +1,45 @@
+#ifndef LI_MD5_H
+#define LI_MD5_H
+#include "first.h"
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} li_MD5_CTX;
+
+#ifndef MD5_DIGEST_LENGTH
+#define MD5_DIGEST_LENGTH 16
+#endif
+
+void li_MD5_Init (li_MD5_CTX *);
+void li_MD5_Update (li_MD5_CTX *, const void *, unsigned int);
+void li_MD5_Final (unsigned char [MD5_DIGEST_LENGTH], li_MD5_CTX *);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/meson.build b/data/lighttpd/lighttpd-1.4.53/src/meson.build
new file mode 100644
index 000000000..842afaa45
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/meson.build
@@ -0,0 +1,981 @@
+sbinddir = join_paths(get_option('prefix'), get_option('sbindir'))
+moduledir = join_paths(get_option('prefix'), get_option('moduledir'))
+
+include_base_paths = [
+ '/usr/include',
+ '/usr/local/include',
+# '/opt/local/include',
+]
+
+defs = [
+ '-D_FILE_OFFSET_BITS=64',
+ '-D_LARGEFILE_SOURCE',
+ '-D_LARGE_FILES',
+ '-D_GNU_SOURCE',
+]
+
+libws2_32 = []
+if target_machine.system() == 'windows'
+ libws2_32 = [ compiler.find_library('ws2_32') ]
+ defs += [
+ '-DNVALGRIND',
+ ]
+endif
+
+
+compiler = meson.get_compiler('c')
+conf_data = configuration_data()
+
+conf_data.set('HAVE_SYS_DEVPOLL_H', compiler.has_header('sys/devpoll.h'))
+conf_data.set('HAVE_SYS_EPOLL_H', compiler.has_header('sys/epoll.h'))
+conf_data.set('HAVE_SYS_EVENT_H', compiler.has_header('sys/event.h'))
+conf_data.set('HAVE_SYS_MMAN_H', compiler.has_header('sys/mman.h'))
+conf_data.set('HAVE_SYS_POLL_H', compiler.has_header('sys/poll.h'))
+conf_data.set('HAVE_SYS_PORT_H', compiler.has_header('sys/port.h'))
+conf_data.set('HAVE_SYS_PRCTL_H', compiler.has_header('sys/prctl.h'))
+conf_data.set('HAVE_SYS_RESOURCE_H', compiler.has_header('sys/resource.h'))
+conf_data.set('HAVE_SYS_SENDFILE_H', compiler.has_header('sys/sendfile.h'))
+conf_data.set('HAVE_SYS_SELECT_H', compiler.has_header('sys/select.h'))
+conf_data.set('HAVE_SYS_TYPES_H', compiler.has_header('sys/types.h'))
+conf_data.set('HAVE_SYS_UIO_H', compiler.has_header('sys/uio.h'))
+conf_data.set('HAVE_SYS_UN_H', compiler.has_header('sys/un.h'))
+conf_data.set('HAVE_SYS_WAIT_H', compiler.has_header('sys/wait.h'))
+conf_data.set('HAVE_SYS_TIME_H', compiler.has_header('sys/time.h'))
+conf_data.set('HAVE_UNISTD_H', compiler.has_header('unistd.h'))
+conf_data.set('HAVE_PTHREAD_H', compiler.has_header('pthread.h'))
+conf_data.set('HAVE_GETOPT_H', compiler.has_header('getopt.h'))
+conf_data.set('HAVE_INTTYPES_H', compiler.has_header('inttypes.h'))
+conf_data.set('HAVE_POLL_H', compiler.has_header('poll.h'))
+conf_data.set('HAVE_PWD_H', compiler.has_header('pwd.h'))
+conf_data.set('HAVE_STDDEF_H', compiler.has_header('stddef.h'))
+conf_data.set('HAVE_STDINT_H', compiler.has_header('stdint.h'))
+conf_data.set('HAVE_STRINGS_H', compiler.has_header('strings.h'))
+conf_data.set('HAVE_SYSLOG_H', compiler.has_header('syslog.h'))
+
+# check for fastcgi lib, for the tests only
+conf_data.set('HAVE_FASTCGI_H', compiler.has_header('fastcgi.h'))
+if not(conf_data.get('HAVE_FASTCGI_H'))
+ conf_data.set('HAVE_FASTCGI_FASTCGI_H', compiler.has_header('fastcgi/fastcgi.h'))
+endif
+
+# will be needed for auth
+conf_data.set('HAVE_CRYPT_H', compiler.has_header('crypt.h'))
+if conf_data.get('HAVE_CRYPT_H')
+ # check if we need libcrypt for crypt_r / crypt
+
+ # crypt_r in default libs?
+ if compiler.has_function('crypt_r', args: defs, prefix: '#include <crypt.h>')
+ libcrypt = []
+ conf_data.set('HAVE_CRYPT_R', 1)
+ # crypt_r in -lcrypt ?
+ elif compiler.has_function('crypt_r', args: defs + ['-lcrypt'], prefix: '#include <crypt.h>')
+ libcrypt = [ compiler.find_library('crypt') ]
+ conf_data.set('HAVE_CRYPT_R', 1)
+ # crypt in default libs?
+ elif compiler.has_function('crypt', args: defs, prefix: '#include <crypt.h>')
+ libcrypt = []
+ conf_data.set('HAVE_CRYPT', 1)
+ # crypt in -lcrypt ?
+ elif compiler.has_function('crypt', args: defs + ['-lcrypt'], prefix: '#include <crypt.h>')
+ libcrypt = [ compiler.find_library('crypt') ]
+ conf_data.set('HAVE_CRYPT', 1)
+ endif
+endif
+
+conf_data.set('HAVE_SYS_INOTIFY_H', compiler.has_header('sys/inotify.h'))
+if conf_data.get('HAVE_SYS_INOTIFY_H')
+ conf_data.set('HAVE_INOTIFY_INIT', compiler.has_function('inotify_init', args: defs))
+endif
+
+conf_data.set('HAVE_SOCKLEN_T', compiler.has_type('socklen_t', args: defs, prefix: '#include <sys/socket.h>'))
+
+conf_data.set('HAVE_SYS_RANDOM_H', compiler.has_header('sys/random.h'))
+if conf_data.get('HAVE_SYS_RANDOM_H')
+ conf_data.set('HAVE_GETENTROPY', compiler.has_function(
+ 'getentropy',
+ args: defs,
+ prefix: '#include <sys/random.h>'
+ ))
+endif
+
+conf_data.set('HAVE_LINUX_RANDOM_H', compiler.has_header('linux/random.h'))
+if conf_data.get('HAVE_LINUX_RANDOM_H')
+ conf_data.set('HAVE_GETRANDOM', compiler.has_function(
+ 'getrandom',
+ args: defs,
+ prefix: '#include <linux/random.h>'
+ ))
+endif
+
+conf_data.set('SIZEOF_LONG', compiler.sizeof('long', args: defs))
+conf_data.set('SIZEOF_OFF_T', compiler.sizeof('off_t', args: defs))
+
+conf_data.set('HAVE_ARC4RANDOM_BUF', compiler.has_function('arc4random_buf', args: defs))
+conf_data.set('HAVE_CHROOT', compiler.has_function('chroot', args: defs))
+conf_data.set('HAVE_EPOLL_CTL', compiler.has_function('epoll_ctl', args: defs))
+conf_data.set('HAVE_FORK', compiler.has_function('fork', args: defs))
+conf_data.set('HAVE_GETLOADAVG', compiler.has_function('getloadavg', args: defs))
+conf_data.set('HAVE_GETRLIMIT', compiler.has_function('getrlimit', args: defs))
+conf_data.set('HAVE_GETUID', compiler.has_function('getuid', args: defs))
+conf_data.set('HAVE_GMTIME_R', compiler.has_function('gmtime_r', args: defs))
+conf_data.set('HAVE_INET_NTOP', compiler.has_function('inet_ntop', args: defs))
+conf_data.set('HAVE_JRAND48', compiler.has_function('jrand48', args: defs))
+conf_data.set('HAVE_KQUEUE', compiler.has_function('kqueue', args: defs))
+conf_data.set('HAVE_LOCALTIME_R', compiler.has_function('localtime_r', args: defs))
+conf_data.set('HAVE_LSTAT', compiler.has_function('lstat', args: defs))
+conf_data.set('HAVE_MADVISE', compiler.has_function('madvise', args: defs))
+conf_data.set('HAVE_MEMCPY', compiler.has_function('memcpy', args: defs))
+conf_data.set('HAVE_MEMSET', compiler.has_function('memset', args: defs))
+conf_data.set('HAVE_MMAP', compiler.has_function('mmap', args: defs))
+conf_data.set('HAVE_PATHCONF', compiler.has_function('pathconf', args: defs))
+conf_data.set('HAVE_PIPE2', compiler.has_function('pipe2', args: defs))
+conf_data.set('HAVE_POLL', compiler.has_function('poll', args: defs))
+conf_data.set('HAVE_PORT_CREATE', compiler.has_function('port_create', args: defs))
+conf_data.set('HAVE_PRCTL', compiler.has_function('prctl', args: defs))
+conf_data.set('HAVE_PREAD', compiler.has_function('pread', args: defs))
+conf_data.set('HAVE_POSIX_FADVISE', compiler.has_function('posix_fadvise', args: defs))
+conf_data.set('HAVE_SELECT', compiler.has_function('select', args: defs))
+conf_data.set('HAVE_SENDFILE', compiler.has_function('sendfile', args: defs))
+conf_data.set('HAVE_SEND_FILE', compiler.has_function('send_file', args: defs))
+conf_data.set('HAVE_SENDFILE64', compiler.has_function('sendfile64', args: defs))
+conf_data.set('HAVE_SENDFILEV', compiler.has_function('sendfilev', args: defs))
+conf_data.set('HAVE_SIGACTION', compiler.has_function('sigaction', args: defs))
+conf_data.set('HAVE_SIGNAL', compiler.has_function('signal', args: defs))
+conf_data.set('HAVE_SIGTIMEDWAIT', compiler.has_function('sigtimedwait', args: defs))
+conf_data.set('HAVE_SRANDOM', compiler.has_function('srandom', args: defs))
+conf_data.set('HAVE_STRPTIME', compiler.has_function('strptime', args: defs))
+conf_data.set('HAVE_SYSLOG', compiler.has_function('syslog', args: defs))
+conf_data.set('HAVE_WRITEV', compiler.has_function('writev', args: defs))
+conf_data.set('HAVE_INET_ATON', compiler.has_function('inet_aton', args: defs))
+conf_data.set('HAVE_ISSETUGID', compiler.has_function('issetugid', args: defs))
+conf_data.set('HAVE_INET_PTON', compiler.has_function('inet_pton', args: defs))
+conf_data.set('HAVE_MEMSET_S', compiler.has_function('memset_s', args: defs))
+conf_data.set('HAVE_EXPLICIT_BZERO', compiler.has_function('explicit_bzero', args: defs))
+
+conf_data.set('HAVE_CLOCK_GETTIME', compiler.has_header_symbol('time.h', 'clock_gettime'))
+clock_lib = []
+if not(conf_data.get('HAVE_CLOCK_GETTIME'))
+ if compiler.has_function('clock_gettime', args: defs + ['-lrt'], prefix: '#include <time.h>')
+ conf_data.set('HAVE_CLOCK_GETTIME', true)
+ clock_lib = [ compiler.find_library('rt') ]
+ endif
+endif
+
+conf_data.set('HAVE_IPV6', compiler.compiles('''
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+
+ int main() {
+ struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0;
+ return 0;
+ }
+''',
+ name: 'IPv6 support',
+ args: defs
+))
+
+conf_data.set('HAVE_WEAK_SYMBOLS', compiler.compiles('''
+ __attribute__((weak)) void __dummy(void *x) { }
+ int main() {
+ void *x;
+ __dummy(x);
+ }
+''',
+ name: 'weak symbols',
+ args: defs
+))
+
+conf_data.set('HAVE_STRUCT_TM_GMTOFF', compiler.compiles('''
+ #include <time.h>
+ int main(void) {
+ struct tm t;
+ t.tm_gmtoff = 0;
+ return 0;
+ }
+''',
+ name: 'struct tm gmt offset',
+ args: defs
+))
+
+conf_data.set('LIGHTTPD_VERSION_ID', 10400)
+conf_data.set_quoted('PACKAGE_NAME', meson.project_name())
+conf_data.set_quoted('PACKAGE_VERSION', meson.project_version())
+conf_data.set_quoted('LIBRARY_DIR', moduledir)
+
+conf_data.set('LIGHTTPD_STATIC', get_option('build_static'))
+libdl = []
+if not(get_option('build_static'))
+ if target_machine.system() != 'windows'
+ libdl = [ compiler.find_library('dl') ]
+ if not(compiler.has_function('dlopen', args: defs, dependencies: libdl, prefix: '#include <dlfcn.h>'))
+ error('Couldn\'t find dlfcn.h or dlopen in lib dl')
+ endif
+ endif
+endif
+
+libbz2 = []
+if get_option('with_bzip')
+ libbz2 = [ compiler.find_library('bz2') ]
+ if compiler.has_function('BZ2_bzCompress', args: defs, dependencies: libbz2, prefix: '#include <bzlib.h>')
+ conf_data.set('HAVE_BZLIB_H', true)
+ conf_data.set('HAVE_LIBBZ2', true)
+ else
+ error('Couldn\'t find bz2 header / library')
+ endif
+endif
+
+if get_option('with_dbi')
+ libdbi = dependency('dbi', required: false)
+ if libdbi.found()
+ libdbi = [ libdbi ]
+ else
+ libdbi = [ compiler.find_library('dbi') ]
+ if not(compiler.has_function('dbi_conn_connect', args: defs, dependencies: libdbi, prefix: '#include <dbi/dbi.h>'))
+ error('Couldn\'t find dbi/dbi.h or dbi_conn_connect in lib dbi')
+ endif
+ endif
+ conf_data.set('HAVE_DBI', true)
+endif
+
+libfam = []
+if get_option('with_fam')
+ libfam = [ compiler.find_library('fam') ]
+ if not(compiler.has_function('FAMOpen2', args: defs, dependencies: libfam, prefix: '#include <fam.h>'))
+ error('Couldn\'t find fam.h or FAMOpen2 in lib fam')
+ endif
+ conf_data.set('HAVE_FAM_H', true)
+endif
+
+libgeoip = []
+if get_option('with_geoip')
+ libgeoip = dependency('geoip', required: false)
+ if libgeoip.found()
+ libgeoip = [ libgeoip ]
+ else
+ libgeoip = [ compiler.find_library('GeoIP') ]
+ if not(compiler.has_function('GeoIP_country_name_by_addr', args: defs, dependencies: libgeoip))
+ error('Couldn\'t find GeoIP_country_name_by_addr in lib GeoIP')
+ endif
+ endif
+endif
+
+libgdbm = []
+if get_option('with_gdbm')
+ libgdbm = [ compiler.find_library('gdbm') ]
+ if not(compiler.has_function('gdbm_open', args: defs, dependencies: libgdbm, prefix: '#include <gdbm.h>'))
+ error('Couldn\'t find gdbm.h or gdbm_open in lib gdbm')
+ endif
+ conf_data.set('HAVE_GDBM_H', true)
+ conf_data.set('HAVE_GDBM', true)
+endif
+
+libkrb5 = []
+libgssapi_krb5 = []
+if get_option('with_krb5')
+ libkrb5 = dependency('krb5', required: false)
+ if libkrb5.found()
+ libkrb5 = [ libkrb5 ]
+ else
+ libkrb5 = [ compiler.find_library('krb5') ]
+ if not(compiler.has_function('krb5_init_context', args: defs, dependencies: libkrb5))
+ error('Couldn\'t find krb5_init_context in lib krb5')
+ endif
+ endif
+
+ libgssapi_krb5 = dependency('krb5-gssapi', required: false)
+ if libgssapi_krb5.found()
+ libgssapi_krb5 = [ libgssapi_krb5 ]
+ else
+ libgssapi_krb5 = [ compiler.find_library('gssapi_krb5') ]
+ endif
+
+ conf_data.set('HAVE_KRB5', true)
+endif
+
+libldap = []
+liblber = []
+if get_option('with_ldap')
+ libldap = [ compiler.find_library('ldap') ]
+ if not(compiler.has_function('ldap_sasl_bind_s',
+ args: defs,
+ dependencies: libldap,
+ prefix: '''
+ #include <ldap.h>
+ '''
+ ))
+ error('Couldn\'t find ldap.h or ldap_bind in lib libldap')
+ endif
+ conf_data.set('HAVE_LDAP_H', true)
+ conf_data.set('HAVE_LIBLDAP', true)
+ liblber = [ compiler.find_library('lber') ]
+ if not(compiler.has_function('ber_printf', args: defs, dependencies: liblber, prefix: '#include <lber.h>'))
+ error('Couldn\'t find lber.h or ber_printf in lib liblber')
+ endif
+ conf_data.set('HAVE_LBER_H', true)
+ conf_data.set('HAVE_LIBLBER', true)
+endif
+
+libpam = []
+if get_option('with_pam')
+ libpam = [ compiler.find_library('pam') ]
+ if not(compiler.has_function('pam_start',
+ args: defs,
+ dependencies: libpam,
+ prefix: '''
+ #include <security/pam_appl.h>
+ '''
+ ))
+ error('Couldn\'t find security/pam_appl.h or pam_start in lib libpam')
+ endif
+ conf_data.set('HAVE_PAM', true)
+endif
+
+libev = []
+if get_option('with_libev')
+ libev = dependency('ev', required: false)
+ if libev.found()
+ libev = [ libev ]
+ elif compiler.has_header('ev.h') and compiler.has_function('ev_time', args: defs + ['-lev'])
+ libev = [ compiler.find_library('ev') ]
+ else
+ error('Couldn\'t find libev header / library')
+ endif
+ conf_data.set('HAVE_LIBEV', true)
+endif
+
+libunwind = []
+if get_option('with_libunwind')
+ libunwind = [ dependency('libunwind') ]
+endif
+
+liblua = []
+if get_option('with_lua')
+ found_lua = false
+ foreach l: ['lua5.3', 'lua-5.3', 'lua5.2', 'lua-5.2', 'lua5.1', 'lua-5.1', 'lua']
+ if not(found_lua)
+ liblua = dependency(l, required: false)
+ found_lua = liblua.found()
+ endif
+ endforeach
+ if not(found_lua)
+ error('Couldn\'t find any lua library')
+ endif
+ liblua = [ liblua ]
+ conf_data.set('HAVE_LUA_H', true)
+endif
+
+libmemcached = []
+if get_option('with_memcached')
+ # manual search:
+ # header: libmemcached/memcached.h
+ # function: memcached (-lmemcached)
+ libmemcached = [ dependency('libmemcached') ]
+ conf_data.set('USE_MEMCACHED', true)
+endif
+
+libmysqlclient = []
+if get_option('with_mysql')
+ # manual search: extend include path with 'mysql/'
+ # header: mysql.h
+ # function: mysql_real_connect (-lmariadb)
+ libmysqlclient = [ dependency('mariadb') ]
+ #-# function: mysql_real_connect (-lmysqlclient)
+ #-libmysqlclient = [ dependency('mysqlclient') ]
+ conf_data.set('HAVE_MYSQL', true)
+endif
+
+libssl = []
+libcrypto = []
+if get_option('with_openssl')
+ # manual search:
+ # header: openssl/ssl.h
+ # function: SSL_new (-lssl)
+ # function: BIO_f_base64 (-lcrypto)
+ libssl = [ dependency('libssl') ]
+ libcrypto = [ dependency('libcrypto') ]
+ conf_data.set('HAVE_OPENSSL_SSL_H', true)
+ conf_data.set('HAVE_LIBSSL', true)
+endif
+if get_option('with_wolfssl') != 'false'
+ # manual search:
+ # header: wolfssl/ssl.h
+ # function: wolfSSL_Init (-lwolfssl)
+ p = get_option('with_wolfssl')
+ if p == 'true'
+ p = '/usr/local'
+ endif
+ i = include_directories(p+'/include', p+'/include/wolfssl')
+ libwolfssl_includes_dep = [ declare_dependency(include_directories: i) ]
+ libcrypto = [ compiler.find_library('libwolfssl', dirs: [ p+'/lib', p+'/lib64' ]) ]
+ libcrypto += libwolfssl_includes_dep
+ conf_data.set('HAVE_WOLFSSL_SSL_H', true)
+endif
+
+libpcre = []
+if get_option('with_pcre')
+ # manual search:
+ # header: pcre.h
+ # function: pcre_exec (-lpcre)
+ libpcre = [ dependency('libpcre') ]
+ conf_data.set('HAVE_PCRE_H', true)
+ conf_data.set('HAVE_LIBPCRE', true)
+endif
+
+libpq = []
+if get_option('with_pgsql')
+ # manual search:
+ # header: libpq-fe.h
+ # function: PQsetdbLogin (-lpq)
+ libpq = [ dependency('libpq') ]
+ conf_data.set('HAVE_PGSQL', true)
+endif
+
+if get_option('with_sasl')
+ libsasl = dependency('sasl2', required: false)
+ if libsasl.found()
+ libsasl = [ libsasl2 ]
+ else
+ libsasl = [ compiler.find_library('sasl2') ]
+ if not(compiler.has_function('sasl_server_init', args: defs, dependencies: libsasl, prefix: '#include <sasl/sasl.h>'))
+ error('Couldn\'t find sasl/sasl.h or sasl_server_init in libsasl2')
+ endif
+ endif
+ conf_data.set('HAVE_SASL', true)
+endif
+
+#if get_option('with_valgrind')
+#endif
+
+libuuid = []
+if get_option('with_webdav_locks')
+ libuuid = dependency('uuid', required: false)
+ if libuuid.found()
+ libuuid = [ libuuid ]
+ elif compiler.has_function('uuid_generate', args: defs, prefix: '#include <uuid/uuid.h>')
+ # uuid_generate in libc, everything is fine, no lib needed
+ libuuid = []
+ else
+ libuuid = compiler.find_library('uuid')
+ if not(compiler.has_function('uuid_generate',
+ args: defs,
+ dependencies: libuuid,
+ prefix: '#include <uuid/uuid.h>'
+ ))
+ error('Couldn\'t find uuid/uuid.h or uuid_generate in lib c and uuid')
+ endif
+ endif
+ conf_data.set('HAVE_UUID', true)
+ conf_data.set('HAVE_UUID_UUID_H', true)
+endif
+
+libxml2 = []
+libsqlite3 = []
+if get_option('with_webdav_props')
+ libxml2 = dependency('libxml-2.0', required: false)
+ if libxml2.found()
+ libxml2 = [ libxml2 ]
+ else
+ libxml2_includes = []
+ libxml2_includes_dep = []
+ libxml2_found_header = compiler.has_header('libxml/tree.h')
+ foreach i: include_base_paths
+ if not(libxml2_found_header)
+ message('Searching in ' + join_paths(i, 'libxml2'))
+ i = include_directories(join_paths(i, 'libxml2'))
+ if compiler.has_header('libxml/tree.h', include_directories: i)
+ libxml2_found_header = true
+ libxml2_includes = [ i ]
+ libxml2_includes_dep = [ declare_dependency(include_directories: i) ]
+ endif
+ endif
+ endforeach
+ if not(libxml2_found_header)
+ error('Couldn\'t find libxml/tree.h')
+ endif
+ libxml2 = [ compiler.find_library('xml2') ]
+ if not(compiler.has_function('xmlParseChunk',
+ args: defs,
+ dependencies: libxml2,
+ include_directories: libxml2_includes,
+ prefix: '''
+ #include <libxml/tree.h>
+ '''
+ ))
+ error('Couldn\'t find xmlParseChunk in lib xml2')
+ endif
+ # has_function doesn't like "internal dependencies"
+ libxml2 += libxml2_includes_dep
+ endif
+ conf_data.set('HAVE_LIBXML_H', true)
+
+ libsqlite3 = dependency('sqlite31', required: false)
+ if libsqlite3.found()
+ libsqlite3 = [ libsqlite3 ]
+ else
+ libsqlite3 = [ compiler.find_library('sqlite3') ]
+ if not(compiler.has_function('sqlite3_reset',
+ args: defs,
+ dependencies: libsqlite3,
+ prefix: '''
+ #include <sqlite3.h>
+ '''
+ ))
+ error('Couldn\'t find sqlite3.h or sqlite3_reset in lib sqlite3')
+ endif
+ endif
+ conf_data.set('HAVE_SQLITE3_H', true)
+endif
+
+libattr = []
+if get_option('with_xattr')
+ libattr = [ compiler.find_library('attr') ]
+ if not(compiler.has_function('attr_get',
+ args: defs,
+ dependencies: libattr,
+ prefix: '''
+ #include <sys/types.h>
+ #include <attr/attributes.h>
+ '''
+ ))
+ error('Couldn\'t find attr/attributes.h or attr_get in lib attr')
+ endif
+ conf_data.set('HAVE_ATTR_ATTRIBUTES_H', true)
+ conf_data.set('HAVE_XATTR', true)
+endif
+
+libz = []
+if get_option('with_zlib')
+ libz = dependency('zlib', required: false)
+ if libz.found()
+ libz = [ libz ]
+ else
+ # windows alternative names? 'zlib', 'zdll'
+ libz = [ compiler.find_library('z') ]
+ if not(compiler.has_function('deflate', args: defs, dependencies: libz, prefix: '#include <zlib.h>'))
+ error('Couldn\'t find z header / library')
+ endif
+ endif
+ conf_data.set('HAVE_ZLIB_H', true)
+ conf_data.set('HAVE_LIBZ', true)
+endif
+
+configure_file(
+ output : 'config.h',
+ configuration : conf_data,
+)
+
+common_src = [
+ 'algo_sha1.c',
+ 'array.c',
+ 'base64.c',
+ 'buffer.c',
+ 'burl.c',
+ 'chunk.c',
+ 'configfile-glue.c',
+ 'connections-glue.c',
+ 'crc32.c',
+ 'data_array.c',
+ 'data_config.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'etag.c',
+ 'fdevent_freebsd_kqueue.c',
+ 'fdevent_libev.c',
+ 'fdevent_linux_sysepoll.c',
+ 'fdevent_poll.c',
+ 'fdevent_select.c',
+ 'fdevent_solaris_devpoll.c',
+ 'fdevent_solaris_port.c',
+ 'fdevent.c',
+ 'gw_backend.c',
+ 'http_auth.c',
+ 'http_chunk.c',
+ 'http_header.c',
+ 'http_kv.c',
+ 'http_vhostdb.c',
+ 'http-header-glue.c',
+ 'joblist.c',
+ 'keyvalue.c',
+ 'log.c',
+ 'md5.c',
+ 'plugin.c',
+ 'rand.c',
+ 'request.c',
+ 'safe_memclear.c',
+ 'sock_addr.c',
+ 'splaytree.c',
+ 'stat_cache.c',
+ 'stream.c',
+ 'vector.c',
+]
+if target_machine.system() == 'windows'
+ common_src += [ 'xgetopt.c' ]
+endif
+main_src = [
+ 'configfile.c',
+ 'connections.c',
+ 'inet_ntop_cache.c',
+ 'network_write.c',
+ 'network.c',
+ 'response.c',
+ 'server.c',
+]
+
+lemon = executable('lemon',
+ sources: 'lemon.c',
+ native: true,
+)
+# generator doesn't handle additional "input dependencies" like lempar.c
+# => use custom_target
+configparser = custom_target('configparser',
+ input: ['configparser.y', 'lempar.c'],
+ output: ['configparser.c', 'configparser.h'],
+ command: [lemon, '-q', 'o=@OUTDIR@', '@INPUT0@', '@INPUT1@'],
+)
+ssi_exprparser = custom_target('mod_ssi_exprparser',
+ input: ['mod_ssi_exprparser.y', 'lempar.c'],
+ output: ['mod_ssi_exprparser.c', 'mod_ssi_exprparser.h'],
+ command: [lemon, '-q', 'o=@OUTDIR@', '@INPUT0@', '@INPUT1@'],
+)
+
+common_cflags = defs + [
+ '-DHAVE_CONFIG_H',
+]
+
+if compiler.get_id() == 'gcc' or compiler.get_id() == 'clang'
+ common_cflags += [
+ '-Wall',
+ '-g',
+ '-Wshadow',
+ '-W',
+ '-pedantic',
+ ]
+ if get_option('build_extra_warnings')
+ common_cflags += get_option('warn_cflags').split()
+ endif
+endif
+
+common_flags = [ declare_dependency(
+ compile_args: common_cflags,
+ # tests also use common_flags, and need this
+ include_directories: include_directories('.'),
+) ]
+
+lighttpd_flags = []
+lighttpd_angel_flags = []
+if target_machine.system() == 'windows'
+ lighttpd_flags += [ declare_dependency(
+ compile_args: [
+ '-DLI_DECLARE_EXPORTS',
+ ],
+ ) ]
+ if compiler.get_id() == 'gcc'
+ libmsvcr70 = [ compiler.find_library('msvcr70') ]
+ lighttpd_flags += libmsvcr70 + [ declare_dependency(
+ link_args: [
+ '-Wl,-subsystem,console',
+ ],
+ ) ]
+ lighttpd_angel_flags += libmsvcr70 + [ declare_dependency(
+ link_args: [
+ '-Wl,-subsystem,console',
+ ],
+ ) ]
+ endif
+endif
+
+if compiler.get_id() == 'gcc' or target_machine.system() != 'darwin'
+ lighttpd_flags += [ declare_dependency(
+ link_args: [
+ '-Wl,-export-dynamic',
+ ],
+ ) ]
+endif
+
+executable('lighttpd-angel',
+ sources: 'lighttpd-angel.c',
+ dependencies: common_flags + lighttpd_angel_flags,
+ c_args: ['-DSBIN_DIR="' + sbinddir + '"'],
+ install: true,
+ install_dir: sbinddir,
+)
+
+executable('lighttpd', configparser,
+ sources: common_src + main_src,
+ # libssl needed?
+ dependencies: [ common_flags, lighttpd_flags
+ , libattr
+ , libcrypto
+ , libdl
+ , libev
+ , libfam
+ , libpcre
+ , libunwind
+ , libws2_32
+ ],
+ install: true,
+ install_dir: sbinddir,
+)
+
+test('test_array', executable('test_array',
+ sources: ['t/test_array.c', 'array.c', 'data_array.c', 'data_integer.c', 'data_string.c', 'buffer.c'],
+ dependencies: common_flags + libunwind,
+ build_by_default: false,
+))
+
+test('test_buffer', executable('test_buffer',
+ sources: ['t/test_buffer.c', 'buffer.c'],
+ dependencies: common_flags + libunwind,
+ build_by_default: false,
+))
+
+test('test_burl', executable('test_burl',
+ sources: ['t/test_burl.c', 'burl.c', 'buffer.c', 'base64.c'],
+ dependencies: common_flags + libunwind,
+ build_by_default: false,
+))
+
+test('test_base64', executable('test_base64',
+ sources: ['t/test_base64.c', 'buffer.c', 'base64.c'],
+ dependencies: common_flags + libunwind,
+ build_by_default: false,
+))
+
+test('test_configfile', executable('test_configfile',
+ sources: [
+ 't/test_configfile.c',
+ 'buffer.c',
+ 'array.c',
+ 'data_config.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'http_header.c',
+ 'http_kv.c',
+ 'vector.c',
+ 'log.c',
+ 'sock_addr.c',
+ ],
+ dependencies: common_flags + libpcre + libunwind,
+ build_by_default: false,
+))
+
+test('test_keyvalue', executable('test_keyvalue',
+ sources: [
+ 't/test_keyvalue.c',
+ 'burl.c',
+ 'buffer.c',
+ 'base64.c',
+ 'array.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'log.c',
+ ],
+ dependencies: common_flags + libpcre + libunwind,
+ build_by_default: false,
+))
+
+test('test_mod_access', executable('test_mod_access',
+ sources: [
+ 't/test_mod_access.c',
+ 'configfile-glue.c',
+ 'buffer.c',
+ 'array.c',
+ 'data_config.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'http_header.c',
+ 'http_kv.c',
+ 'vector.c',
+ 'log.c',
+ 'sock_addr.c',
+ ],
+ dependencies: common_flags + libpcre + libunwind,
+ build_by_default: false,
+))
+
+test('test_mod_evhost', executable('test_mod_evhost',
+ sources: [
+ 't/test_mod_evhost.c',
+ 'configfile-glue.c',
+ 'buffer.c',
+ 'array.c',
+ 'data_config.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'http_header.c',
+ 'http_kv.c',
+ 'vector.c',
+ 'log.c',
+ 'sock_addr.c',
+ ],
+ dependencies: common_flags + libpcre + libunwind,
+ build_by_default: false,
+))
+
+test('test_mod_simple_vhost', executable('test_mod_simple_vhost',
+ sources: [
+ 't/test_mod_simple_vhost.c',
+ 'configfile-glue.c',
+ 'buffer.c',
+ 'array.c',
+ 'data_config.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'http_header.c',
+ 'http_kv.c',
+ 'vector.c',
+ 'log.c',
+ 'sock_addr.c',
+ ],
+ dependencies: common_flags + libpcre + libunwind,
+ build_by_default: false,
+))
+
+test('test_request', executable('test_request',
+ sources: [
+ 't/test_request.c',
+ 'request.c',
+ 'buffer.c',
+ 'array.c',
+ 'data_integer.c',
+ 'data_string.c',
+ 'http_header.c',
+ 'http_kv.c',
+ 'log.c',
+ 'sock_addr.c',
+ ],
+ dependencies: common_flags + libunwind,
+ build_by_default: false,
+))
+
+modules = [
+ [ 'mod_access', [ 'mod_access.c' ] ],
+ [ 'mod_accesslog', [ 'mod_accesslog.c' ] ],
+ [ 'mod_alias', [ 'mod_alias.c' ] ],
+ [ 'mod_auth', [ 'mod_auth.c' ] ],
+ [ 'mod_authn_file', [ 'mod_authn_file.c' ], [ libcrypt, libcrypto ] ],
+ [ 'mod_compress', [ 'mod_compress.c' ], libbz2 + libz ],
+ [ 'mod_deflate', [ 'mod_deflate.c' ], libbz2 + libz ],
+ [ 'mod_dirlisting', [ 'mod_dirlisting.c' ], libpcre ],
+ [ 'mod_evasive', [ 'mod_evasive.c' ] ],
+ [ 'mod_evhost', [ 'mod_evhost.c' ] ],
+ [ 'mod_expire', [ 'mod_expire.c' ] ],
+ [ 'mod_extforward', [ 'mod_extforward.c' ] ],
+ [ 'mod_fastcgi', [ 'mod_fastcgi.c' ], libws2_32 ],
+ [ 'mod_flv_streaming', [ 'mod_flv_streaming.c' ] ],
+ [ 'mod_indexfile', [ 'mod_indexfile.c' ] ],
+ [ 'mod_proxy', [ 'mod_proxy.c' ], libws2_32 ],
+ [ 'mod_redirect', [ 'mod_redirect.c' ], libpcre ],
+ [ 'mod_rewrite', [ 'mod_rewrite.c' ], libpcre ],
+ [ 'mod_rrdtool', [ 'mod_rrdtool.c' ] ],
+ [ 'mod_scgi', [ 'mod_scgi.c' ], libws2_32 ],
+ [ 'mod_secdownload', [ 'mod_secdownload.c' ], libcrypto ],
+ [ 'mod_setenv', [ 'mod_setenv.c' ] ],
+ [ 'mod_simple_vhost', [ 'mod_simple_vhost.c' ] ],
+ [ 'mod_sockproxy', [ 'mod_sockproxy.c' ] ],
+ [ 'mod_ssi', [ ssi_exprparser, 'mod_ssi_expr.c', 'mod_ssi.c' ], libws2_32 ],
+ [ 'mod_staticfile', [ 'mod_staticfile.c' ] ],
+ [ 'mod_status', [ 'mod_status.c' ] ],
+ [ 'mod_uploadprogress', [ 'mod_uploadprogress.c' ] ],
+ [ 'mod_userdir', [ 'mod_userdir.c' ] ],
+ [ 'mod_usertrack', [ 'mod_usertrack.c' ] ],
+ [ 'mod_vhostdb', [ 'mod_vhostdb.c' ] ],
+ [ 'mod_webdav', [ 'mod_webdav.c' ], libsqlite3 + libuuid + libxml2 ],
+ [ 'mod_wstunnel', [ 'mod_wstunnel.c' ], libcrypto ],
+]
+
+if target_machine.system() != 'windows'
+ modules += [
+ [ 'mod_cgi', [ 'mod_cgi.c' ] ],
+ ]
+endif
+
+if get_option('with_pcre') and (get_option('with_memcached') or get_option('with_gdbm'))
+ modules += [
+ [ 'mod_trigger_b4_dl', [ 'mod_trigger_b4_dl.c' ], libpcre + libmemcached + libgdbm ],
+ ]
+endif
+
+if get_option('with_lua')
+ modules += [
+ [ 'mod_cml', [ 'mod_cml.c', 'mod_cml_lua.c', 'mod_cml_funcs.c' ], liblua + libmemcached ],
+ [ 'mod_magnet', [ 'mod_magnet.c', 'mod_magnet_cache.c' ], liblua ],
+ ]
+endif
+
+if get_option('with_geoip')
+ modules += [
+ [ 'mod_geoip', [ 'mod_geoip.c' ], libgeoip ],
+ ]
+endif
+
+if get_option('with_mysql')
+ modules += [
+ [ 'mod_authn_mysql', [ 'mod_authn_mysql.c' ], libcrypt + libmysqlclient ],
+ [ 'mod_mysql_vhost', [ 'mod_mysql_vhost.c' ], libmysqlclient ],
+ [ 'mod_vhostdb_mysql', [ 'mod_vhostdb_mysql.c' ], libmysqlclient ],
+ ]
+endif
+
+if get_option('with_pgsql')
+ modules += [
+ [ 'mod_vhostdb_pgsql', [ 'mod_vhostdb_pgsql.c' ], libpq ],
+ ]
+endif
+
+if get_option('with_dbi')
+ modules += [
+ [ 'mod_vhostdb_dbi', [ 'mod_vhostdb_dbi.c' ], libdbi ],
+ ]
+endif
+
+if get_option('with_krb5')
+ modules += [
+ [ 'mod_authn_gssapi', [ 'mod_authn_gssapi.c' ], libkrb5 + libgssapi_krb5 ],
+ ]
+endif
+
+if get_option('with_ldap')
+ modules += [
+ [ 'mod_authn_ldap', [ 'mod_authn_ldap.c' ], libldap + liblber ],
+ [ 'mod_vhostdb_ldap', [ 'mod_vhostdb_ldap.c' ], libldap + liblber ],
+ ]
+endif
+
+if get_option('with_openssl')
+ modules += [
+ [ 'mod_openssl', [ 'mod_openssl.c' ], libssl + libcrypto ],
+ ]
+endif
+
+if get_option('with_wolfssl') != 'false'
+ modules += [
+ [ 'mod_openssl', [ 'mod_openssl.c' ], libcrypto ],
+ ]
+endif
+
+if get_option('with_pam')
+ modules += [
+ [ 'mod_authn_pam', [ 'mod_authn_pam.c' ], libpam ],
+ ]
+endif
+
+if get_option('with_sasl')
+ modules += [
+ [ 'mod_authn_sasl', [ 'mod_authn_sasl.c' ], libsasl ],
+ ]
+endif
+
+foreach mod: modules
+ mod_name = mod.get(0)
+ mod_sources = mod.get(1)
+ mod_deps = mod.length() > 2 ? mod.get(2) : []
+ shared_module(mod_name,
+ sources: mod_sources,
+ dependencies: [ common_flags, mod_deps ],
+ name_prefix: '',
+ install: true,
+ install_dir: moduledir,
+ )
+endforeach
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_access.c b/data/lighttpd/lighttpd-1.4.53/src/mod_access.c
new file mode 100644
index 000000000..9798f8844
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_access.c
@@ -0,0 +1,216 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ array *access_allow;
+ array *access_deny;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_access_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+FREE_FUNC(mod_access_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->access_allow);
+ array_free(s->access_deny);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_access_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "url.access-allow", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->access_deny = array_init();
+ s->access_allow = array_init();
+
+ cv[0].destination = s->access_deny;
+ cv[1].destination = s->access_allow;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->access_deny)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for url.access-deny; expected list of \"suffix\"");
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->access_allow)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for url.access-allow; expected list of \"suffix\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(access_allow);
+ PATCH(access_deny);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
+ PATCH(access_deny);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-allow"))) {
+ PATCH(access_allow);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_access_check (const array *allow, const array *deny, const buffer *urlpath, const int lc) {
+
+ if (allow->used) {
+ const buffer *match = (!lc)
+ ? array_match_value_suffix(allow, urlpath)
+ : array_match_value_suffix_nc(allow, urlpath);
+ return (match != NULL); /* allowed if match; denied if none matched */
+ }
+
+ if (deny->used) {
+ const buffer *match = (!lc)
+ ? array_match_value_suffix(deny, urlpath)
+ : array_match_value_suffix_nc(deny, urlpath);
+ return (match == NULL); /* deny if match; allow if none matched */
+ }
+
+ return 1; /* allowed (not denied) */
+}
+
+/**
+ * URI handler
+ *
+ * we will get called twice:
+ * - after the clean up of the URL and
+ * - after the pathinfo checks are done
+ *
+ * this handles the issue of trailing slashes
+ */
+URIHANDLER_FUNC(mod_access_uri_handler) {
+ plugin_data *p = p_d;
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_access_patch_connection(srv, con, p);
+
+ if (0 == p->conf.access_allow->used && 0 == p->conf.access_deny->used) {
+ return HANDLER_GO_ON; /* access allowed; nothing to match */
+ }
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_access_uri_handler called");
+ }
+
+ if (mod_access_check(p->conf.access_allow, p->conf.access_deny,
+ con->uri.path, con->conf.force_lowercase_filenames)) {
+ return HANDLER_GO_ON; /* access allowed */
+ }
+
+ /* (else) access denied */
+ if (con->conf.log_request_handling) {
+ if (p->conf.access_allow->used) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "url denied as failed to match any from access_allow", con->uri.path);
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "url denied as we match access_deny", con->uri.path);
+ }
+ }
+
+ con->http_status = 403;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+}
+
+
+int mod_access_plugin_init(plugin *p);
+int mod_access_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("access");
+
+ p->init = mod_access_init;
+ p->set_defaults = mod_access_set_defaults;
+ p->handle_uri_clean = mod_access_uri_handler;
+ p->handle_subrequest_start = mod_access_uri_handler;
+ p->cleanup = mod_access_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_accesslog.c b/data/lighttpd/lighttpd-1.4.53/src/mod_accesslog.c
new file mode 100644
index 000000000..5a64cf1dd
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_accesslog.c
@@ -0,0 +1,1167 @@
+#include "first.h"
+
+#include "base.h"
+#include "fdevent.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+#include "sock_addr.h"
+
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+typedef struct {
+ char key;
+ enum {
+ FORMAT_UNSET,
+ FORMAT_UNSUPPORTED,
+ FORMAT_PERCENT,
+ FORMAT_REMOTE_HOST,
+ FORMAT_REMOTE_IDENT,
+ FORMAT_REMOTE_USER,
+ FORMAT_TIMESTAMP,
+ FORMAT_REQUEST_LINE,
+ FORMAT_STATUS,
+ FORMAT_BYTES_OUT_NO_HEADER,
+ FORMAT_HEADER,
+
+ FORMAT_REMOTE_ADDR,
+ FORMAT_LOCAL_ADDR,
+ FORMAT_COOKIE,
+ FORMAT_TIME_USED_US,
+ FORMAT_ENV,
+ FORMAT_FILENAME,
+ FORMAT_REQUEST_PROTOCOL,
+ FORMAT_REQUEST_METHOD,
+ FORMAT_SERVER_PORT,
+ FORMAT_QUERY_STRING,
+ FORMAT_TIME_USED,
+ FORMAT_URL,
+ FORMAT_SERVER_NAME,
+ FORMAT_HTTP_HOST,
+ FORMAT_CONNECTION_STATUS,
+ FORMAT_BYTES_IN,
+ FORMAT_BYTES_OUT,
+
+ FORMAT_KEEPALIVE_COUNT,
+ FORMAT_RESPONSE_HEADER,
+ FORMAT_NOTE
+ } type;
+} format_mapping;
+
+/**
+ *
+ *
+ * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
+ *
+ */
+
+static const format_mapping fmap[] =
+{
+ { '%', FORMAT_PERCENT },
+ { 'h', FORMAT_REMOTE_HOST },
+ { 'l', FORMAT_REMOTE_IDENT },
+ { 'u', FORMAT_REMOTE_USER },
+ { 't', FORMAT_TIMESTAMP },
+ { 'r', FORMAT_REQUEST_LINE },
+ { 's', FORMAT_STATUS },
+ { 'b', FORMAT_BYTES_OUT_NO_HEADER },
+ { 'i', FORMAT_HEADER },
+
+ { 'a', FORMAT_REMOTE_ADDR },
+ { 'A', FORMAT_LOCAL_ADDR },
+ { 'B', FORMAT_BYTES_OUT_NO_HEADER },
+ { 'C', FORMAT_COOKIE },
+ { 'D', FORMAT_TIME_USED_US },
+ { 'e', FORMAT_ENV },
+ { 'f', FORMAT_FILENAME },
+ { 'H', FORMAT_REQUEST_PROTOCOL },
+ { 'k', FORMAT_KEEPALIVE_COUNT },
+ { 'm', FORMAT_REQUEST_METHOD },
+ { 'n', FORMAT_NOTE },
+ { 'p', FORMAT_SERVER_PORT },
+ { 'P', FORMAT_UNSUPPORTED }, /* we are only one process */
+ { 'q', FORMAT_QUERY_STRING },
+ { 'T', FORMAT_TIME_USED },
+ { 'U', FORMAT_URL }, /* w/o querystring */
+ { 'v', FORMAT_SERVER_NAME },
+ { 'V', FORMAT_HTTP_HOST },
+ { 'X', FORMAT_CONNECTION_STATUS },
+ { 'I', FORMAT_BYTES_IN },
+ { 'O', FORMAT_BYTES_OUT },
+
+ { 'o', FORMAT_RESPONSE_HEADER },
+
+ { '\0', FORMAT_UNSET }
+};
+
+
+enum e_optflags_time {
+ /* format string is passed to strftime unless other format optflags set
+ * (besides FORMAT_FLAG_TIME_BEGIN or FORMAT_FLAG_TIME_END) */
+ FORMAT_FLAG_TIME_END = 0x00,/* use request end time (default) */
+ FORMAT_FLAG_TIME_BEGIN = 0x01,/* use request start time */
+ FORMAT_FLAG_TIME_SEC = 0x02,/* request time as num sec since epoch */
+ FORMAT_FLAG_TIME_MSEC = 0x04,/* request time as num msec since epoch */
+ FORMAT_FLAG_TIME_USEC = 0x08,/* request time as num usec since epoch */
+ FORMAT_FLAG_TIME_NSEC = 0x10,/* request time as num nsec since epoch */
+ FORMAT_FLAG_TIME_MSEC_FRAC = 0x20,/* request time msec fraction */
+ FORMAT_FLAG_TIME_USEC_FRAC = 0x40,/* request time usec fraction */
+ FORMAT_FLAG_TIME_NSEC_FRAC = 0x80 /* request time nsec fraction */
+};
+
+enum e_optflags_port {
+ FORMAT_FLAG_PORT_LOCAL = 0x01,/* (default) */
+ FORMAT_FLAG_PORT_REMOTE = 0x02
+};
+
+
+typedef struct {
+ enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
+
+ buffer *string;
+ int field;
+ int opt;
+} format_field;
+
+typedef struct {
+ format_field **ptr;
+
+ size_t used;
+ size_t size;
+} format_fields;
+
+typedef struct {
+ buffer *access_logfile;
+ int log_access_fd;
+ buffer *access_logbuffer; /* each logfile has a separate buffer */
+
+ unsigned short use_syslog; /* syslog has global buffer */
+ unsigned short syslog_level;
+
+ buffer *format;
+
+ time_t last_generated_accesslog_ts;
+ time_t *last_generated_accesslog_ts_ptr;
+
+ buffer *ts_accesslog_str;
+
+ format_fields *parsed_format;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+
+ buffer *syslog_logbuffer; /* syslog has global buffer. no caching, always written directly */
+} plugin_data;
+
+INIT_FUNC(mod_accesslog_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+ p->syslog_logbuffer = buffer_init();
+
+ return p;
+}
+
+static void accesslog_write_all(server *srv, const buffer *filename, int fd, const void* buf, size_t count) {
+ if (-1 == write_all(fd, buf, count)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "writing access log entry failed:", filename, strerror(errno));
+ }
+}
+
+static void accesslog_append_escaped(buffer *dest, buffer *str) {
+ char *ptr, *start, *end;
+
+ /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
+ /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
+ if (buffer_string_is_empty(str)) return;
+ buffer_string_prepare_append(dest, buffer_string_length(str));
+
+ for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) {
+ unsigned char const c = (unsigned char) *ptr;
+ if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
+ /* nothing to change, add later as one block */
+ } else {
+ /* copy previous part */
+ if (start < ptr) {
+ buffer_append_string_len(dest, start, ptr - start);
+ }
+ start = ptr + 1;
+
+ switch (c) {
+ case '"':
+ BUFFER_APPEND_STRING_CONST(dest, "\\\"");
+ break;
+ case '\\':
+ BUFFER_APPEND_STRING_CONST(dest, "\\\\");
+ break;
+ case '\b':
+ BUFFER_APPEND_STRING_CONST(dest, "\\b");
+ break;
+ case '\n':
+ BUFFER_APPEND_STRING_CONST(dest, "\\n");
+ break;
+ case '\r':
+ BUFFER_APPEND_STRING_CONST(dest, "\\r");
+ break;
+ case '\t':
+ BUFFER_APPEND_STRING_CONST(dest, "\\t");
+ break;
+ case '\v':
+ BUFFER_APPEND_STRING_CONST(dest, "\\v");
+ break;
+ default: {
+ /* non printable char => \xHH */
+ char hh[5] = {'\\','x',0,0,0};
+ char h = c / 16;
+ hh[2] = (h > 9) ? (h - 10 + 'A') : (h + '0');
+ h = c % 16;
+ hh[3] = (h > 9) ? (h - 10 + 'A') : (h + '0');
+ buffer_append_string_len(dest, &hh[0], 4);
+ }
+ break;
+ }
+ }
+ }
+
+ if (start < end) {
+ buffer_append_string_len(dest, start, end - start);
+ }
+}
+
+static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
+ size_t i, j, k = 0, start = 0;
+
+ if (buffer_is_empty(format)) return -1;
+
+ for (i = 0; i < buffer_string_length(format); i++) {
+ switch(format->ptr[i]) {
+ case '%':
+ if (i > 0 && start != i) {
+ /* copy the string before this % */
+ if (fields->size == 0) {
+ fields->size = 16;
+ fields->used = 0;
+ fields->ptr = malloc(fields->size * sizeof(format_field * ));
+ } else if (fields->used == fields->size) {
+ fields->size += 16;
+ fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
+ }
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
+ fields->ptr[fields->used]->type = FIELD_STRING;
+ fields->ptr[fields->used]->string = buffer_init();
+
+ buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
+
+ fields->used++;
+ }
+
+ /* we need a new field */
+
+ if (fields->size == 0) {
+ fields->size = 16;
+ fields->used = 0;
+ fields->ptr = malloc(fields->size * sizeof(format_field * ));
+ } else if (fields->used == fields->size) {
+ fields->size += 16;
+ fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
+ }
+
+ /* search for the terminating command */
+ switch (format->ptr[i+1]) {
+ case '>':
+ case '<':
+ /* after the } has to be a character */
+ if (format->ptr[i+2] == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%< and %> have to be followed by a format-specifier");
+ return -1;
+ }
+
+
+ for (j = 0; fmap[j].key != '\0'; j++) {
+ if (fmap[j].key != format->ptr[i+2]) continue;
+
+ /* found key */
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
+ fields->ptr[fields->used]->type = FIELD_FORMAT;
+ fields->ptr[fields->used]->field = fmap[j].type;
+ fields->ptr[fields->used]->string = NULL;
+ fields->ptr[fields->used]->opt = 0;
+
+ fields->used++;
+
+ break;
+ }
+
+ if (fmap[j].key == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%< and %> have to be followed by a valid format-specifier");
+ return -1;
+ }
+
+ start = i + 3;
+ i = start - 1; /* skip the string */
+
+ break;
+ case '{':
+ /* go forward to } */
+
+ for (k = i+2; k < buffer_string_length(format); k++) {
+ if (format->ptr[k] == '}') break;
+ }
+
+ if (k == buffer_string_length(format)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{ has to be terminated by a }");
+ return -1;
+ }
+
+ /* after the } has to be a character */
+ if (format->ptr[k+1] == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be followed by a format-specifier");
+ return -1;
+ }
+
+ if (k == i + 2) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to contain a string");
+ return -1;
+ }
+
+ for (j = 0; fmap[j].key != '\0'; j++) {
+ if (fmap[j].key != format->ptr[k+1]) continue;
+
+ /* found key */
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
+ fields->ptr[fields->used]->type = FIELD_FORMAT;
+ fields->ptr[fields->used]->field = fmap[j].type;
+ fields->ptr[fields->used]->string = buffer_init();
+ fields->ptr[fields->used]->opt = 0;
+
+ buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
+
+ fields->used++;
+
+ break;
+ }
+
+ if (fmap[j].key == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be followed by a valid format-specifier");
+ return -1;
+ }
+
+ start = k + 2;
+ i = start - 1; /* skip the string */
+
+ break;
+ default:
+ /* after the % has to be a character */
+ if (format->ptr[i+1] == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "% has to be followed by a format-specifier");
+ return -1;
+ }
+
+ for (j = 0; fmap[j].key != '\0'; j++) {
+ if (fmap[j].key != format->ptr[i+1]) continue;
+
+ /* found key */
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
+ fields->ptr[fields->used]->type = FIELD_FORMAT;
+ fields->ptr[fields->used]->field = fmap[j].type;
+ fields->ptr[fields->used]->string = NULL;
+ fields->ptr[fields->used]->opt = 0;
+
+ fields->used++;
+
+ break;
+ }
+
+ if (fmap[j].key == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "% has to be followed by a valid format-specifier");
+ return -1;
+ }
+
+ start = i + 2;
+ i = start - 1; /* skip the string */
+
+ break;
+ }
+
+ break;
+ }
+ }
+
+ if (start < i) {
+ /* copy the string */
+ if (fields->size == 0) {
+ fields->size = 16;
+ fields->used = 0;
+ fields->ptr = malloc(fields->size * sizeof(format_field * ));
+ } else if (fields->used == fields->size) {
+ fields->size += 16;
+ fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
+ }
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
+ fields->ptr[fields->used]->type = FIELD_STRING;
+ fields->ptr[fields->used]->string = buffer_init();
+
+ buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
+
+ fields->used++;
+ }
+
+ return 0;
+}
+
+FREE_FUNC(mod_accesslog_free) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ if (!buffer_string_is_empty(s->access_logbuffer)) {
+ if (s->log_access_fd != -1) {
+ accesslog_write_all(srv, s->access_logfile, s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
+ }
+ }
+
+ if (s->log_access_fd != -1) {
+ if (buffer_string_is_empty(s->access_logfile) || *s->access_logfile->ptr != '|') {
+ close(s->log_access_fd);
+ } /*(else piped loggers closed in fdevent_close_logger_pipes())*/
+ }
+
+ buffer_free(s->ts_accesslog_str);
+ buffer_free(s->access_logbuffer);
+ buffer_free(s->format);
+ buffer_free(s->access_logfile);
+
+ if (s->parsed_format) {
+ size_t j;
+ for (j = 0; j < s->parsed_format->used; j++) {
+ if (s->parsed_format->ptr[j]->string) buffer_free(s->parsed_format->ptr[j]->string);
+ free(s->parsed_format->ptr[j]);
+ }
+ free(s->parsed_format->ptr);
+ free(s->parsed_format);
+ }
+
+ free(s);
+ }
+
+ free(p->config_storage);
+ }
+
+ if (p->syslog_logbuffer) buffer_free(p->syslog_logbuffer);
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(log_access_open) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
+ { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "accesslog.syslog-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->access_logfile = buffer_init();
+ s->format = buffer_init();
+ s->access_logbuffer = buffer_init();
+ s->ts_accesslog_str = buffer_init();
+ s->log_access_fd = -1;
+ s->last_generated_accesslog_ts = 0;
+ s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
+ s->syslog_level = LOG_INFO;
+
+
+ cv[0].destination = s->access_logfile;
+ cv[1].destination = &(s->use_syslog);
+ cv[2].destination = s->format;
+ cv[3].destination = &(s->syslog_level);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (i == 0 && buffer_string_is_empty(s->format)) {
+ /* set a default logfile string */
+
+ buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));
+ }
+
+ /* parse */
+
+ if (!buffer_is_empty(s->format)) {
+ size_t j, tcount = 0;
+
+ s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
+
+ if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing accesslog-definition failed:", s->format);
+
+ return HANDLER_ERROR;
+ }
+
+ for (j = 0; j < s->parsed_format->used; ++j) {
+ format_field * const f = s->parsed_format->ptr[j];
+ if (FIELD_FORMAT != f->type) continue;
+ if (FORMAT_TIMESTAMP == f->field) {
+ if (!buffer_string_is_empty(f->string)) {
+ const char *ptr = f->string->ptr;
+ if (0 == strncmp(ptr, "begin:", sizeof("begin:")-1)) {
+ f->opt |= FORMAT_FLAG_TIME_BEGIN;
+ ptr += sizeof("begin:")-1;
+ } else if (0 == strncmp(ptr, "end:", sizeof("end:")-1)) {
+ f->opt |= FORMAT_FLAG_TIME_END;
+ ptr += sizeof("end:")-1;
+ }
+ if (0 == strcmp(ptr, "sec")) f->opt |= FORMAT_FLAG_TIME_SEC;
+ else if (0 == strcmp(ptr, "msec")) f->opt |= FORMAT_FLAG_TIME_MSEC;
+ else if (0 == strcmp(ptr, "usec")) f->opt |= FORMAT_FLAG_TIME_USEC;
+ else if (0 == strcmp(ptr, "nsec")) f->opt |= FORMAT_FLAG_TIME_NSEC;
+ else if (0 == strcmp(ptr, "msec_frac")) f->opt |= FORMAT_FLAG_TIME_MSEC_FRAC;
+ else if (0 == strcmp(ptr, "usec_frac")) f->opt |= FORMAT_FLAG_TIME_USEC_FRAC;
+ else if (0 == strcmp(ptr, "nsec_frac")) f->opt |= FORMAT_FLAG_TIME_NSEC_FRAC;
+ else if (NULL == strchr(ptr, '%')) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "constant string for time format (misspelled token? or missing '%'):", s->format);
+
+ return HANDLER_ERROR;
+ }
+ }
+
+ /* make sure they didn't try to send the timestamp in twice
+ * (would invalidate s->ts_accesslog_str cache of timestamp str) */
+ if (!(f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END|FORMAT_FLAG_TIME_SEC)) && ++tcount > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "you may not use strftime timestamp format %{}t twice in the same access log:", s->format);
+
+ return HANDLER_ERROR;
+ }
+
+ if (f->opt & FORMAT_FLAG_TIME_BEGIN) srv->srvconf.high_precision_timestamps = 1;
+ } else if (FORMAT_TIME_USED_US == f->field) {
+ f->opt |= FORMAT_FLAG_TIME_USEC;
+ srv->srvconf.high_precision_timestamps = 1;
+ } else if (FORMAT_TIME_USED == f->field) {
+ if (buffer_string_is_empty(f->string)
+ || buffer_is_equal_string(f->string, CONST_STR_LEN("s"))
+ || buffer_is_equal_string(f->string, CONST_STR_LEN("sec"))) f->opt |= FORMAT_FLAG_TIME_SEC;
+ else if (buffer_is_equal_string(f->string, CONST_STR_LEN("ms"))
+ || buffer_is_equal_string(f->string, CONST_STR_LEN("msec"))) f->opt |= FORMAT_FLAG_TIME_MSEC;
+ else if (buffer_is_equal_string(f->string, CONST_STR_LEN("us"))
+ || buffer_is_equal_string(f->string, CONST_STR_LEN("usec"))) f->opt |= FORMAT_FLAG_TIME_USEC;
+ else if (buffer_is_equal_string(f->string, CONST_STR_LEN("ns"))
+ || buffer_is_equal_string(f->string, CONST_STR_LEN("nsec"))) f->opt |= FORMAT_FLAG_TIME_NSEC;
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid time unit in %{UNIT}T:", s->format);
+
+ return HANDLER_ERROR;
+ }
+
+ if (f->opt & ~(FORMAT_FLAG_TIME_SEC)) srv->srvconf.high_precision_timestamps = 1;
+ } else if (FORMAT_COOKIE == f->field) {
+ if (buffer_string_is_empty(f->string)) f->type = FIELD_STRING; /*(blank)*/
+ } else if (FORMAT_SERVER_PORT == f->field) {
+ if (buffer_string_is_empty(f->string))
+ f->opt |= FORMAT_FLAG_PORT_LOCAL;
+ else if (buffer_is_equal_string(f->string, CONST_STR_LEN("canonical")))
+ f->opt |= FORMAT_FLAG_PORT_LOCAL;
+ else if (buffer_is_equal_string(f->string, CONST_STR_LEN("local")))
+ f->opt |= FORMAT_FLAG_PORT_LOCAL;
+ else if (buffer_is_equal_string(f->string, CONST_STR_LEN("remote")))
+ f->opt |= FORMAT_FLAG_PORT_REMOTE;
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid format %{canonical,local,remote}p:", s->format);
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+#if 0
+ /* debugging */
+ for (j = 0; j < s->parsed_format->used; j++) {
+ switch (s->parsed_format->ptr[j]->type) {
+ case FIELD_FORMAT:
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
+ "config:", "format", s->parsed_format->ptr[j]->field,
+ s->parsed_format->ptr[j]->string ?
+ s->parsed_format->ptr[j]->string->ptr : "" );
+ break;
+ case FIELD_STRING:
+ log_error_write(srv, __FILE__, __LINE__, "ssbs", "config:", "string '", s->parsed_format->ptr[j]->string, "'");
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ }
+
+ if (s->use_syslog) {
+ /* ignore the next checks */
+ continue;
+ }
+
+ if (buffer_string_is_empty(s->access_logfile)) continue;
+
+ if (srv->srvconf.preflight_check) continue;
+
+ if (-1 == (s->log_access_fd = fdevent_open_logger(s->access_logfile->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "SBSS",
+ "opening log '", s->access_logfile,
+ "' failed: ", strerror(errno));
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static void log_access_flush(server *srv, void *p_d) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!buffer_string_is_empty(s->access_logbuffer)) {
+ if (s->log_access_fd != -1) {
+ accesslog_write_all(srv, s->access_logfile, s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
+ }
+
+ buffer_clear(s->access_logbuffer);
+ }
+ }
+}
+
+TRIGGER_FUNC(log_access_periodic_flush) {
+ /* flush buffered access logs every 4 seconds */
+ if (0 == (srv->cur_ts & 3)) log_access_flush(srv, p_d);
+ return HANDLER_GO_ON;
+}
+
+SIGHUP_FUNC(log_access_cycle) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ if (!p->config_storage) return HANDLER_GO_ON;
+
+ log_access_flush(srv, p);
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (s->use_syslog == 0
+ && !buffer_string_is_empty(s->access_logfile)
+ && s->access_logfile->ptr[0] != '|') {
+
+ if (-1 == fdevent_cycle_logger(s->access_logfile->ptr, &s->log_access_fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(access_logfile);
+ PATCH(log_access_fd);
+ PATCH(last_generated_accesslog_ts_ptr);
+ PATCH(access_logbuffer);
+ PATCH(ts_accesslog_str);
+ PATCH(parsed_format);
+ PATCH(use_syslog);
+ PATCH(syslog_level);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
+ PATCH(access_logfile);
+ PATCH(log_access_fd);
+ PATCH(access_logbuffer);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
+ PATCH(parsed_format);
+ PATCH(last_generated_accesslog_ts_ptr);
+ PATCH(ts_accesslog_str);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
+ PATCH(use_syslog);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.syslog-level"))) {
+ PATCH(syslog_level);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+REQUESTDONE_FUNC(log_access_write) {
+ plugin_data *p = p_d;
+ buffer *b;
+ size_t j;
+
+ int newts = 0;
+ buffer *vb;
+ struct timespec ts = { 0, 0 };
+
+ mod_accesslog_patch_connection(srv, con, p);
+
+ /* No output device, nothing to do */
+ if (!p->conf.use_syslog && p->conf.log_access_fd == -1) return HANDLER_GO_ON;
+
+ if (p->conf.use_syslog) {
+ b = p->syslog_logbuffer;
+ } else {
+ b = p->conf.access_logbuffer;
+ }
+
+ for (j = 0; j < p->conf.parsed_format->used; j++) {
+ const format_field * const f = p->conf.parsed_format->ptr[j];
+ switch(f->type) {
+ case FIELD_STRING:
+ buffer_append_string_buffer(b, f->string);
+ break;
+ case FIELD_FORMAT:
+ switch(f->field) {
+ case FORMAT_TIMESTAMP:
+
+ if (f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END)) {
+ if (f->opt & FORMAT_FLAG_TIME_SEC) {
+ time_t t = (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) ? srv->cur_ts : con->request_start;
+ buffer_append_int(b, (intmax_t)t);
+ } else if (f->opt & (FORMAT_FLAG_TIME_MSEC|FORMAT_FLAG_TIME_USEC|FORMAT_FLAG_TIME_NSEC)) {
+ off_t t; /*(expected to be 64-bit since large file support enabled)*/
+ long ns;
+ if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
+ if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts);
+ t = (off_t)ts.tv_sec;
+ ns = ts.tv_nsec;
+ } else {
+ t = (off_t)con->request_start_hp.tv_sec;
+ ns = con->request_start_hp.tv_nsec;
+ }
+ if (f->opt & FORMAT_FLAG_TIME_MSEC) {
+ t *= 1000;
+ t += (ns + 999999) / 1000000; /* ceil */
+ } else if (f->opt & FORMAT_FLAG_TIME_USEC) {
+ t *= 1000000;
+ t += (ns + 999) / 1000; /* ceil */
+ } else {/*(f->opt & FORMAT_FLAG_TIME_NSEC)*/
+ t *= 1000000000;
+ t += ns;
+ }
+ buffer_append_int(b, (intmax_t)t);
+ } else { /*(FORMAT_FLAG_TIME_MSEC_FRAC|FORMAT_FLAG_TIME_USEC_FRAC|FORMAT_FLAG_TIME_NSEC_FRAC)*/
+ long ns;
+ char *ptr;
+ if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
+ if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts);
+ ns = ts.tv_nsec;
+ } else {
+ ns = con->request_start_hp.tv_nsec;
+ }
+ /*assert(t < 1000000000);*/
+ if (f->opt & FORMAT_FLAG_TIME_MSEC_FRAC) {
+ ns += 999999; /* ceil */
+ ns /= 1000000;
+ buffer_append_string_len(b, CONST_STR_LEN("000"));
+ } else if (f->opt & FORMAT_FLAG_TIME_USEC_FRAC) {
+ ns += 999; /* ceil */
+ ns /= 1000;
+ buffer_append_string_len(b, CONST_STR_LEN("000000"));
+ } else {/*(f->opt & FORMAT_FLAG_TIME_NSEC_FRAC)*/
+ buffer_append_string_len(b, CONST_STR_LEN("000000000"));
+ }
+ for (ptr = b->ptr + buffer_string_length(b); ns > 0; ns /= 10)
+ *--ptr = (ns % 10) + '0';
+ }
+ } else if (!(f->opt & FORMAT_FLAG_TIME_BEGIN) && srv->cur_ts == *(p->conf.last_generated_accesslog_ts_ptr)) {
+ buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
+ } else {
+ /* cache the generated timestamp (only if ! FORMAT_FLAG_TIME_BEGIN) */
+ struct tm *tmptr;
+ time_t t;
+ #if defined(HAVE_STRUCT_TM_GMTOFF)
+ # ifdef HAVE_LOCALTIME_R
+ struct tm tm;
+ # endif /* HAVE_LOCALTIME_R */
+ #else /* HAVE_STRUCT_TM_GMTOFF */
+ # ifdef HAVE_GMTIME_R
+ struct tm tm;
+ # endif /* HAVE_GMTIME_R */
+ #endif /* HAVE_STRUCT_TM_GMTOFF */
+
+ if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
+ t = *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
+ newts = 1;
+ } else {
+ t = con->request_start;
+ }
+
+ #if defined(HAVE_STRUCT_TM_GMTOFF)
+ # ifdef HAVE_LOCALTIME_R
+ tmptr = localtime_r(&t, &tm);
+ # else /* HAVE_LOCALTIME_R */
+ tmptr = localtime(&t);
+ # endif /* HAVE_LOCALTIME_R */
+ #else /* HAVE_STRUCT_TM_GMTOFF */
+ # ifdef HAVE_GMTIME_R
+ tmptr = gmtime_r(&t, &tm);
+ # else /* HAVE_GMTIME_R */
+ tmptr = gmtime(&t);
+ # endif /* HAVE_GMTIME_R */
+ #endif /* HAVE_STRUCT_TM_GMTOFF */
+
+ buffer_clear(p->conf.ts_accesslog_str);
+
+ if (buffer_string_is_empty(f->string)) {
+ #if defined(HAVE_STRUCT_TM_GMTOFF)
+ long scd, hrs, min;
+ buffer_append_strftime(p->conf.ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S ", tmptr);
+ buffer_append_string_len(p->conf.ts_accesslog_str, tmptr->tm_gmtoff >= 0 ? "+" : "-", 1);
+
+ scd = labs(tmptr->tm_gmtoff);
+ hrs = scd / 3600;
+ min = (scd % 3600) / 60;
+
+ /* hours */
+ if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
+ buffer_append_int(p->conf.ts_accesslog_str, hrs);
+
+ if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
+ buffer_append_int(p->conf.ts_accesslog_str, min);
+ buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));
+ #else
+ buffer_append_strftime(p->conf.ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S +0000]", tmptr);
+ #endif /* HAVE_STRUCT_TM_GMTOFF */
+ } else {
+ buffer_append_strftime(p->conf.ts_accesslog_str, f->string->ptr, tmptr);
+ }
+
+ buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
+ }
+ break;
+ case FORMAT_TIME_USED:
+ case FORMAT_TIME_USED_US:
+ if (f->opt & FORMAT_FLAG_TIME_SEC) {
+ buffer_append_int(b, srv->cur_ts - con->request_start);
+ } else {
+ const struct timespec * const bs = &con->request_start_hp;
+ off_t tdiff; /*(expected to be 64-bit since large file support enabled)*/
+ if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts);
+ tdiff = (off_t)(ts.tv_sec - bs->tv_sec)*1000000000 + (ts.tv_nsec - bs->tv_nsec);
+ if (tdiff <= 0) {
+ /* sanity check for time moving backwards
+ * (daylight savings adjustment or leap seconds or ?) */
+ tdiff = -1;
+ } else if (f->opt & FORMAT_FLAG_TIME_MSEC) {
+ tdiff += 999999; /* ceil */
+ tdiff /= 1000000;
+ } else if (f->opt & FORMAT_FLAG_TIME_USEC) {
+ tdiff += 999; /* ceil */
+ tdiff /= 1000;
+ } /* else (f->opt & FORMAT_FLAG_TIME_NSEC) */
+ buffer_append_int(b, (intmax_t)tdiff);
+ }
+ break;
+ case FORMAT_REMOTE_ADDR:
+ case FORMAT_REMOTE_HOST:
+ buffer_append_string_buffer(b, con->dst_addr_buf);
+ break;
+ case FORMAT_REMOTE_IDENT:
+ /* ident */
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ break;
+ case FORMAT_REMOTE_USER:
+ if (NULL != (vb = http_header_env_get(con, CONST_STR_LEN("REMOTE_USER")))) {
+ accesslog_append_escaped(b, vb);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_REQUEST_LINE:
+ if (!buffer_string_is_empty(con->request.request_line)) {
+ accesslog_append_escaped(b, con->request.request_line);
+ }
+ break;
+ case FORMAT_STATUS:
+ buffer_append_int(b, con->http_status);
+ break;
+
+ case FORMAT_BYTES_OUT_NO_HEADER:
+ if (con->bytes_written > 0) {
+ buffer_append_int(b,
+ con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_HEADER:
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(f->string)))) {
+ accesslog_append_escaped(b, vb);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_RESPONSE_HEADER:
+ if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(f->string)))) {
+ accesslog_append_escaped(b, vb);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_ENV:
+ case FORMAT_NOTE:
+ if (NULL != (vb = http_header_env_get(con, CONST_BUF_LEN(f->string)))) {
+ accesslog_append_escaped(b, vb);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_FILENAME:
+ if (!buffer_string_is_empty(con->physical.path)) {
+ buffer_append_string_buffer(b, con->physical.path);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_BYTES_OUT:
+ if (con->bytes_written > 0) {
+ buffer_append_int(b, con->bytes_written);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_BYTES_IN:
+ if (con->bytes_read > 0) {
+ buffer_append_int(b, con->bytes_read);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_SERVER_NAME:
+ if (!buffer_string_is_empty(con->server_name)) {
+ buffer_append_string_buffer(b, con->server_name);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_HTTP_HOST:
+ if (!buffer_string_is_empty(con->uri.authority)) {
+ accesslog_append_escaped(b, con->uri.authority);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_REQUEST_PROTOCOL:
+ buffer_append_string_len(b,
+ con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0", 8);
+ break;
+ case FORMAT_REQUEST_METHOD:
+ http_method_append(b, con->request.http_method);
+ break;
+ case FORMAT_PERCENT:
+ buffer_append_string_len(b, CONST_STR_LEN("%"));
+ break;
+ case FORMAT_LOCAL_ADDR:
+ {
+ /* (perf: not using getsockname() and inet_ntop_cache_get_ip())
+ * (still useful if admin has configured explicit listen IPs) */
+ const char *colon;
+ buffer *srvtoken = con->srv_socket->srv_token;
+ if (srvtoken->ptr[0] == '[') {
+ colon = strstr(srvtoken->ptr, "]:");
+ } else {
+ colon = strchr(srvtoken->ptr, ':');
+ }
+ if (colon) {
+ buffer_append_string_len(b, srvtoken->ptr, (size_t)(colon - srvtoken->ptr));
+ } else {
+ buffer_append_string_buffer(b, srvtoken);
+ }
+ }
+ break;
+ case FORMAT_SERVER_PORT:
+ if (f->opt & FORMAT_FLAG_PORT_REMOTE) {
+ buffer_append_int(b, sock_addr_get_port(&con->dst_addr));
+ } else { /* if (f->opt & FORMAT_FLAG_PORT_LOCAL) *//*(default)*/
+ const char *colon;
+ buffer *srvtoken = ((server_socket*)(con->srv_socket))->srv_token;
+ if (srvtoken->ptr[0] == '[') {
+ colon = strstr(srvtoken->ptr, "]:");
+ } else {
+ colon = strchr(srvtoken->ptr, ':');
+ }
+ if (colon) {
+ buffer_append_string(b, colon+1);
+ } else {
+ buffer_append_int(b, srv->srvconf.port);
+ }
+ }
+ break;
+ case FORMAT_QUERY_STRING:
+ accesslog_append_escaped(b, con->uri.query);
+ break;
+ case FORMAT_URL:
+ accesslog_append_escaped(b, con->uri.path_raw);
+ break;
+ case FORMAT_CONNECTION_STATUS:
+ if (con->state == CON_STATE_RESPONSE_END) {
+ if (0 == con->keep_alive) {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("+"));
+ }
+ } else { /* CON_STATE_ERROR */
+ buffer_append_string_len(b, CONST_STR_LEN("X"));
+ }
+ break;
+ case FORMAT_KEEPALIVE_COUNT:
+ if (con->request_count > 1) {
+ buffer_append_int(b, (intmax_t)(con->request_count-1));
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("0"));
+ }
+ break;
+ case FORMAT_COOKIE:
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_COOKIE, CONST_STR_LEN("Cookie")))) {
+ char *str = vb->ptr;
+ size_t len = buffer_string_length(f->string);
+ do {
+ while (*str == ' ' || *str == '\t') ++str;
+ if (0 == strncmp(str, f->string->ptr, len) && str[len] == '=') {
+ char *v = str+len+1;
+ buffer *bstr;
+ for (str = v; *str != '\0' && *str != ';'; ++str) ;
+ if (str == v) break;
+ do { --str; } while (str > v && (*str == ' ' || *str == '\t'));
+ bstr = buffer_init();
+ buffer_copy_string_len(bstr, v, str - v + 1);
+ accesslog_append_escaped(b, bstr);
+ buffer_free(bstr);
+ break;
+ } else {
+ do { ++str; } while (*str != ' ' && *str != '\t' && *str != '\0');
+ }
+ while (*str == ' ' || *str == '\t') ++str;
+ } while (*str++ == ';');
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (p->conf.use_syslog) { /* syslog doesn't cache */
+#ifdef HAVE_SYSLOG_H
+ if (!buffer_string_is_empty(b)) {
+ /*(syslog appends a \n on its own)*/
+ syslog(p->conf.syslog_level, "%s", b->ptr);
+ }
+#endif
+ buffer_clear(b);
+ return HANDLER_GO_ON;
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ if ((!buffer_string_is_empty(p->conf.access_logfile) && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */
+ newts ||
+ buffer_string_length(b) >= BUFFER_MAX_REUSE_SIZE) {
+ if (p->conf.log_access_fd >= 0) {
+ accesslog_write_all(srv, p->conf.access_logfile, p->conf.log_access_fd, CONST_BUF_LEN(b));
+ }
+ buffer_clear(b);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_accesslog_plugin_init(plugin *p);
+int mod_accesslog_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("accesslog");
+
+ p->init = mod_accesslog_init;
+ p->set_defaults= log_access_open;
+ p->cleanup = mod_accesslog_free;
+
+ p->handle_request_done = log_access_write;
+ p->handle_trigger = log_access_periodic_flush;
+ p->handle_sighup = log_access_cycle;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_alias.c b/data/lighttpd/lighttpd-1.4.53/src/mod_alias.c
new file mode 100644
index 000000000..cd9414ff5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_alias.c
@@ -0,0 +1,219 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* plugin config for all request/connections */
+typedef struct {
+ array *alias;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_alias_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_alias_free) {
+ plugin_data *p = p_d;
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->alias);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_alias_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->alias = array_init();
+ cv[0].destination = s->alias;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->alias)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for alias.url; expected list of \"urlpath\" => \"filepath\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->alias->used >= 2) {
+ const array *a = s->alias;
+ size_t j, k;
+
+ for (j = 0; j < a->used; j ++) {
+ const buffer *prefix = a->data[a->sorted[j]]->key;
+ for (k = j + 1; k < a->used; k ++) {
+ const buffer *key = a->data[a->sorted[k]]->key;
+
+ if (buffer_string_length(key) < buffer_string_length(prefix)) {
+ break;
+ }
+ if (memcmp(key->ptr, prefix->ptr, buffer_string_length(prefix)) != 0) {
+ break;
+ }
+ /* ok, they have same prefix. check position */
+ if (a->sorted[j] < a->sorted[k]) {
+ log_error_write(srv, __FILE__, __LINE__, "SBSBS",
+ "url.alias: `", key, "' will never match as `", prefix, "' matched first");
+ return HANDLER_ERROR;
+ }
+ }
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(alias);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
+ PATCH(alias);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+PHYSICALPATH_FUNC(mod_alias_physical_handler) {
+ plugin_data *p = p_d;
+ char *uri_ptr;
+ size_t uri_len = buffer_string_length(con->physical.path);
+ size_t basedir_len, alias_len;
+ data_string *ds;
+
+ if (0 == uri_len) return HANDLER_GO_ON;
+
+ mod_alias_patch_connection(srv, con, p);
+
+ /* do not include trailing slash on basedir */
+ basedir_len = buffer_string_length(con->physical.basedir);
+ if ('/' == con->physical.basedir->ptr[basedir_len-1]) --basedir_len;
+ uri_len -= basedir_len;
+ uri_ptr = con->physical.path->ptr + basedir_len;
+
+ ds = (!con->conf.force_lowercase_filenames)
+ ? (data_string *)array_match_key_prefix_klen(p->conf.alias, uri_ptr, uri_len)
+ : (data_string *)array_match_key_prefix_nc_klen(p->conf.alias, uri_ptr, uri_len);
+ if (NULL == ds) { return HANDLER_GO_ON; }
+
+ /* matched */
+
+ /* check for path traversal in url-path following alias if key
+ * does not end in slash, but replacement value ends in slash */
+ alias_len = buffer_string_length(ds->key);
+ if (uri_ptr[alias_len] == '.') {
+ char *s = uri_ptr + alias_len + 1;
+ if (*s == '.') ++s;
+ if (*s == '/' || *s == '\0') {
+ size_t vlen = buffer_string_length(ds->value);
+ if (0 != alias_len && ds->key->ptr[alias_len-1] != '/'
+ && 0 != vlen && ds->value->ptr[vlen-1] == '/') {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ }
+ }
+
+ buffer_copy_buffer(con->physical.basedir, ds->value);
+ buffer_copy_buffer(srv->tmp_buf, ds->value);
+ buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
+ buffer_copy_buffer(con->physical.path, srv->tmp_buf);
+
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_alias_plugin_init(plugin *p);
+int mod_alias_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("alias");
+
+ p->init = mod_alias_init;
+ p->handle_physical= mod_alias_physical_handler;
+ p->set_defaults = mod_alias_set_defaults;
+ p->cleanup = mod_alias_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_auth.c b/data/lighttpd/lighttpd-1.4.53/src/mod_auth.c
new file mode 100644
index 000000000..977b5c2dd
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_auth.c
@@ -0,0 +1,888 @@
+#include "first.h"
+
+#include "base.h"
+#include "plugin.h"
+#include "http_auth.h"
+#include "http_header.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * auth framework
+ */
+
+typedef struct {
+ /* auth */
+ array *auth_require;
+ buffer *auth_backend_conf;
+ unsigned short auth_extern_authn;
+
+ /* generated */
+ const http_auth_backend_t *auth_backend;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+static handler_t mod_auth_check_basic(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
+static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
+static handler_t mod_auth_check_extern(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
+
+INIT_FUNC(mod_auth_init) {
+ static const http_auth_scheme_t http_auth_scheme_basic = { "basic", mod_auth_check_basic, NULL };
+ static const http_auth_scheme_t http_auth_scheme_digest = { "digest", mod_auth_check_digest, NULL };
+ static const http_auth_scheme_t http_auth_scheme_extern = { "extern", mod_auth_check_extern, NULL };
+ plugin_data *p;
+
+ /* register http_auth_scheme_* */
+ http_auth_scheme_set(&http_auth_scheme_basic);
+ http_auth_scheme_set(&http_auth_scheme_digest);
+ http_auth_scheme_set(&http_auth_scheme_extern);
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+FREE_FUNC(mod_auth_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 (NULL == s) continue;
+
+ array_free(s->auth_require);
+ buffer_free(s->auth_backend_conf);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* data type for mod_auth structured data
+ * (parsed from auth.require array of strings) */
+typedef struct {
+ DATA_UNSET;
+ http_auth_require_t *require;
+} data_auth;
+
+static void data_auth_free(data_unset *d)
+{
+ data_auth * const dauth = (data_auth *)d;
+ buffer_free(dauth->key);
+ http_auth_require_free(dauth->require);
+ free(dauth);
+}
+
+static data_auth *data_auth_init(void)
+{
+ static const struct data_methods fn = {
+ NULL, /* reset must not be called on this data */
+ NULL, /* copy must not be called on this data */
+ data_auth_free,
+ NULL, /* insert_dup must not be called on this data */
+ NULL /* print must not be called on this data */
+ };
+ data_auth * const dauth = calloc(1, sizeof(*dauth));
+ force_assert(NULL != dauth);
+ dauth->type = TYPE_OTHER;
+ dauth->fn = &fn;
+
+ dauth->key = buffer_init();
+ dauth->require = http_auth_require_init();
+
+ return dauth;
+}
+
+static int mod_auth_require_parse (server *srv, http_auth_require_t * const require, const buffer *b)
+{
+ /* user=name1|user=name2|group=name3|host=name4 */
+
+ const char *str = b->ptr;
+ const char *p;
+
+ if (buffer_is_equal_string(b, CONST_STR_LEN("valid-user"))) {
+ require->valid_user = 1;
+ return 1; /* success */
+ }
+
+ do {
+ const char *eq;
+ size_t len;
+ p = strchr(str, '|');
+ len = NULL != p ? (size_t)(p - str) : strlen(str);
+ eq = memchr(str, '=', len);
+ if (NULL == eq) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbss",
+ "error parsing auth.require 'require' field: missing '='",
+ "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\").",
+ "error value:", b, "error near:", str);
+ return 0;
+ }
+ if (p-1 == eq) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbss",
+ "error parsing auth.require 'require' field: missing token after '='",
+ "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\").",
+ "error value:", b, "error near:", str);
+ return 0;
+ }
+
+ switch ((int)(eq - str)) {
+ case 4:
+ if (0 == memcmp(str, CONST_STR_LEN("user"))) {
+ /*("user=" is 5)*/
+ array_set_key_value(require->user, str+5, len-5, CONST_STR_LEN(""));
+ continue;
+ }
+ else if (0 == memcmp(str, CONST_STR_LEN("host"))) {
+ /*("host=" is 5)*/
+ array_set_key_value(require->host, str+5, len-5, CONST_STR_LEN(""));
+ log_error_write(srv, __FILE__, __LINE__, "ssb",
+ "warning parsing auth.require 'require' field: 'host' not implemented;",
+ "field value:", b);
+ continue;
+ }
+ break; /* to error */
+ case 5:
+ if (0 == memcmp(str, CONST_STR_LEN("group"))) {
+ /*("group=" is 6)*/
+ array_set_key_value(require->group, str+6, len-6, CONST_STR_LEN(""));
+ #if 0/*(supported by mod_authn_ldap, but not all other backends)*/
+ log_error_write(srv, __FILE__, __LINE__, "ssb",
+ "warning parsing auth.require 'require' field: 'group' not implemented;",
+ "field value:", b);
+ #endif
+ continue;
+ }
+ break; /* to error */
+ case 10:
+ if (0 == memcmp(str, CONST_STR_LEN("valid-user"))) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
+ "error parsing auth.require 'require' field: valid user can not be combined with other require rules",
+ "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\").",
+ "error value:", b);
+ return 0;
+ }
+ break; /* to error */
+ default:
+ break; /* to error */
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "sssbss",
+ "error parsing auth.require 'require' field: invalid/unsupported token",
+ "(expecting \"valid-user\" or \"user=a|user=b|group=g|host=h\").",
+ "error value:", b, "error near:", str);
+ return 0;
+
+ } while (p && *((str = p+1)));
+
+ return 1; /* success */
+}
+
+SETDEFAULTS_FUNC(mod_auth_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ config_values_t cv[] = {
+ { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "auth.extern-authn", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },/* 2 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+ size_t n;
+ data_array *da;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->auth_backend_conf = buffer_init();
+
+ s->auth_require = array_init();
+
+ cv[0].destination = s->auth_backend_conf;
+ cv[1].destination = s->auth_require; /* T_CONFIG_LOCAL; not modified by config_insert_values_global() */
+ cv[2].destination = &s->auth_extern_authn;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->auth_backend_conf)) {
+ s->auth_backend = http_auth_backend_get(s->auth_backend_conf);
+ if (NULL == s->auth_backend) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
+
+ return HANDLER_ERROR;
+ }
+ }
+
+ /* no auth.require for this section */
+ if (NULL == (da = (data_array *)array_get_element(config->value, "auth.require"))) continue;
+
+ if (da->type != TYPE_ARRAY || !array_is_kvarray(da->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "unexpected value for auth.require; expected ",
+ "auth.require = ( \"urlpath\" => ( \"option\" => \"value\" ) )");
+ return HANDLER_ERROR;
+ }
+
+
+ for (n = 0; n < da->value->used; n++) {
+ size_t m;
+ data_array *da_file = (data_array *)da->value->data[n];
+ const buffer *method = NULL, *realm = NULL, *require = NULL;
+ const http_auth_scheme_t *auth_scheme;
+
+ if (!array_is_kvstring(da_file->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "unexpected value for auth.require; expected ",
+ "auth.require = ( \"urlpath\" => ( \"option\" => \"value\" ) )");
+
+ return HANDLER_ERROR;
+ }
+
+ for (m = 0; m < da_file->value->used; m++) {
+ if (da_file->value->data[m]->type == TYPE_STRING) {
+ data_string *ds = (data_string *)da_file->value->data[m];
+ if (buffer_is_equal_string(ds->key, CONST_STR_LEN("method"))) {
+ method = ds->value;
+ } else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("realm"))) {
+ realm = ds->value;
+ } else if (buffer_is_equal_string(ds->key, CONST_STR_LEN("require"))) {
+ require = ds->value;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssbs",
+ "the field is unknown in:",
+ "auth.require = ( \"...\" => ( ..., -> \"",
+ da_file->value->data[m]->key,
+ "\" <- => \"...\" ) )");
+
+ return HANDLER_ERROR;
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ssbs",
+ "a string was expected for:",
+ "auth.require = ( \"...\" => ( ..., -> \"",
+ da_file->value->data[m]->key,
+ "\" <- => \"...\" ) )");
+
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (buffer_string_is_empty(method)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "the method field is missing or blank in:",
+ "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
+ return HANDLER_ERROR;
+ } else {
+ auth_scheme = http_auth_scheme_get(method);
+ if (NULL == auth_scheme) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "unknown method", method, "(e.g. \"basic\", \"digest\" or \"extern\") in",
+ "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (buffer_is_empty(realm)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "the realm field is missing in:",
+ "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
+ return HANDLER_ERROR;
+ }
+
+ if (buffer_string_is_empty(require)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "the require field is missing or blank in:",
+ "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
+ return HANDLER_ERROR;
+ }
+
+ if (require) { /*(always true at this point)*/
+ data_auth * const dauth = data_auth_init();
+ buffer_copy_buffer(dauth->key, da_file->key);
+ dauth->require->scheme = auth_scheme;
+ buffer_copy_buffer(dauth->require->realm, realm);
+ if (!mod_auth_require_parse(srv, dauth->require, require)) {
+ dauth->fn->free((data_unset *)dauth);
+ return HANDLER_ERROR;
+ }
+ array_insert_unique(s->auth_require, (data_unset *)dauth);
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_auth_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(auth_backend);
+ PATCH(auth_require);
+ PATCH(auth_extern_authn);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
+ PATCH(auth_backend);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
+ PATCH(auth_require);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.extern-authn"))) {
+ PATCH(auth_extern_authn);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ data_auth *dauth;
+
+ mod_auth_patch_connection(srv, con, p);
+
+ if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
+
+ /* search auth directives for first prefix match against URL path */
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+ dauth = (!con->conf.force_lowercase_filenames)
+ ? (data_auth *)array_match_key_prefix(p->conf.auth_require, con->uri.path)
+ : (data_auth *)array_match_key_prefix_nc(p->conf.auth_require, con->uri.path);
+ if (NULL == dauth) return HANDLER_GO_ON;
+
+ {
+ const http_auth_scheme_t * const scheme = dauth->require->scheme;
+ if (p->conf.auth_extern_authn) {
+ buffer *vb = http_header_env_get(con, CONST_STR_LEN("REMOTE_USER"));
+ if (NULL != vb && http_auth_match_rules(dauth->require, vb->ptr, NULL, NULL)) {
+ return HANDLER_GO_ON;
+ }
+ }
+ return scheme->checkfn(srv, con, scheme->p_d, dauth->require, p->conf.auth_backend);
+ }
+}
+
+int mod_auth_plugin_init(plugin *p);
+int mod_auth_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("auth");
+ p->init = mod_auth_init;
+ p->set_defaults = mod_auth_set_defaults;
+ p->handle_uri_clean = mod_auth_uri_handler;
+ p->cleanup = mod_auth_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
+
+
+
+/*
+ * auth schemes (basic, digest, extern)
+ *
+ * (could be in separate file from mod_auth.c as long as registration occurs)
+ */
+
+#include "base64.h"
+#include "md5.h"
+#include "rand.h"
+#include "http_header.h"
+
+static handler_t mod_auth_send_400_bad_request(server *srv, connection *con) {
+ UNUSED(srv);
+
+ /* a field was missing or invalid */
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_auth_send_401_unauthorized_basic(server *srv, connection *con, buffer *realm) {
+ con->http_status = 401;
+ con->mode = DIRECT;
+
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("Basic realm=\""));
+ buffer_append_string_buffer(srv->tmp_buf, realm);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\", charset=\"UTF-8\""));
+
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(srv->tmp_buf));
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_auth_check_basic(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend) {
+ buffer *b = http_header_request_get(con, HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization"));
+ buffer *username;
+ char *pw;
+ handler_t rc = HANDLER_UNSET;
+
+ UNUSED(p_d);
+
+ if (NULL == backend) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not configured for", con->uri.path);
+ con->http_status = 500;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ if (NULL == b) {
+ return mod_auth_send_401_unauthorized_basic(srv, con, require->realm);
+ }
+
+ if (0 != strncasecmp(b->ptr, "Basic ", sizeof("Basic ")-1)) {
+ return mod_auth_send_401_unauthorized_basic(srv, con, require->realm);
+ }
+ #ifdef __COVERITY__
+ if (buffer_string_length(b) < sizeof("Basic ")-1) {
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+ #endif
+
+ username = buffer_init();
+
+ /* coverity[overflow_sink : FALSE] */
+ if (!buffer_append_base64_decode(username, b->ptr+sizeof("Basic ")-1, buffer_string_length(b)-(sizeof("Basic ")-1), BASE64_STANDARD)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "decoding base64-string failed", username);
+
+ buffer_free(username);
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+
+ /* r2 == user:password */
+ if (NULL == (pw = strchr(username->ptr, ':'))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "missing ':' in", username);
+
+ buffer_free(username);
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+
+ buffer_string_set_length(username, pw - username->ptr);
+ pw++;
+
+ rc = backend->basic(srv, con, backend->p_d, require, username, pw);
+ switch (rc) {
+ case HANDLER_GO_ON:
+ http_auth_setenv(con, CONST_BUF_LEN(username), CONST_STR_LEN("Basic"));
+ break;
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_FINISHED:
+ break;
+ case HANDLER_ERROR:
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sbsBsB", "password doesn't match for", con->uri.path, "username:", username, ", IP:", con->dst_addr_buf);
+ rc = HANDLER_UNSET;
+ break;
+ }
+
+ buffer_free(username);
+ return (HANDLER_UNSET != rc) ? rc : mod_auth_send_401_unauthorized_basic(srv, con, require->realm);
+}
+
+#define HASHLEN 16
+#define HASHHEXLEN 32
+typedef unsigned char HASH[HASHLEN];
+typedef char HASHHEX[HASHHEXLEN+1];
+
+static void CvtHex(const HASH Bin, char (*Hex)[33]) {
+ li_tohex(*Hex, sizeof(*Hex), (const char*) Bin, 16);
+}
+
+typedef struct {
+ const char *key;
+ int key_len;
+ char **ptr;
+} digest_kv;
+
+static handler_t mod_auth_send_401_unauthorized_digest(server *srv, connection *con, buffer *realm, int nonce_stale);
+
+static handler_t mod_auth_check_digest(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend) {
+ buffer *vb = http_header_request_get(con, HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization"));
+
+ char a1[33];
+ char a2[33];
+
+ char *username = NULL;
+ char *realm = NULL;
+ char *nonce = NULL;
+ char *uri = NULL;
+ char *algorithm = NULL;
+ char *qop = NULL;
+ char *cnonce = NULL;
+ char *nc = NULL;
+ char *respons = NULL;
+
+ char *e, *c;
+ const char *m = NULL;
+ int i;
+ buffer *b;
+
+ li_MD5_CTX Md5Ctx;
+ HASH HA1;
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+
+
+ /* init pointers */
+#define S(x) \
+ x, sizeof(x)-1, NULL
+ digest_kv dkv[10] = {
+ { S("username=") },
+ { S("realm=") },
+ { S("nonce=") },
+ { S("uri=") },
+ { S("algorithm=") },
+ { S("qop=") },
+ { S("cnonce=") },
+ { S("nc=") },
+ { S("response=") },
+
+ { NULL, 0, NULL }
+ };
+#undef S
+
+ dkv[0].ptr = &username;
+ dkv[1].ptr = &realm;
+ dkv[2].ptr = &nonce;
+ dkv[3].ptr = &uri;
+ dkv[4].ptr = &algorithm;
+ dkv[5].ptr = &qop;
+ dkv[6].ptr = &cnonce;
+ dkv[7].ptr = &nc;
+ dkv[8].ptr = &respons;
+
+ UNUSED(p_d);
+
+ if (NULL == backend) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not configured for", con->uri.path);
+ con->http_status = 500;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ if (NULL == vb) {
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
+ }
+
+ if (0 != strncasecmp(vb->ptr, "Digest ", sizeof("Digest ")-1)) {
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
+ } else {
+ size_t n = buffer_string_length(vb);
+ #ifdef __COVERITY__
+ if (n < sizeof("Digest ")-1) {
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+ #endif
+ n -= (sizeof("Digest ")-1);
+ b = buffer_init();
+ buffer_copy_string_len(b,vb->ptr+sizeof("Digest ")-1,n);
+ }
+
+ /* parse credentials from client */
+ for (c = b->ptr; *c; c++) {
+ /* skip whitespaces */
+ while (*c == ' ' || *c == '\t') c++;
+ if (!*c) break;
+
+ for (i = 0; dkv[i].key; i++) {
+ if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
+ if ((c[dkv[i].key_len] == '"') &&
+ (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
+ /* value with "..." */
+ *(dkv[i].ptr) = c + dkv[i].key_len + 1;
+ c = e;
+
+ *e = '\0';
+ } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
+ /* value without "...", terminated by ',' */
+ *(dkv[i].ptr) = c + dkv[i].key_len;
+ c = e;
+
+ *e = '\0';
+ } else {
+ /* value without "...", terminated by EOL */
+ *(dkv[i].ptr) = c + dkv[i].key_len;
+ c += strlen(c) - 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* check if everything is transmitted */
+ if (!username ||
+ !realm ||
+ !nonce ||
+ !uri ||
+ (qop && (!nc || !cnonce)) ||
+ !respons ) {
+ /* missing field */
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "digest: missing field");
+
+ buffer_free(b);
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+
+ if (!buffer_is_equal_string(require->realm, realm, strlen(realm))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "digest: realm mismatch");
+ buffer_free(b);
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
+ }
+
+ /**
+ * protect the md5-sess against missing cnonce and nonce
+ */
+ if (algorithm &&
+ 0 == strcasecmp(algorithm, "md5-sess") &&
+ (!nonce || !cnonce)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "digest: (md5-sess: missing field");
+
+ buffer_free(b);
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+
+ if (qop && strcasecmp(qop, "auth-int") == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "digest: qop=auth-int not supported");
+
+ buffer_free(b);
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+
+ m = get_http_method_name(con->request.http_method);
+ force_assert(m);
+
+ /* detect if attacker is attempting to reuse valid digest for one uri
+ * on a different request uri. Might also happen if intermediate proxy
+ * altered client request line. (Altered request would not result in
+ * the same digest as that calculated by the client.)
+ * Internal redirects such as with mod_rewrite will modify request uri.
+ * Reauthentication is done to detect crossing auth realms, but this
+ * uri validation step is bypassed. con->request.orig_uri is original
+ * uri sent in client request. */
+ {
+ const size_t ulen = strlen(uri);
+ const size_t rlen = buffer_string_length(con->request.orig_uri);
+ if (!buffer_is_equal_string(con->request.orig_uri, uri, ulen)
+ && !(rlen < ulen && 0 == memcmp(con->request.orig_uri->ptr, uri, rlen) && uri[rlen] == '?')) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsssB",
+ "digest: auth failed: uri mismatch (", con->request.orig_uri, "!=", uri, "), IP:", con->dst_addr_buf);
+ buffer_free(b);
+ return mod_auth_send_400_bad_request(srv, con);
+ }
+ }
+
+ /* password-string == HA1 */
+ switch (backend->digest(srv, con, backend->p_d, username, realm, HA1)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_WAIT_FOR_EVENT:
+ buffer_free(b);
+ return HANDLER_WAIT_FOR_EVENT;
+ case HANDLER_FINISHED:
+ buffer_free(b);
+ return HANDLER_FINISHED;
+ case HANDLER_ERROR:
+ default:
+ buffer_free(b);
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
+ }
+
+ if (algorithm &&
+ strcasecmp(algorithm, "md5-sess") == 0) {
+ li_MD5_Init(&Md5Ctx);
+ /* Errata ID 1649: http://www.rfc-editor.org/errata_search.php?rfc=2617 */
+ CvtHex(HA1, &a1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
+ li_MD5_Final(HA1, &Md5Ctx);
+ }
+
+ CvtHex(HA1, &a1);
+
+ /* calculate H(A2) */
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
+ /* qop=auth-int not supported, already checked above */
+/*
+ if (qop && strcasecmp(qop, "auth-int") == 0) {
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *) [body checksum], HASHHEXLEN);
+ }
+*/
+ li_MD5_Final(HA2, &Md5Ctx);
+ CvtHex(HA2, &HA2Hex);
+
+ /* calculate response */
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ if (qop && *qop) {
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ };
+ li_MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
+ li_MD5_Final(RespHash, &Md5Ctx);
+ CvtHex(RespHash, &a2);
+
+ if (0 != strcmp(a2, respons)) {
+ /* digest not ok */
+ log_error_write(srv, __FILE__, __LINE__, "sssB",
+ "digest: auth failed for ", username, ": wrong password, IP:", con->dst_addr_buf);
+
+ buffer_free(b);
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
+ }
+
+ /* value is our allow-rules */
+ if (!http_auth_match_rules(require, username, NULL, NULL)) {
+ buffer_free(b);
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 0);
+ }
+
+ /* check age of nonce. Note, random data is used in nonce generation
+ * in mod_auth_send_401_unauthorized_digest(). If that were replaced
+ * with nanosecond time, then nonce secret would remain unique enough
+ * for the purposes of Digest auth, and would be reproducible (and
+ * verifiable) if nanoseconds were inclued with seconds as part of the
+ * nonce "timestamp:secret". Since that is not done, timestamp in
+ * nonce could theoretically be modified and still produce same md5sum,
+ * but that is highly unlikely within a 10 min (moving) window of valid
+ * time relative to current time (now) */
+ {
+ time_t ts = 0;
+ const unsigned char * const nonce_uns = (unsigned char *)nonce;
+ for (i = 0; i < 8 && light_isxdigit(nonce_uns[i]); ++i) {
+ ts = (ts << 4) + hex2int(nonce_uns[i]);
+ }
+ if (nonce[i] != ':'
+ || ts > srv->cur_ts || srv->cur_ts - ts > 600) { /*(10 mins)*/
+ /* nonce is stale; have client regenerate digest */
+ buffer_free(b);
+ return mod_auth_send_401_unauthorized_digest(srv, con, require->realm, 1);
+ } /*(future: might send nextnonce when expiration is imminent)*/
+ }
+
+ http_auth_setenv(con, username, strlen(username), CONST_STR_LEN("Digest"));
+
+ buffer_free(b);
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_auth_send_401_unauthorized_digest(server *srv, connection *con, buffer *realm, int nonce_stale) {
+ li_MD5_CTX Md5Ctx;
+ HASH h;
+ char hh[33];
+
+ force_assert(33 >= LI_ITOSTRING_LENGTH); /*(buffer used for both li_itostrn() and CvtHex())*/
+
+ /* generate nonce */
+
+ /* generate shared-secret */
+ li_MD5_Init(&Md5Ctx);
+
+ li_itostrn(hh, sizeof(hh), srv->cur_ts);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+ li_itostrn(hh, sizeof(hh), li_rand_pseudo());
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+
+ li_MD5_Final(h, &Md5Ctx);
+
+ CvtHex(h, &hh);
+
+ /* generate WWW-Authenticate */
+
+ con->http_status = 401;
+ con->mode = DIRECT;
+
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("Digest realm=\""));
+ buffer_append_string_buffer(srv->tmp_buf, realm);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\", charset=\"UTF-8\", nonce=\""));
+ buffer_append_uint_hex(srv->tmp_buf, (uintmax_t)srv->cur_ts);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(":"));
+ buffer_append_string_len(srv->tmp_buf, hh, HASHHEXLEN);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\", qop=\"auth\""));
+ if (nonce_stale) {
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(", stale=true"));
+ }
+
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(srv->tmp_buf));
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_auth_check_extern(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend) {
+ /* require REMOTE_USER already set */
+ buffer *vb = http_header_env_get(con, CONST_STR_LEN("REMOTE_USER"));
+ UNUSED(srv);
+ UNUSED(p_d);
+ UNUSED(backend);
+ if (NULL != vb && http_auth_match_rules(require, vb->ptr, NULL, NULL)) {
+ return HANDLER_GO_ON;
+ } else {
+ con->http_status = 401;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_authn_file.c b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_file.c
new file mode 100644
index 000000000..db1a241cb
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_file.c
@@ -0,0 +1,734 @@
+#include "first.h"
+
+
+/*(htpasswd)*/
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#elif defined(__linux__)
+/* linux needs _XOPEN_SOURCE */
+# define _XOPEN_SOURCE
+#endif
+
+#if defined(HAVE_LIBCRYPT) && !defined(HAVE_CRYPT)
+/* always assume crypt() is present if we have -lcrypt */
+# define HAVE_CRYPT
+#endif
+
+#include "sys-crypto.h"
+#ifdef USE_OPENSSL_CRYPTO
+#include <openssl/md4.h>
+#endif
+
+#include "safe_memclear.h"
+/*(htpasswd)*/
+
+
+#include "base.h"
+#include "plugin.h"
+#include "http_auth.h"
+#include "log.h"
+
+#include "algo_sha1.h"
+#include "base64.h"
+#include "md5.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+ * htdigest, htpasswd, plain auth backends
+ */
+
+typedef struct {
+ buffer *auth_plain_groupfile;
+ buffer *auth_plain_userfile;
+ buffer *auth_htdigest_userfile;
+ buffer *auth_htpasswd_userfile;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static handler_t mod_authn_file_htdigest_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
+static handler_t mod_authn_file_htdigest_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
+static handler_t mod_authn_file_plain_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+
+INIT_FUNC(mod_authn_file_init) {
+ static http_auth_backend_t http_auth_backend_htdigest =
+ { "htdigest", mod_authn_file_htdigest_basic, mod_authn_file_htdigest_digest, NULL };
+ static http_auth_backend_t http_auth_backend_htpasswd =
+ { "htpasswd", mod_authn_file_htpasswd_basic, NULL, NULL };
+ static http_auth_backend_t http_auth_backend_plain =
+ { "plain", mod_authn_file_plain_basic, mod_authn_file_plain_digest, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_auth_backend_htdigest */
+ http_auth_backend_htdigest.p_d = p;
+ http_auth_backend_set(&http_auth_backend_htdigest);
+
+ /* register http_auth_backend_htpasswd */
+ http_auth_backend_htpasswd.p_d = p;
+ http_auth_backend_set(&http_auth_backend_htpasswd);
+
+ /* register http_auth_backend_plain */
+ http_auth_backend_plain.p_d = p;
+ http_auth_backend_set(&http_auth_backend_plain);
+
+ return p;
+}
+
+FREE_FUNC(mod_authn_file_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 (NULL == s) continue;
+
+ buffer_free(s->auth_plain_groupfile);
+ buffer_free(s->auth_plain_userfile);
+ buffer_free(s->auth_htdigest_userfile);
+ buffer_free(s->auth_htpasswd_userfile);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_authn_file_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ config_values_t cv[] = {
+ { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->auth_plain_groupfile = buffer_init();
+ s->auth_plain_userfile = buffer_init();
+ s->auth_htdigest_userfile = buffer_init();
+ s->auth_htpasswd_userfile = buffer_init();
+
+ cv[0].destination = s->auth_plain_groupfile;
+ cv[1].destination = s->auth_plain_userfile;
+ cv[2].destination = s->auth_htdigest_userfile;
+ cv[3].destination = s->auth_htpasswd_userfile;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_authn_file_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(auth_plain_groupfile);
+ PATCH(auth_plain_userfile);
+ PATCH(auth_htdigest_userfile);
+ PATCH(auth_htpasswd_userfile);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
+ PATCH(auth_plain_groupfile);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
+ PATCH(auth_plain_userfile);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
+ PATCH(auth_htdigest_userfile);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
+ PATCH(auth_htpasswd_userfile);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static int mod_authn_file_htdigest_get(server *srv, const buffer *auth_fn, const buffer *username, const buffer *realm, unsigned char HA1[16]) {
+ FILE *fp;
+ char f_user[1024];
+
+ if (buffer_string_is_empty(auth_fn)) return -1;
+ if (buffer_is_empty(username) || buffer_is_empty(realm)) return -1;
+
+ fp = fopen(auth_fn->ptr, "r");
+ if (NULL == fp) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", auth_fn, "failed:", strerror(errno));
+
+ return -1;
+ }
+
+ while (NULL != fgets(f_user, sizeof(f_user), fp)) {
+ char *f_pwd, *f_realm;
+ size_t u_len, r_len;
+
+ /* skip blank lines and comment lines (beginning '#') */
+ if (f_user[0] == '#' || f_user[0] == '\n' || f_user[0] == '\0') continue;
+
+ /*
+ * htdigest format
+ *
+ * user:realm:md5(user:realm:password)
+ */
+
+ if (NULL == (f_realm = strchr(f_user, ':'))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "parsed error in", auth_fn,
+ "expected 'username:realm:hashed password'");
+
+ continue; /* skip bad lines */
+ }
+
+ if (NULL == (f_pwd = strchr(f_realm + 1, ':'))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "parsed error in", auth_fn,
+ "expected 'username:realm:hashed password'");
+
+ continue; /* skip bad lines */
+ }
+
+ /* get pointers to the fields */
+ u_len = f_realm - f_user;
+ f_realm++;
+ r_len = f_pwd - f_realm;
+ f_pwd++;
+
+ if (buffer_string_length(username) == u_len &&
+ (buffer_string_length(realm) == r_len) &&
+ (0 == strncmp(username->ptr, f_user, u_len)) &&
+ (0 == strncmp(realm->ptr, f_realm, r_len))) {
+ /* found */
+
+ size_t pwd_len = strlen(f_pwd);
+ if (f_pwd[pwd_len-1] == '\n') --pwd_len;
+
+ fclose(fp);
+
+ return http_auth_md5_hex2bin(f_pwd, pwd_len, HA1);
+ }
+ }
+
+ fclose(fp);
+ return -1;
+}
+
+static handler_t mod_authn_file_htdigest_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
+ plugin_data *p = (plugin_data *)p_d;
+ buffer *username_buf = buffer_init_string(username);
+ buffer *realm_buf = buffer_init_string(realm);
+ int rc;
+ mod_authn_file_patch_connection(srv, con, p);
+ rc = mod_authn_file_htdigest_get(srv, p->conf.auth_htdigest_userfile, username_buf, realm_buf, HA1);
+ buffer_free(realm_buf);
+ buffer_free(username_buf);
+ UNUSED(con);
+ return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
+
+static handler_t mod_authn_file_htdigest_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ plugin_data *p = (plugin_data *)p_d;
+ li_MD5_CTX Md5Ctx;
+ unsigned char HA1[16];
+ unsigned char htdigest[16];
+
+ mod_authn_file_patch_connection(srv, con, p);
+ if (mod_authn_file_htdigest_get(srv, p->conf.auth_htdigest_userfile, username, require->realm, htdigest)) return HANDLER_ERROR;
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(username));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(require->realm));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
+ li_MD5_Final(HA1, &Md5Ctx);
+
+ UNUSED(con);
+ return (0 == memcmp(HA1, htdigest, sizeof(HA1))
+ && http_auth_match_rules(require, username->ptr, NULL, NULL))
+ ? HANDLER_GO_ON
+ : HANDLER_ERROR;
+}
+
+
+
+
+static int mod_authn_file_htpasswd_get(server *srv, const buffer *auth_fn, const buffer *username, buffer *password) {
+ FILE *fp;
+ char f_user[1024];
+
+ if (buffer_is_empty(username)) return -1;
+
+ if (buffer_string_is_empty(auth_fn)) return -1;
+ fp = fopen(auth_fn->ptr, "r");
+ if (NULL == fp) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "opening plain-userfile", auth_fn, "failed:", strerror(errno));
+
+ return -1;
+ }
+
+ while (NULL != fgets(f_user, sizeof(f_user), fp)) {
+ char *f_pwd;
+ size_t u_len;
+
+ /* skip blank lines and comment lines (beginning '#') */
+ if (f_user[0] == '#' || f_user[0] == '\n' || f_user[0] == '\0') continue;
+
+ /*
+ * htpasswd format
+ *
+ * user:crypted passwd
+ */
+
+ if (NULL == (f_pwd = strchr(f_user, ':'))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "parsed error in", auth_fn,
+ "expected 'username:hashed password'");
+
+ continue; /* skip bad lines */
+ }
+
+ /* get pointers to the fields */
+ u_len = f_pwd - f_user;
+ f_pwd++;
+
+ if (buffer_string_length(username) == u_len &&
+ (0 == strncmp(username->ptr, f_user, u_len))) {
+ /* found */
+
+ size_t pwd_len = strlen(f_pwd);
+ if (f_pwd[pwd_len-1] == '\n') --pwd_len;
+
+ buffer_copy_string_len(password, f_pwd, pwd_len);
+
+ fclose(fp);
+ return 0;
+ }
+ }
+
+ fclose(fp);
+ return -1;
+}
+
+static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
+ plugin_data *p = (plugin_data *)p_d;
+ buffer *username_buf = buffer_init_string(username);
+ buffer *password_buf = buffer_init();/* password-string from auth-backend */
+ int rc;
+ mod_authn_file_patch_connection(srv, con, p);
+ rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, username_buf, password_buf);
+ if (0 == rc) {
+ /* generate password from plain-text */
+ li_MD5_CTX Md5Ctx;
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)username_buf->ptr, buffer_string_length(username_buf));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN(":"));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)password_buf->ptr, buffer_string_length(password_buf));
+ li_MD5_Final(HA1, &Md5Ctx);
+ }
+ buffer_free(password_buf);
+ buffer_free(username_buf);
+ UNUSED(con);
+ return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
+
+static handler_t mod_authn_file_plain_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ plugin_data *p = (plugin_data *)p_d;
+ buffer *password_buf = buffer_init();/* password-string from auth-backend */
+ int rc;
+ mod_authn_file_patch_connection(srv, con, p);
+ rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, username, password_buf);
+ if (0 == rc) {
+ rc = http_auth_const_time_memeq(CONST_BUF_LEN(password_buf), pw, strlen(pw)) ? 0 : -1;
+ }
+ buffer_free(password_buf);
+ UNUSED(con);
+ return 0 == rc && http_auth_match_rules(require, username->ptr, NULL, NULL)
+ ? HANDLER_GO_ON
+ : HANDLER_ERROR;
+}
+
+
+
+
+/**
+ * the $apr1$ handling is taken from apache 1.3.x
+ */
+
+/*
+ * The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0
+ * MD5 crypt() function, which is licenced as follows:
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#define APR_MD5_DIGESTSIZE 16
+#define APR1_ID "$apr1$"
+
+/*
+ * The following MD5 password encryption code was largely borrowed from
+ * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
+ * licenced as stated above.
+ */
+
+static void to64(char *s, unsigned long v, int n)
+{
+ static const unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+static void apr_md5_encode(const char *pw, const char *salt, char *result, size_t nbytes) {
+ /*
+ * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
+ * plus 4 for the '$' separators, plus the password hash itself.
+ * Let's leave a goodly amount of leeway.
+ */
+
+ char passwd[120], *p;
+ const char *sp, *ep;
+ unsigned char final[APR_MD5_DIGESTSIZE];
+ ssize_t sl, pl, i;
+ li_MD5_CTX ctx, ctx1;
+ unsigned long l;
+
+ /*
+ * Refine the salt first. It's possible we were given an already-hashed
+ * string as the salt argument, so extract the actual salt value from it
+ * if so. Otherwise just use the string up to the first '$' as the salt.
+ */
+ sp = salt;
+
+ /*
+ * If it starts with the magic string, then skip that.
+ */
+ if (!strncmp(sp, APR1_ID, strlen(APR1_ID))) {
+ sp += strlen(APR1_ID);
+ }
+
+ /*
+ * It stops at the first '$' or 8 chars, whichever comes first
+ */
+ for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
+ continue;
+ }
+
+ /*
+ * Get the length of the true salt
+ */
+ sl = ep - sp;
+
+ /*
+ * 'Time to make the doughnuts..'
+ */
+ li_MD5_Init(&ctx);
+
+ /*
+ * The password first, since that is what is most unknown
+ */
+ li_MD5_Update(&ctx, pw, strlen(pw));
+
+ /*
+ * Then our magic string
+ */
+ li_MD5_Update(&ctx, APR1_ID, strlen(APR1_ID));
+
+ /*
+ * Then the raw salt
+ */
+ li_MD5_Update(&ctx, sp, sl);
+
+ /*
+ * Then just as many characters of the MD5(pw, salt, pw)
+ */
+ li_MD5_Init(&ctx1);
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ li_MD5_Update(&ctx1, sp, sl);
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ li_MD5_Final(final, &ctx1);
+ for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
+ li_MD5_Update(&ctx, final,
+ (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
+ }
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ /*
+ * Then something really weird...
+ */
+ for (i = strlen(pw); i != 0; i >>= 1) {
+ if (i & 1) {
+ li_MD5_Update(&ctx, final, 1);
+ }
+ else {
+ li_MD5_Update(&ctx, pw, 1);
+ }
+ }
+
+ /*
+ * Now make the output string. We know our limitations, so we
+ * can use the string routines without bounds checking.
+ */
+ strcpy(passwd, APR1_ID);
+ strncat(passwd, sp, sl);
+ strcat(passwd, "$");
+
+ li_MD5_Final(final, &ctx);
+
+ /*
+ * And now, just to make sure things don't run too fast..
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ li_MD5_Init(&ctx1);
+ if (i & 1) {
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ }
+ else {
+ li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
+ }
+ if (i % 3) {
+ li_MD5_Update(&ctx1, sp, sl);
+ }
+
+ if (i % 7) {
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ }
+
+ if (i & 1) {
+ li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
+ }
+ else {
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ }
+ li_MD5_Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
+ l = final[11] ; to64(p, l, 2); p += 2;
+ *p = '\0';
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ safe_memclear(final, sizeof(final));
+
+ /* FIXME
+ */
+#define apr_cpystrn strncpy
+ apr_cpystrn(result, passwd, nbytes - 1);
+}
+
+static void apr_sha_encode(const char *pw, char *result, size_t nbytes) {
+ unsigned char digest[20];
+ size_t base64_written;
+ SHA_CTX sha1;
+
+ SHA1_Init(&sha1);
+ SHA1_Update(&sha1, (const unsigned char *) pw, strlen(pw));
+ SHA1_Final(digest, &sha1);
+
+ memset(result, 0, nbytes);
+
+ /* need 5 bytes for "{SHA}", 28 for base64 (3 bytes -> 4 bytes) of SHA1 (20 bytes), 1 terminating */
+ if (nbytes < 5 + 28 + 1) return;
+
+ memcpy(result, "{SHA}", 5);
+ base64_written = li_to_base64(result + 5, nbytes - 5, digest, 20, BASE64_STANDARD);
+ force_assert(base64_written == 28);
+ result[5 + base64_written] = '\0'; /* terminate string */
+}
+
+static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ plugin_data *p = (plugin_data *)p_d;
+ buffer *password = buffer_init();/* password-string from auth-backend */
+ int rc;
+ mod_authn_file_patch_connection(srv, con, p);
+ rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_htpasswd_userfile, username, password);
+ if (0 == rc) {
+ char sample[256];
+ rc = -1;
+ if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) {
+ /*
+ * The hash was created using $apr1$ custom algorithm.
+ */
+ apr_md5_encode(pw, password->ptr, sample, sizeof(sample));
+ rc = strcmp(sample, password->ptr);
+ }
+ else if (0 == strncmp(password->ptr, "{SHA}", 5)) {
+ apr_sha_encode(pw, sample, sizeof(sample));
+ rc = strcmp(sample, password->ptr);
+ }
+ #if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
+ /* a simple DES password is 2 + 11 characters. everything else should be longer. */
+ else if (buffer_string_length(password) >= 13) {
+ char *crypted;
+ #if defined(HAVE_CRYPT_R)
+ struct crypt_data crypt_tmp_data;
+ #ifdef _AIX
+ memset(&crypt_tmp_data, 0, sizeof(crypt_tmp_data));
+ #else
+ crypt_tmp_data.initialized = 0;
+ #endif
+ #endif
+ #ifdef USE_OPENSSL_CRYPTO /* (for MD4_*() (e.g. MD4_Update())) */
+ #ifndef NO_MD4 /*(e.g. wolfSSL built without MD4)*/
+ if (0 == memcmp(password->ptr, CONST_STR_LEN("$1+ntlm$"))) {
+ /* CRYPT-MD5-NTLM algorithm
+ * This algorithm allows for the construction of (slight more)
+ * secure, salted password hashes from an environment where only
+ * legacy NTLM hashes are available and where it is not feasible
+ * to re-hash all the passwords with the MD5-based crypt(). */
+ /* Note: originally, LM password were limited to 14 chars.
+ * NTLM passwords limited to 127 chars, and encoding to UCS-2LE
+ * requires double that, so sample[256] buf is large enough.
+ * Prior sample[120] size likely taken from apr_md5_encode(). */
+ char *b = password->ptr+sizeof("$1+ntlm$")-1;
+ char *e = strchr(b, '$');
+ size_t slen = (NULL != e) ? (size_t)(e - b) : sizeof(sample);
+ size_t pwlen = strlen(pw) * 2;
+ if (slen < sizeof(sample) - (sizeof("$1$")-1)
+ && pwlen < sizeof(sample)) {
+ /* compute NTLM hash and convert to lowercase hex chars
+ * (require lc hex chars from li_tohex()) */
+ char ntlmhash[16];
+ char ntlmhex[33]; /*(sizeof(ntlmhash)*2 + 1)*/
+ MD4_CTX c;
+ MD4_Init(&c);
+ if (pwlen) {
+ /*(reuse sample buffer to encode pw into UCS-2LE)
+ *(Note: assumes pw input in ISO-8859-1) */
+ /*(buffer sizes checked above)*/
+ for (int i=0; i < (int)pwlen; i+=2) {
+ sample[i] = pw[(i >> 1)];
+ sample[i+1] = 0;
+ }
+ MD4_Update(&c, (unsigned char *)sample, pwlen);
+ }
+ MD4_Final((unsigned char *)ntlmhash, &c);
+ li_tohex(ntlmhex,sizeof(ntlmhex),ntlmhash,sizeof(ntlmhash));
+
+ /*(reuse sample buffer for salt (FYI: expect slen == 8))*/
+ memcpy(sample, "$1$", sizeof("$1$")-1);
+ memcpy(sample+sizeof("$1$")-1, b, slen);
+ sample[sizeof("$1$")-1+slen] = '\0';
+ #if defined(HAVE_CRYPT_R)
+ crypted = crypt_r(ntlmhex, sample, &crypt_tmp_data);
+ #else
+ crypted = crypt(ntlmhex, sample);
+ #endif
+ if (NULL != crypted
+ && 0 == strncmp(crypted, "$1$", sizeof("$1$")-1)) {
+ rc = strcmp(b, crypted+3); /*skip crypted "$1$" prefix*/
+ }
+ }
+ }
+ else
+ #endif
+ #endif
+ {
+ #if defined(HAVE_CRYPT_R)
+ crypted = crypt_r(pw, password->ptr, &crypt_tmp_data);
+ #else
+ crypted = crypt(pw, password->ptr);
+ #endif
+ if (NULL != crypted) {
+ rc = strcmp(password->ptr, crypted);
+ }
+ }
+ }
+ #endif
+ }
+ buffer_free(password);
+ UNUSED(con);
+ return 0 == rc && http_auth_match_rules(require, username->ptr, NULL, NULL)
+ ? HANDLER_GO_ON
+ : HANDLER_ERROR;
+}
+
+
+int mod_authn_file_plugin_init(plugin *p);
+int mod_authn_file_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("authn_file");
+ p->init = mod_authn_file_init;
+ p->set_defaults= mod_authn_file_set_defaults;
+ p->cleanup = mod_authn_file_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_authn_gssapi.c b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_gssapi.c
new file mode 100644
index 000000000..6ed61ee92
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_gssapi.c
@@ -0,0 +1,801 @@
+#include "first.h"
+
+/* mod_authn_gssapi
+ *
+ * - provides http_auth_backend_t "gssapi" for HTTP auth Basic realm="Kerberos"
+ * - provides http_auth_scheme_t "Negotiate"
+ * - (does not provide http_auth_backend_t for HTTP auth Digest)
+ *
+ * Note: Credentials cache (KRB5CCNAME) is exported into CGI and SSI environment
+ * as well as passed to FastCGI and SCGI (useful if on same machine
+ * and running under same user account with access to KRB5CCNAME file).
+ * Credentials are clean up at the end of each request.
+ *
+ * LIMITATIONS:
+ * - no rate limiting of auth requests, so remote attacker can send many auth
+ * requests very quickly if attempting brute force password cracking attack
+ *
+ * FUTURE POTENTIAL PERFORMANCE ENHANCEMENTS:
+ * - Kerberos auth is synchronous and blocks waiting for response
+ * TODO: attempt async?
+ */
+
+#include "plugin.h"
+
+#include <krb5.h>
+#include <gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+
+#include "http_auth.h"
+#include "http_header.h"
+#include "base.h"
+#include "log.h"
+#include "md5.h"
+#include "base64.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef struct {
+ buffer *auth_gssapi_keytab;
+ buffer *auth_gssapi_principal;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static handler_t mod_authn_gssapi_check(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
+static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+
+INIT_FUNC(mod_authn_gssapi_init) {
+ static http_auth_scheme_t http_auth_scheme_gssapi =
+ { "gssapi", mod_authn_gssapi_check, NULL };
+ static http_auth_backend_t http_auth_backend_gssapi =
+ { "gssapi", mod_authn_gssapi_basic, NULL, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_auth_scheme_gssapi and http_auth_backend_gssapi */
+ http_auth_scheme_gssapi.p_d = p;
+ http_auth_scheme_set(&http_auth_scheme_gssapi);
+ http_auth_backend_gssapi.p_d = p;
+ http_auth_backend_set(&http_auth_backend_gssapi);
+
+ return p;
+}
+
+FREE_FUNC(mod_authn_gssapi_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 (NULL == s) continue;
+
+ buffer_free(s->auth_gssapi_keytab);
+ buffer_free(s->auth_gssapi_principal);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_authn_gssapi_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+ config_values_t cv[] = {
+ { "auth.backend.gssapi.keytab", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.gssapi.principal", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+
+ s->auth_gssapi_keytab = buffer_init();
+ s->auth_gssapi_principal = buffer_init();
+
+ cv[0].destination = s->auth_gssapi_keytab;
+ cv[1].destination = s->auth_gssapi_principal;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_authn_gssapi_patch_connection(server *srv, connection *con, plugin_data *p)
+{
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(auth_gssapi_keytab);
+ PATCH(auth_gssapi_principal);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.gssapi.keytab"))) {
+ PATCH(auth_gssapi_keytab);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.gssapi.principal"))) {
+ PATCH(auth_gssapi_principal);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static handler_t mod_authn_gssapi_send_400_bad_request (server *srv, connection *con)
+{
+ UNUSED(srv);
+ con->http_status = 400;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+}
+
+static void mod_authn_gssapi_log_gss_error(server *srv, const char *file, unsigned int line, const char *func, const char *extra, OM_uint32 err_maj, OM_uint32 err_min)
+{
+ buffer * const msg = buffer_init_string(func);
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+
+ buffer_append_string_len(msg, CONST_STR_LEN("("));
+ if (extra) buffer_append_string(msg, extra);
+ buffer_append_string_len(msg, CONST_STR_LEN("):"));
+
+ do {
+ maj_stat = gss_display_status(&min_stat, err_maj, GSS_C_GSS_CODE,
+ GSS_C_NO_OID, &msg_ctx, &status_string);
+ if (GSS_ERROR(maj_stat))
+ break;
+
+ buffer_append_string(msg, status_string.value);
+ gss_release_buffer(&min_stat, &status_string);
+
+ maj_stat = gss_display_status(&min_stat, err_min, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &status_string);
+ if (!GSS_ERROR(maj_stat)) {
+ buffer_append_string_len(msg, CONST_STR_LEN(" ("));
+ buffer_append_string(msg, status_string.value);
+ buffer_append_string_len(msg, CONST_STR_LEN(")"));
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
+
+ log_error_write(srv, file, line, "b", msg);
+ buffer_free(msg);
+}
+
+static void mod_authn_gssapi_log_krb5_error(server *srv, const char *file, unsigned int line, const char *func, const char *extra, krb5_context context, int code)
+{
+ UNUSED(context);
+ /*(extra might be NULL)*/
+ log_error_write(srv, file, line, "sssss", func, "(", extra, "):",
+ error_message(code));
+}
+
+static int mod_authn_gssapi_create_krb5_ccache(server *srv, connection *con, plugin_data *p, krb5_context kcontext, krb5_principal princ, krb5_ccache *ccache)
+{
+ buffer * const kccname = buffer_init_string("FILE:/tmp/krb5cc_gssapi_XXXXXX");
+ char * const ccname = kccname->ptr + sizeof("FILE:")-1;
+ const size_t ccnamelen = buffer_string_length(kccname)-(sizeof("FILE:")-1);
+ /*(future: might consider using server.upload-dirs instead of /tmp)*/
+ #ifdef __COVERITY__
+ /* POSIX-2008 requires mkstemp create file with 0600 perms */
+ umask(0600);
+ #endif
+ /* coverity[secure_temp : FALSE] */
+ int fd = mkstemp(ccname);
+ if (fd < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "sss", "mkstemp():", ccname, strerror(errno));
+ buffer_free(kccname);
+ return -1;
+ }
+ close(fd);
+
+ do {
+ krb5_error_code problem;
+
+ problem = krb5_cc_resolve(kcontext, kccname->ptr, ccache);
+ if (problem) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_resolve", NULL, kcontext, problem);
+ break;
+ }
+
+ problem = krb5_cc_initialize(kcontext, *ccache, princ);
+ if (problem) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_initialize", kccname->ptr, kcontext, problem);
+ break;
+ }
+
+ con->plugin_ctx[p->id] = kccname;
+
+ http_header_env_set(con, CONST_STR_LEN("KRB5CCNAME"), ccname, ccnamelen);
+ http_header_request_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-Forwarded-Keytab"), ccname, ccnamelen);
+
+ return 0;
+
+ } while (0);
+
+ if (*ccache) {
+ krb5_cc_destroy(kcontext, *ccache);
+ *ccache = NULL;
+ }
+ unlink(ccname);
+ buffer_free(kccname);
+
+ return -1;
+}
+
+/*
+ * HTTP auth Negotiate
+ */
+
+static handler_t mod_authn_gssapi_send_401_unauthorized_negotiate (connection *con)
+{
+ con->http_status = 401;
+ con->mode = DIRECT;
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_STR_LEN("Negotiate"));
+ return HANDLER_FINISHED;
+}
+
+static int mod_authn_gssapi_store_gss_creds(server *srv, connection *con, plugin_data *p, char *princ_name, gss_cred_id_t delegated_cred)
+{
+ OM_uint32 maj_stat, min_stat;
+ krb5_principal princ = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_error_code problem;
+ krb5_context context;
+
+ problem = krb5_init_context(&context);
+ if (problem) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_init_context", NULL, context, problem);
+ return 0;
+ }
+
+ problem = krb5_parse_name(context, princ_name, &princ);
+ if (problem) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", NULL, context, problem);
+ goto end;
+ }
+
+ if (mod_authn_gssapi_create_krb5_ccache(srv, con, p, context, princ, &ccache))
+ goto end;
+
+ maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
+ if (GSS_ERROR(maj_stat)) {
+ mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_krb5_copy_ccache", princ_name, maj_stat, min_stat);
+ goto end;
+ }
+
+ krb5_cc_close(context, ccache);
+ krb5_free_principal(context, princ);
+ krb5_free_context(context);
+ return 1;
+
+ end:
+ if (princ)
+ krb5_free_principal(context, princ);
+ if (ccache)
+ krb5_cc_destroy(context, ccache);
+ krb5_free_context(context);
+
+ return 0;
+}
+
+static handler_t mod_authn_gssapi_check_spnego(server *srv, connection *con, plugin_data *p, const http_auth_require_t *require, const char *realm_str)
+{
+ OM_uint32 st_major, st_minor, acc_flags;
+ gss_buffer_desc token_s = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc token_in = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc token_out = GSS_C_EMPTY_BUFFER;
+ gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL;
+ gss_ctx_id_t context = GSS_C_NO_CONTEXT;
+ gss_name_t server_name = GSS_C_NO_NAME;
+ gss_name_t client_name = GSS_C_NO_NAME;
+
+ buffer *sprinc;
+ int ret = 0;
+
+ buffer *t_in = buffer_init();
+ if (!buffer_append_base64_decode(t_in, realm_str, strlen(realm_str), BASE64_STANDARD)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "decoding GSSAPI authentication header failed", realm_str);
+ buffer_free(t_in);
+ return mod_authn_gssapi_send_400_bad_request(srv, con);
+ }
+
+ mod_authn_gssapi_patch_connection(srv, con, p);
+
+ {
+ /* ??? Should code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
+ * be used, instead of putenv() of KRB5_KTNAME=...? See mod_authn_gssapi_basic() */
+ /* ??? Should KRB5_KTNAME go into con->environment instead ??? */
+ /* ??? Should KRB5_KTNAME be added to mod_authn_gssapi_basic(), too? */
+ buffer ktname;
+ memset(&ktname, 0, sizeof(ktname));
+ buffer_copy_string(&ktname, "KRB5_KTNAME=");
+ buffer_append_string_buffer(&ktname, p->conf.auth_gssapi_keytab);
+ putenv(ktname.ptr);
+ /* ktname.ptr becomes part of the environment, do not free */
+ }
+
+ sprinc = buffer_init_buffer(p->conf.auth_gssapi_principal);
+ if (strchr(sprinc->ptr, '/') == NULL) {
+ /*(copy HTTP Host, omitting port if port is present)*/
+ /* ??? Should con->server_name be used if http_host not present?
+ * ??? What if con->server_name is not set?
+ * ??? Will this work below if IPv6 provided in Host? probably not */
+ if (!buffer_is_empty(con->request.http_host)) {
+ buffer_append_string_len(sprinc, CONST_STR_LEN("/"));
+ buffer_append_string_len(sprinc, con->request.http_host->ptr, strcspn(con->request.http_host->ptr, ":"));
+ }
+ }
+ if (strchr(sprinc->ptr, '@') == NULL) {
+ buffer_append_string_len(sprinc, CONST_STR_LEN("@"));
+ buffer_append_string_buffer(sprinc, require->realm);
+ }
+ /*#define GSS_C_NT_USER_NAME gss_nt_user_name*/
+ /*#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name*/
+ #define GSS_KRB5_NT_PRINCIPAL_NAME gss_nt_krb5_name
+
+ token_s.value = sprinc->ptr;
+ token_s.length = buffer_string_length(sprinc);
+ st_major = gss_import_name(&st_minor, &token_s, (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME, &server_name);
+ if (GSS_ERROR(st_major)) {
+ mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_import_name", NULL, st_major, st_minor);
+ goto end;
+ }
+
+ memset(&token_s, 0, sizeof(token_s));
+ st_major = gss_display_name(&st_minor, server_name, &token_s, NULL);
+ if (GSS_ERROR(st_major)) {
+ mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_display_name", NULL, st_major, st_minor);
+ goto end;
+ }
+
+ /* acquire server's own credentials */
+ st_major = gss_acquire_cred(&st_minor, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_cred, NULL, NULL);
+ if (GSS_ERROR(st_major)) {
+ mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_acquire_cred", sprinc->ptr, st_major, st_minor);
+ goto end;
+ }
+
+ /* accept the user's context */
+ token_in.length = buffer_string_length(t_in);
+ token_in.value = t_in->ptr;
+ st_major = gss_accept_sec_context(&st_minor, &context, server_cred, &token_in, GSS_C_NO_CHANNEL_BINDINGS,
+ &client_name, NULL, &token_out, &acc_flags, NULL, &client_cred);
+ if (GSS_ERROR(st_major)) {
+ mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_accept_sec_context", NULL, st_major, st_minor);
+ goto end;
+ }
+
+ /* fetch the username */
+ st_major = gss_display_name(&st_minor, client_name, &token_out, NULL);
+ if (GSS_ERROR(st_major)) {
+ mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_display_name", NULL, st_major, st_minor);
+ goto end;
+ }
+
+ if (!(acc_flags & GSS_C_CONF_FLAG)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "No confidentiality for user:", token_out.value);
+ goto end;
+ }
+
+ if (!(acc_flags & GSS_C_DELEG_FLAG)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "Unable to delegate credentials for user:", token_out.value);
+ goto end;
+ }
+
+ /* check the allow-rules */
+ if (!http_auth_match_rules(require, token_out.value, NULL, NULL)) {
+ goto end;
+ }
+
+ ret = mod_authn_gssapi_store_gss_creds(srv, con, p, token_out.value, client_cred);
+ if (ret)
+ http_auth_setenv(con, token_out.value, token_out.length, CONST_STR_LEN("GSSAPI"));
+
+ end:
+ buffer_free(t_in);
+ buffer_free(sprinc);
+
+ if (context != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&st_minor, &context, GSS_C_NO_BUFFER);
+
+ if (client_cred != GSS_C_NO_CREDENTIAL)
+ gss_release_cred(&st_minor, &client_cred);
+ if (server_cred != GSS_C_NO_CREDENTIAL)
+ gss_release_cred(&st_minor, &server_cred);
+
+ if (client_name != GSS_C_NO_NAME)
+ gss_release_name(&st_minor, &client_name);
+ if (server_name != GSS_C_NO_NAME)
+ gss_release_name(&st_minor, &server_name);
+
+ if (token_s.length)
+ gss_release_buffer(&st_minor, &token_s);
+ /* if (token_in.length)
+ * gss_release_buffer(&st_minor, &token_in); */
+ if (token_out.length)
+ gss_release_buffer(&st_minor, &token_out);
+
+ return ret ? HANDLER_GO_ON : mod_authn_gssapi_send_401_unauthorized_negotiate(con);
+}
+
+static handler_t mod_authn_gssapi_check (server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend)
+{
+ buffer *vb = http_header_request_get(con, HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization"));
+
+ UNUSED(backend);
+ if (NULL == vb) {
+ return mod_authn_gssapi_send_401_unauthorized_negotiate(con);
+ }
+
+ if (0 != strncasecmp(vb->ptr, "Negotiate ", sizeof("Negotiate ")-1)) {
+ return mod_authn_gssapi_send_400_bad_request(srv, con);
+ }
+
+ return mod_authn_gssapi_check_spnego(srv, con, (plugin_data *)p_d, require, vb->ptr+sizeof("Negotiate ")-1);
+}
+
+/*
+ * HTTP auth Basic realm="kerberos"
+ */
+
+static krb5_error_code mod_authn_gssapi_verify_krb5_init_creds(server *srv, krb5_context context, krb5_creds *creds, krb5_principal ap_req_server, krb5_keytab ap_req_keytab)
+{
+ krb5_error_code ret;
+ krb5_data req;
+ krb5_ccache local_ccache = NULL;
+ krb5_creds *new_creds = NULL;
+ krb5_auth_context auth_context = NULL;
+ krb5_keytab keytab = NULL;
+ char *server_name;
+
+ memset(&req, 0, sizeof(req));
+
+ if (ap_req_keytab == NULL) {
+ ret = krb5_kt_default(context, &keytab);
+ if (ret)
+ return ret;
+ } else
+ keytab = ap_req_keytab;
+
+ ret = krb5_cc_resolve(context, "MEMORY:", &local_ccache);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_cc_resolve() failed when verifying KDC");
+ /* return ret; */
+ goto end;
+ }
+
+ ret = krb5_cc_initialize(context, local_ccache, creds->client);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_cc_initialize() failed when verifying KDC");
+ goto end;
+ }
+
+ ret = krb5_cc_store_cred(context, local_ccache, creds);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_cc_store_cred() failed when verifying KDC");
+ goto end;
+ }
+
+ ret = krb5_unparse_name(context, ap_req_server, &server_name);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_unparse_name() failed when verifying KDC");
+ goto end;
+ }
+ krb5_free_unparsed_name(context, server_name);
+
+ if (!krb5_principal_compare(context, ap_req_server, creds->server)) {
+ krb5_creds match_cred;
+
+ memset(&match_cred, 0, sizeof(match_cred));
+
+ match_cred.client = creds->client;
+ match_cred.server = ap_req_server;
+
+ ret = krb5_get_credentials(context, 0, local_ccache, &match_cred, &new_creds);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_get_credentials() failed when verifying KDC");
+ goto end;
+ }
+ creds = new_creds;
+ }
+
+ ret = krb5_mk_req_extended(context, &auth_context, 0, NULL, creds, &req);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_mk_req_extended() failed when verifying KDC");
+ goto end;
+ }
+
+ krb5_auth_con_free(context, auth_context);
+ auth_context = NULL;
+ ret = krb5_auth_con_init(context, &auth_context);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_auth_con_init() failed when verifying KDC");
+ goto end;
+ }
+
+ /* use KRB5_AUTH_CONTEXT_DO_SEQUENCE to skip replay cache checks */
+ krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ ret = krb5_rd_req(context, &auth_context, &req, ap_req_server, keytab, 0, NULL);
+ if (ret) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "krb5_rd_req() failed when verifying KDC");
+ goto end;
+ }
+
+ end:
+ krb5_free_data_contents(context, &req);
+ if (auth_context)
+ krb5_auth_con_free(context, auth_context);
+ if (new_creds)
+ krb5_free_creds(context, new_creds);
+ if (ap_req_keytab == NULL && keytab)
+ krb5_kt_close(context, keytab);
+ if (local_ccache)
+ krb5_cc_destroy(context, local_ccache);
+
+ return ret;
+}
+
+static int mod_authn_gssapi_store_krb5_creds(server *srv, connection *con, plugin_data *p,
+ krb5_context kcontext, krb5_ccache delegated_cred)
+{
+ krb5_error_code problem;
+ krb5_principal princ = NULL;
+ krb5_ccache ccache = NULL;
+
+ problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
+ if (problem) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_get_principal", NULL, kcontext, problem);
+ goto end;
+ }
+
+ if (mod_authn_gssapi_create_krb5_ccache(srv, con, p, kcontext, princ, &ccache)) {
+ goto end;
+ }
+
+ problem = krb5_cc_copy_creds(kcontext, delegated_cred, ccache);
+ if (problem) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_copy_creds", NULL, kcontext, problem);
+ goto end;
+ }
+
+ krb5_free_principal(kcontext, princ);
+ krb5_cc_close(kcontext, ccache);
+ return 0;
+
+ end:
+ if (princ)
+ krb5_free_principal(kcontext, princ);
+ if (ccache)
+ krb5_cc_destroy(kcontext, ccache);
+ return -1;
+}
+
+static handler_t mod_authn_gssapi_send_401_unauthorized_basic (connection *con)
+{
+ con->http_status = 401;
+ con->mode = DIRECT;
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("WWW-Authenticate"), CONST_STR_LEN("Basic realm=\"Kerberos\""));
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw)
+{
+ krb5_context kcontext = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_principal s_princ = NULL;
+ krb5_principal c_princ = NULL;
+ krb5_creds c_creds;
+ krb5_ccache c_ccache = NULL;
+ krb5_ccache ret_ccache = NULL;
+ krb5_error_code code;
+ int ret;
+ buffer *sprinc;
+ buffer *user_at_realm = NULL;
+ plugin_data * const p = (plugin_data *)p_d;
+
+ if (*pw == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "Empty passwords are not accepted");
+ return mod_authn_gssapi_send_401_unauthorized_basic(con);
+ }
+
+ mod_authn_gssapi_patch_connection(srv, con, p);
+
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "krb5_init_context():", code);
+ return mod_authn_gssapi_send_401_unauthorized_basic(con); /*(well, should be 500)*/
+ }
+
+ code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
+ if (code) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb", "krb5_kt_resolve():", code, p->conf.auth_gssapi_keytab);
+ return mod_authn_gssapi_send_401_unauthorized_basic(con); /*(well, should be 500)*/
+ }
+
+ sprinc = buffer_init_buffer(p->conf.auth_gssapi_principal);
+ if (strchr(sprinc->ptr, '/') == NULL) {
+ /*(copy HTTP Host, omitting port if port is present)*/
+ /* ??? Should con->server_name be used if http_host not present?
+ * ??? What if con->server_name is not set?
+ * ??? Will this work below if IPv6 provided in Host? probably not */
+ if (!buffer_is_empty(con->request.http_host)) {
+ buffer_append_string_len(sprinc, CONST_STR_LEN("/"));
+ buffer_append_string_len(sprinc, con->request.http_host->ptr, strcspn(con->request.http_host->ptr, ":"));
+ }
+ }
+
+ /*(init c_creds before anything which might krb5_free_cred_contents())*/
+ memset(&c_creds, 0, sizeof(c_creds));
+
+ ret = krb5_parse_name(kcontext, sprinc->ptr, &s_princ);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", sprinc->ptr, kcontext, ret);
+ ret = -1;
+ goto end;
+ }
+
+ if (strchr(username->ptr, '@') == NULL) {
+ user_at_realm = buffer_init_buffer(username);
+ BUFFER_APPEND_STRING_CONST(user_at_realm, "@");
+ buffer_append_string_buffer(user_at_realm, require->realm);
+ }
+
+ ret = krb5_parse_name(kcontext, (user_at_realm ? user_at_realm->ptr : username->ptr), &c_princ);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", (user_at_realm ? user_at_realm->ptr : username->ptr), kcontext, ret);
+ if (user_at_realm) buffer_free(user_at_realm);
+ ret = -1;
+ goto end;
+ }
+ if (user_at_realm) buffer_free(user_at_realm);
+ /* XXX: if the qualified username with @realm should be in REMOTE_USER,
+ * then http_auth_backend_t basic interface needs to change to pass
+ * modifiable buffer *username, but note that const char *pw follows
+ * in the truncated buffer *username, so pw would need to be copied
+ * before modifying buffer *username */
+
+ /*
+ * char *name = NULL;
+ * ret = krb5_unparse_name(kcontext, c_princ, &name);
+ * if (ret == 0) {
+ * log_error_write(srv, __FILE__, __LINE__, "sbss", "Trying to get TGT for user:", username, "password:", pw);
+ * }
+ * krb5_free_unparsed_name(kcontext, name);
+ */
+
+ ret = krb5_get_init_creds_password(kcontext, &c_creds, c_princ, pw, NULL, NULL, 0, NULL, NULL);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_get_init_creds_password", NULL, kcontext, ret);
+ goto end;
+ }
+
+ ret = mod_authn_gssapi_verify_krb5_init_creds(srv, kcontext, &c_creds, s_princ, keytab);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "mod_authn_gssapi_verify_krb5_init_creds", NULL, kcontext, ret);
+ goto end;
+ }
+
+ ret = krb5_cc_resolve(kcontext, "MEMORY:", &ret_ccache);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_resolve", NULL, kcontext, ret);
+ goto end;
+ }
+
+ ret = krb5_cc_initialize(kcontext, ret_ccache, c_princ);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_initialize", NULL, kcontext, ret);
+ goto end;
+ }
+
+ ret = krb5_cc_store_cred(kcontext, ret_ccache, &c_creds);
+ if (ret) {
+ mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_store_cred", NULL, kcontext, ret);
+ goto end;
+ }
+
+ c_ccache = ret_ccache;
+ ret_ccache = NULL;
+
+ end:
+
+ krb5_free_cred_contents(kcontext, &c_creds);
+ if (ret_ccache)
+ krb5_cc_destroy(kcontext, ret_ccache);
+
+ if (!ret && c_ccache && (ret = mod_authn_gssapi_store_krb5_creds(srv, con, p, kcontext, c_ccache))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "mod_authn_gssapi_store_krb5_creds failed for", username);
+ }
+
+ buffer_free(sprinc);
+ if (c_princ)
+ krb5_free_principal(kcontext, c_princ);
+ if (s_princ)
+ krb5_free_principal(kcontext, s_princ);
+ if (c_ccache)
+ krb5_cc_destroy(kcontext, c_ccache);
+ if (keytab)
+ krb5_kt_close(kcontext, keytab);
+
+ krb5_free_context(kcontext);
+
+ if (0 == ret && http_auth_match_rules(require,username->ptr,NULL,NULL)){
+ return HANDLER_GO_ON;
+ }
+ else {
+ /* ret == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN or no authz rules match */
+ log_error_write(srv, __FILE__, __LINE__, "sbsBsB", "password doesn't match for", con->uri.path, "username:", username, ", IP:", con->dst_addr_buf);
+ return mod_authn_gssapi_send_401_unauthorized_basic(con);
+ }
+}
+
+
+CONNECTION_FUNC(mod_authn_gssapi_handle_reset) {
+ plugin_data *p = (plugin_data *)p_d;
+ buffer *kccname = (buffer *)con->plugin_ctx[p->id];
+ if (NULL != kccname) {
+ con->plugin_ctx[p->id] = NULL;
+ unlink(kccname->ptr+sizeof("FILE:")-1);
+ buffer_free(kccname);
+ }
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+int mod_authn_gssapi_plugin_init(plugin *p);
+int mod_authn_gssapi_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("authn_gssapi");
+ p->init = mod_authn_gssapi_init;
+ p->set_defaults= mod_authn_gssapi_set_defaults;
+ p->cleanup = mod_authn_gssapi_free;
+ p->connection_reset = mod_authn_gssapi_handle_reset;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_authn_ldap.c b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_ldap.c
new file mode 100644
index 000000000..233fc239c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_ldap.c
@@ -0,0 +1,694 @@
+#include "first.h"
+
+#include <ldap.h>
+
+#include "base.h"
+#include "http_auth.h"
+#include "log.h"
+#include "plugin.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ LDAP *ldap;
+ server *srv;
+
+ buffer *auth_ldap_hostname;
+ buffer *auth_ldap_basedn;
+ buffer *auth_ldap_binddn;
+ buffer *auth_ldap_bindpw;
+ buffer *auth_ldap_filter;
+ buffer *auth_ldap_cafile;
+ buffer *auth_ldap_groupmember;
+ unsigned short auth_ldap_starttls;
+ unsigned short auth_ldap_allow_empty_pw;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf, *anon_conf; /* this is only used as long as no handler_ctx is setup */
+
+ buffer *ldap_filter;
+} plugin_data;
+
+static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+
+INIT_FUNC(mod_authn_ldap_init) {
+ static http_auth_backend_t http_auth_backend_ldap =
+ { "ldap", mod_authn_ldap_basic, NULL, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+ p->ldap_filter = buffer_init();
+
+ /* register http_auth_backend_ldap */
+ http_auth_backend_ldap.p_d = p;
+ http_auth_backend_set(&http_auth_backend_ldap);
+
+ return p;
+}
+
+FREE_FUNC(mod_authn_ldap_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ buffer_free(p->ldap_filter);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->auth_ldap_hostname);
+ buffer_free(s->auth_ldap_basedn);
+ buffer_free(s->auth_ldap_binddn);
+ buffer_free(s->auth_ldap_bindpw);
+ buffer_free(s->auth_ldap_filter);
+ buffer_free(s->auth_ldap_cafile);
+ buffer_free(s->auth_ldap_groupmember);
+
+ if (NULL != s->ldap) ldap_unbind_ext_s(s->ldap, NULL, NULL);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/*(copied from mod_vhostdb_ldap.c)*/
+static void mod_authn_add_scheme (server *srv, buffer *host)
+{
+ if (!buffer_string_is_empty(host)) {
+ /* reformat hostname(s) as LDAP URIs (scheme://host:port) */
+ static const char *schemes[] = {
+ "ldap://", "ldaps://", "ldapi://", "cldap://"
+ };
+ char *b, *e = host->ptr;
+ buffer_clear(srv->tmp_buf);
+ while (*(b = e)) {
+ unsigned int j;
+ while (*b==' '||*b=='\t'||*b=='\r'||*b=='\n'||*b==',') ++b;
+ if (*b == '\0') break;
+ e = b;
+ while (*e!=' '&&*e!='\t'&&*e!='\r'&&*e!='\n'&&*e!=','&&*e!='\0')
+ ++e;
+ if (!buffer_string_is_empty(srv->tmp_buf))
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(","));
+ for (j = 0; j < sizeof(schemes)/sizeof(char *); ++j) {
+ if (0 == strncasecmp(b, schemes[j], strlen(schemes[j]))) {
+ break;
+ }
+ }
+ if (j == sizeof(schemes)/sizeof(char *))
+ buffer_append_string_len(srv->tmp_buf,
+ CONST_STR_LEN("ldap://"));
+ buffer_append_string_len(srv->tmp_buf, b, (size_t)(e - b));
+ }
+ buffer_copy_buffer(host, srv->tmp_buf);
+ }
+}
+
+SETDEFAULTS_FUNC(mod_authn_ldap_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+config_values_t cv[] = {
+ { "auth.backend.ldap.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "auth.backend.ldap.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "auth.backend.ldap.bind-pw", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "auth.backend.ldap.groupmember", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+
+ s->auth_ldap_hostname = buffer_init();
+ s->auth_ldap_basedn = buffer_init();
+ s->auth_ldap_binddn = buffer_init();
+ s->auth_ldap_bindpw = buffer_init();
+ s->auth_ldap_filter = buffer_init();
+ s->auth_ldap_cafile = buffer_init();
+ s->auth_ldap_groupmember = buffer_init_string("memberUid");
+ s->auth_ldap_starttls = 0;
+ s->ldap = NULL;
+
+ cv[0].destination = s->auth_ldap_hostname;
+ cv[1].destination = s->auth_ldap_basedn;
+ cv[2].destination = s->auth_ldap_filter;
+ cv[3].destination = s->auth_ldap_cafile;
+ cv[4].destination = &(s->auth_ldap_starttls);
+ cv[5].destination = s->auth_ldap_binddn;
+ cv[6].destination = s->auth_ldap_bindpw;
+ cv[7].destination = &(s->auth_ldap_allow_empty_pw);
+ cv[8].destination = s->auth_ldap_groupmember;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->auth_ldap_filter)) {
+ if (*s->auth_ldap_filter->ptr != ',') {
+ /*(translate '$' to '?' for consistency with other modules)*/
+ char *d = s->auth_ldap_filter->ptr;
+ for (; NULL != (d = strchr(d, '$')); ++d) *d = '?';
+ if (NULL == strchr(s->auth_ldap_filter->ptr, '?')) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '?'");
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ mod_authn_add_scheme(srv, s->auth_ldap_hostname);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_authn_ldap_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(auth_ldap_hostname);
+ PATCH(auth_ldap_basedn);
+ PATCH(auth_ldap_binddn);
+ PATCH(auth_ldap_bindpw);
+ PATCH(auth_ldap_filter);
+ PATCH(auth_ldap_cafile);
+ PATCH(auth_ldap_starttls);
+ PATCH(auth_ldap_allow_empty_pw);
+ PATCH(auth_ldap_groupmember);
+ p->anon_conf = s;
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
+ PATCH(auth_ldap_hostname);
+ p->anon_conf = s;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
+ PATCH(auth_ldap_basedn);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
+ PATCH(auth_ldap_filter);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
+ PATCH(auth_ldap_cafile);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
+ PATCH(auth_ldap_starttls);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-dn"))) {
+ PATCH(auth_ldap_binddn);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-pw"))) {
+ PATCH(auth_ldap_bindpw);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) {
+ PATCH(auth_ldap_allow_empty_pw);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.groupmember"))) {
+ PATCH(auth_ldap_groupmember);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static void mod_authn_ldap_err(server *srv, const char *file, unsigned long line, const char *fn, int err)
+{
+ log_error_write(srv,file,line,"sSss","ldap:",fn,":",ldap_err2string(err));
+}
+
+static void mod_authn_ldap_opt_err(server *srv, const char *file, unsigned long line, const char *fn, LDAP *ld)
+{
+ int err;
+ ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
+ mod_authn_ldap_err(srv, file, line, fn, err);
+}
+
+static void mod_authn_append_ldap_dn_escape(buffer * const filter, const buffer * const raw) {
+ /* [RFC4514] 2.4 Converting an AttributeValue from ASN.1 to a String
+ *
+ * https://www.ldap.com/ldap-dns-and-rdns
+ * http://social.technet.microsoft.com/wiki/contents/articles/5312.active-directory-characters-to-escape.aspx
+ */
+ const char * const b = raw->ptr;
+ const size_t rlen = buffer_string_length(raw);
+ if (0 == rlen) return;
+
+ if (b[0] == ' ') { /* || b[0] == '#' handled below for MS Active Directory*/
+ /* escape leading ' ' */
+ buffer_append_string_len(filter, CONST_STR_LEN("\\"));
+ }
+
+ for (size_t i = 0; i < rlen; ++i) {
+ size_t len = i;
+ int bs = 0;
+ do {
+ /* encode all UTF-8 chars with high bit set
+ * (instead of validating UTF-8 and escaping only invalid UTF-8) */
+ if (((unsigned char *)b)[len] > 0x7f)
+ break;
+ switch (b[len]) {
+ default:
+ continue;
+ case '"': case '+': case ',': case ';': case '\\':
+ case '<': case '>':
+ case '=': case '#': /* (for MS Active Directory) */
+ bs = 1;
+ break;
+ case '\0':
+ break;
+ }
+ break;
+ } while (++len < rlen);
+ len -= i;
+
+ if (len) {
+ buffer_append_string_len(filter, b+i, len);
+ if ((i += len) == rlen) break;
+ }
+
+ if (bs) {
+ buffer_append_string_len(filter, CONST_STR_LEN("\\"));
+ buffer_append_string_len(filter, b+i, 1);
+ }
+ else {
+ /* escape NUL ('\0') (and all UTF-8 chars with high bit set) */
+ char *f;
+ buffer_string_prepare_append(filter, 3);
+ f = filter->ptr + buffer_string_length(filter);
+ f[0] = '\\';
+ f[1] = "0123456789abcdef"[(((unsigned char *)b)[i] >> 4) & 0xf];
+ f[2] = "0123456789abcdef"[(((unsigned char *)b)[i] ) & 0xf];
+ buffer_commit(filter, 3);
+ }
+ }
+
+ if (rlen > 1 && b[rlen-1] == ' ') {
+ /* escape trailing ' ' */
+ filter->ptr[buffer_string_length(filter)-1] = '\\';
+ buffer_append_string_len(filter, CONST_STR_LEN(" "));
+ }
+}
+
+static void mod_authn_append_ldap_filter_escape(buffer * const filter, const buffer * const raw) {
+ /* [RFC4515] 3. String Search Filter Definition
+ *
+ * [...]
+ *
+ * The <valueencoding> rule ensures that the entire filter string is a
+ * valid UTF-8 string and provides that the octets that represent the
+ * ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII
+ * 0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a
+ * backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits
+ * representing the value of the encoded octet.
+ *
+ * [...]
+ *
+ * As indicated by the <valueencoding> rule, implementations MUST escape
+ * all octets greater than 0x7F that are not part of a valid UTF-8
+ * encoding sequence when they generate a string representation of a
+ * search filter. Implementations SHOULD accept as input strings that
+ * are not valid UTF-8 strings. This is necessary because RFC 2254 did
+ * not clearly define the term "string representation" (and in
+ * particular did not mention that the string representation of an LDAP
+ * search filter is a string of UTF-8-encoded Unicode characters).
+ *
+ *
+ * https://www.ldap.com/ldap-filters
+ * Although not required, you may escape any other characters that you want
+ * in the assertion value (or substring component) of a filter. This may be
+ * accomplished by prefixing the hexadecimal representation of each byte of
+ * the UTF-8 encoding of the character to escape with a backslash character.
+ */
+ const char * const b = raw->ptr;
+ const size_t rlen = buffer_string_length(raw);
+ for (size_t i = 0; i < rlen; ++i) {
+ size_t len = i;
+ char *f;
+ do {
+ /* encode all UTF-8 chars with high bit set
+ * (instead of validating UTF-8 and escaping only invalid UTF-8) */
+ if (((unsigned char *)b)[len] > 0x7f)
+ break;
+ switch (b[len]) {
+ default:
+ continue;
+ case '\0': case '(': case ')': case '*': case '\\':
+ break;
+ }
+ break;
+ } while (++len < rlen);
+ len -= i;
+
+ if (len) {
+ buffer_append_string_len(filter, b+i, len);
+ if ((i += len) == rlen) break;
+ }
+
+ /* escape * ( ) \ NUL ('\0') (and all UTF-8 chars with high bit set) */
+ buffer_string_prepare_append(filter, 3);
+ f = filter->ptr + buffer_string_length(filter);
+ f[0] = '\\';
+ f[1] = "0123456789abcdef"[(((unsigned char *)b)[i] >> 4) & 0xf];
+ f[2] = "0123456789abcdef"[(((unsigned char *)b)[i] ) & 0xf];
+ buffer_commit(filter, 3);
+ }
+}
+
+static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config *s) {
+ LDAP *ld;
+ int ret;
+
+ if (buffer_string_is_empty(s->auth_ldap_hostname)) return NULL;
+
+ if (LDAP_SUCCESS != ldap_initialize(&ld, s->auth_ldap_hostname->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sss", "ldap:",
+ "ldap_initialize():", strerror(errno));
+ return NULL;
+ }
+
+ ret = LDAP_VERSION3;
+ ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ret);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv, __FILE__, __LINE__, "ldap_set_option()", ret);
+ ldap_destroy(ld);
+ return NULL;
+ }
+
+ if (s->auth_ldap_starttls) {
+ /* if no CA file is given, it is ok, as we will use encryption
+ * if the server requires a CAfile it will tell us */
+ if (!buffer_string_is_empty(s->auth_ldap_cafile)) {
+ ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ s->auth_ldap_cafile->ptr);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv, __FILE__, __LINE__,
+ "ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE)",
+ ret);
+ ldap_destroy(ld);
+ return NULL;
+ }
+ }
+
+ ret = ldap_start_tls_s(ld, NULL, NULL);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv,__FILE__,__LINE__,"ldap_start_tls_s()",ret);
+ ldap_destroy(ld);
+ return NULL;
+ }
+ }
+
+ return ld;
+}
+
+static int mod_authn_ldap_bind(server *srv, LDAP *ld, const char *dn, const char *pw) {
+ struct berval creds;
+ int ret;
+
+ if (NULL != pw) {
+ *((const char **)&creds.bv_val) = pw; /*(cast away const)*/
+ creds.bv_len = strlen(pw);
+ } else {
+ creds.bv_val = NULL;
+ creds.bv_len = 0;
+ }
+
+ /* RFE: add functionality: LDAP_SASL_EXTERNAL (or GSS-SPNEGO, etc.) */
+
+ ret = ldap_sasl_bind_s(ld,dn,LDAP_SASL_SIMPLE,&creds,NULL,NULL,NULL);
+ if (ret != LDAP_SUCCESS) {
+ mod_authn_ldap_err(srv, __FILE__, __LINE__, "ldap_sasl_bind_s()", ret);
+ }
+
+ return ret;
+}
+
+static int mod_authn_ldap_rebind_proc (LDAP *ld, LDAP_CONST char *url, ber_tag_t ldap_request, ber_int_t msgid, void *params) {
+ plugin_config *s = (plugin_config *)params;
+ UNUSED(url);
+ UNUSED(ldap_request);
+ UNUSED(msgid);
+ return !buffer_string_is_empty(s->auth_ldap_binddn)
+ ? mod_authn_ldap_bind(s->srv, ld,
+ s->auth_ldap_binddn->ptr,
+ s->auth_ldap_bindpw->ptr)
+ : mod_authn_ldap_bind(s->srv, ld, NULL, NULL);
+}
+
+static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *base, char *filter) {
+ LDAPMessage *lm = NULL;
+ char *attrs[] = { LDAP_NO_ATTRS, NULL };
+ int ret;
+
+ /*
+ * 1. connect anonymously (if not already connected)
+ * (ldap connection is kept open unless connection-level error occurs)
+ * 2. issue search using filter
+ */
+
+ if (s->ldap != NULL) {
+ ret = ldap_search_ext_s(s->ldap, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, 0, NULL, NULL, NULL, 0, &lm);
+ if (LDAP_SUCCESS == ret) {
+ return lm;
+ } else if (LDAP_SERVER_DOWN != ret) {
+ /* try again (or initial request);
+ * ldap lib sometimes fails for the first call but reconnects */
+ ret = ldap_search_ext_s(s->ldap, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, 0, NULL, NULL, NULL, 0, &lm);
+ if (LDAP_SUCCESS == ret) {
+ return lm;
+ }
+ }
+
+ ldap_unbind_ext_s(s->ldap, NULL, NULL);
+ }
+
+ s->ldap = mod_authn_ldap_host_init(srv, s);
+ if (NULL == s->ldap) {
+ return NULL;
+ }
+
+ ldap_set_rebind_proc(s->ldap, mod_authn_ldap_rebind_proc, s);
+ ret = mod_authn_ldap_rebind_proc(s->ldap, NULL, 0, 0, s);
+ if (LDAP_SUCCESS != ret) {
+ ldap_destroy(s->ldap);
+ s->ldap = NULL;
+ return NULL;
+ }
+
+ ret = ldap_search_ext_s(s->ldap, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, 0, NULL, NULL, NULL, 0, &lm);
+ if (LDAP_SUCCESS != ret) {
+ log_error_write(srv, __FILE__, __LINE__, "sSss",
+ "ldap:", ldap_err2string(ret), "; filter:", filter);
+ ldap_unbind_ext_s(s->ldap, NULL, NULL);
+ s->ldap = NULL;
+ return NULL;
+ }
+
+ return lm;
+}
+
+static char * mod_authn_ldap_get_dn(server *srv, plugin_config *s, char *base, char *filter) {
+ LDAP *ld;
+ LDAPMessage *lm, *first;
+ char *dn;
+ int count;
+
+ lm = mod_authn_ldap_search(srv, s, base, filter);
+ if (NULL == lm) {
+ return NULL;
+ }
+
+ ld = s->ldap; /*(must be after mod_authn_ldap_search(); might reconnect)*/
+
+ count = ldap_count_entries(ld, lm);
+ if (0 == count) { /*(no entires found)*/
+ ldap_msgfree(lm);
+ return NULL;
+ } else if (count > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ldap:", "more than one record returned. "
+ "you might have to refine the filter:", filter);
+ }
+
+ if (NULL == (first = ldap_first_entry(ld, lm))) {
+ mod_authn_ldap_opt_err(srv,__FILE__,__LINE__,"ldap_first_entry()",ld);
+ ldap_msgfree(lm);
+ return NULL;
+ }
+
+ if (NULL == (dn = ldap_get_dn(ld, first))) {
+ mod_authn_ldap_opt_err(srv,__FILE__,__LINE__,"ldap_get_dn()",ld);
+ ldap_msgfree(lm);
+ return NULL;
+ }
+
+ ldap_msgfree(lm);
+ return dn;
+}
+
+static handler_t mod_authn_ldap_memberOf(server *srv, plugin_config *s, const http_auth_require_t *require, const buffer *username, const char *userdn) {
+ array *groups = require->group;
+ buffer *filter = buffer_init();
+ handler_t rc = HANDLER_ERROR;
+
+ buffer_copy_string_len(filter, CONST_STR_LEN("("));
+ buffer_append_string_buffer(filter, s->auth_ldap_groupmember);
+ buffer_append_string_len(filter, CONST_STR_LEN("="));
+ if (buffer_is_equal_string(s->auth_ldap_groupmember,
+ CONST_STR_LEN("member"))) {
+ buffer_append_string(filter, userdn);
+ } else { /*(assume "memberUid"; consider validating in SETDEFAULTS_FUNC)*/
+ mod_authn_append_ldap_filter_escape(filter, username);
+ }
+ buffer_append_string_len(filter, CONST_STR_LEN(")"));
+
+ for (size_t i = 0; i < groups->used; ++i) {
+ char *base = groups->data[i]->key->ptr;
+ LDAPMessage *lm = mod_authn_ldap_search(srv, s, base, filter->ptr);
+ if (NULL != lm) {
+ int count = ldap_count_entries(s->ldap, lm);
+ ldap_msgfree(lm);
+ if (count > 0) {
+ rc = HANDLER_GO_ON;
+ break;
+ }
+ }
+ }
+
+ buffer_free(filter);
+ return rc;
+}
+
+static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ plugin_data *p = (plugin_data *)p_d;
+ LDAP *ld;
+ char *dn;
+ buffer *template;
+ handler_t rc;
+
+ mod_authn_ldap_patch_connection(srv, con, p);
+ p->anon_conf->srv = srv;
+ p->conf.srv = srv;
+
+ if (pw[0] == '\0' && !p->conf.auth_ldap_allow_empty_pw)
+ return HANDLER_ERROR;
+
+ template = p->conf.auth_ldap_filter;
+ if (buffer_string_is_empty(template)) {
+ return HANDLER_ERROR;
+ }
+
+ /* build filter to get DN for uid = username */
+ buffer_clear(p->ldap_filter);
+ if (*template->ptr == ',') {
+ /* special-case filter template beginning with ',' to be explicit DN */
+ buffer_append_string_len(p->ldap_filter, CONST_STR_LEN("uid="));
+ mod_authn_append_ldap_dn_escape(p->ldap_filter, username);
+ buffer_append_string_buffer(p->ldap_filter, template);
+ dn = p->ldap_filter->ptr;
+ } else {
+ for (char *b = template->ptr, *d; *b; b = d+1) {
+ if (NULL != (d = strchr(b, '?'))) {
+ buffer_append_string_len(p->ldap_filter, b, (size_t)(d - b));
+ mod_authn_append_ldap_filter_escape(p->ldap_filter, username);
+ } else {
+ d = template->ptr + buffer_string_length(template);
+ buffer_append_string_len(p->ldap_filter, b, (size_t)(d - b));
+ break;
+ }
+ }
+
+ /* ldap_search for DN (synchronous; blocking) */
+ dn = mod_authn_ldap_get_dn(srv, p->anon_conf,
+ p->conf.auth_ldap_basedn->ptr,
+ p->ldap_filter->ptr);
+ if (NULL == dn) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ /* auth against LDAP server (synchronous; blocking) */
+
+ ld = mod_authn_ldap_host_init(srv, &p->conf);
+ if (NULL == ld) {
+ if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+ return HANDLER_ERROR;
+ }
+
+ /* Disable referral tracking. Target user should be in provided scope */
+ {
+ int ret = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv,__FILE__,__LINE__,"ldap_set_option()",ret);
+ ldap_destroy(ld);
+ if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (LDAP_SUCCESS != mod_authn_ldap_bind(srv, ld, dn, pw)) {
+ ldap_destroy(ld);
+ if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+ return HANDLER_ERROR;
+ }
+
+ ldap_unbind_ext_s(ld, NULL, NULL); /* disconnect */
+
+ if (http_auth_match_rules(require, username->ptr, NULL, NULL)) {
+ rc = HANDLER_GO_ON; /* access granted */
+ } else {
+ rc = HANDLER_ERROR;
+ if (require->group->used) {
+ /*(must not re-use p->ldap_filter, since it might be used for dn)*/
+ rc = mod_authn_ldap_memberOf(srv, &p->conf, require, username, dn);
+ }
+ }
+
+ if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+ return rc;
+}
+
+int mod_authn_ldap_plugin_init(plugin *p);
+int mod_authn_ldap_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("authn_ldap");
+ p->init = mod_authn_ldap_init;
+ p->set_defaults = mod_authn_ldap_set_defaults;
+ p->cleanup = mod_authn_ldap_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_authn_mysql.c b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_mysql.c
new file mode 100644
index 000000000..3a41cd4bb
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_mysql.c
@@ -0,0 +1,550 @@
+#include "first.h"
+
+/* mod_authn_mysql
+ *
+ * KNOWN LIMITATIONS:
+ * - no mechanism provided to configure SSL connection to a remote MySQL db
+ *
+ * FUTURE POTENTIAL PERFORMANCE ENHANCEMENTS:
+ * - database response is not cached
+ * TODO: db response caching (for limited time) to reduce load on db
+ * (only cache successful logins to prevent cache bloat?)
+ * (or limit number of entries (size) of cache)
+ * (maybe have negative cache (limited size) of names not found in database)
+ * - database query is synchronous and blocks waiting for response
+ * TODO: https://mariadb.com/kb/en/mariadb/using-the-non-blocking-library/
+ * - opens and closes connection to MySQL db for each request (inefficient)
+ * (fixed) one-element cache for persistent connection open to last used db
+ * TODO: db connection pool (if asynchronous requests)
+ */
+
+#include <mysql.h>
+
+#include "base.h"
+#include "http_auth.h"
+#include "log.h"
+#include "md5.h"
+#include "plugin.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
+#include <unistd.h> /* crypt() */
+#endif
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+typedef struct {
+ MYSQL *mysql_conn;
+ buffer *mysql_conn_host;
+ buffer *mysql_conn_user;
+ buffer *mysql_conn_pass;
+ buffer *mysql_conn_db;
+ int mysql_conn_port;
+ int auth_mysql_port;
+ buffer *auth_mysql_host;
+ buffer *auth_mysql_user;
+ buffer *auth_mysql_pass;
+ buffer *auth_mysql_db;
+ buffer *auth_mysql_socket;
+ buffer *auth_mysql_users_table;
+ buffer *auth_mysql_col_user;
+ buffer *auth_mysql_col_pass;
+ buffer *auth_mysql_col_realm;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static void mod_authn_mysql_sock_close(plugin_config *pconf) {
+ if (NULL != pconf->mysql_conn) {
+ mysql_close(pconf->mysql_conn);
+ pconf->mysql_conn = NULL;
+ }
+}
+
+static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_config *pconf) {
+ if (NULL != pconf->mysql_conn) {
+ /* reuse open db connection if same ptrs to host user pass db port */
+ if ( pconf->mysql_conn_host == pconf->auth_mysql_host
+ && pconf->mysql_conn_user == pconf->auth_mysql_user
+ && pconf->mysql_conn_pass == pconf->auth_mysql_pass
+ && pconf->mysql_conn_db == pconf->auth_mysql_db
+ && pconf->mysql_conn_port == pconf->auth_mysql_port) {
+ return pconf->mysql_conn;
+ }
+ mod_authn_mysql_sock_close(pconf);
+ }
+
+ /* !! mysql_init() is not thread safe !! (see MySQL doc) */
+ pconf->mysql_conn = mysql_init(NULL);
+ if (mysql_real_connect(pconf->mysql_conn,
+ pconf->auth_mysql_host->ptr,
+ pconf->auth_mysql_user->ptr,
+ pconf->auth_mysql_pass->ptr,
+ pconf->auth_mysql_db->ptr,
+ pconf->auth_mysql_port,
+ !buffer_string_is_empty(pconf->auth_mysql_socket)
+ ? pconf->auth_mysql_socket->ptr
+ : NULL,
+ CLIENT_IGNORE_SIGPIPE)) {
+ /* (copy ptrs to config data (has lifetime until server shutdown)) */
+ pconf->mysql_conn_host = pconf->auth_mysql_host;
+ pconf->mysql_conn_user = pconf->auth_mysql_user;
+ pconf->mysql_conn_pass = pconf->auth_mysql_pass;
+ pconf->mysql_conn_db = pconf->auth_mysql_db;
+ pconf->mysql_conn_port = pconf->auth_mysql_port;
+ return pconf->mysql_conn;
+ }
+ else {
+ /*(note: any of these params might be buffers with b->ptr == NULL)*/
+ log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbss",
+ "opening connection to mysql:", pconf->auth_mysql_host,
+ "user:", pconf->auth_mysql_user,
+ /*"pass:", pconf->auth_mysql_pass,*//*(omit from logs)*/
+ "db:", pconf->auth_mysql_db,
+ "failed:", mysql_error(pconf->mysql_conn));
+ mod_authn_mysql_sock_close(pconf);
+ return NULL;
+ }
+}
+
+static MYSQL * mod_authn_mysql_sock_acquire(server *srv, plugin_config *pconf) {
+ return mod_authn_mysql_sock_connect(srv, pconf);
+}
+
+static void mod_authn_mysql_sock_release(server *srv, plugin_config *pconf) {
+ UNUSED(srv);
+ UNUSED(pconf);
+ /*(empty; leave db connection open)*/
+ /* Note: mod_authn_mysql_result() calls mod_authn_mysql_sock_error()
+ * on error, so take that into account if making changes here.
+ * Must check if (NULL == pconf->mysql_conn) */
+}
+
+static void mod_authn_mysql_sock_error(server *srv, plugin_config *pconf) {
+ UNUSED(srv);
+ mod_authn_mysql_sock_close(pconf);
+}
+
+static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]);
+
+INIT_FUNC(mod_authn_mysql_init) {
+ static http_auth_backend_t http_auth_backend_mysql =
+ { "mysql", mod_authn_mysql_basic, mod_authn_mysql_digest, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_auth_backend_mysql */
+ http_auth_backend_mysql.p_d = p;
+ http_auth_backend_set(&http_auth_backend_mysql);
+
+ return p;
+}
+
+FREE_FUNC(mod_authn_mysql_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 (NULL == s) continue;
+
+ buffer_free(s->auth_mysql_host);
+ buffer_free(s->auth_mysql_user);
+ buffer_free(s->auth_mysql_pass);
+ buffer_free(s->auth_mysql_db);
+ buffer_free(s->auth_mysql_socket);
+ buffer_free(s->auth_mysql_users_table);
+ buffer_free(s->auth_mysql_col_user);
+ buffer_free(s->auth_mysql_col_pass);
+ buffer_free(s->auth_mysql_col_realm);
+
+ if (s->mysql_conn) mod_authn_mysql_sock_close(s);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ mod_authn_mysql_sock_close(&p->conf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_authn_mysql_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+ config_values_t cv[] = {
+ { "auth.backend.mysql.host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.port", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.users_table", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.col_user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.col_pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.mysql.col_realm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+
+ s->mysql_conn = NULL;
+ s->auth_mysql_host = buffer_init();
+ s->auth_mysql_user = buffer_init();
+ s->auth_mysql_pass = buffer_init();
+ s->auth_mysql_db = buffer_init();
+ s->auth_mysql_socket = buffer_init();
+ s->auth_mysql_users_table = buffer_init();
+ s->auth_mysql_col_user = buffer_init();
+ s->auth_mysql_col_pass = buffer_init();
+ s->auth_mysql_col_realm = buffer_init();
+
+ cv[0].destination = s->auth_mysql_host;
+ cv[1].destination = s->auth_mysql_user;
+ cv[2].destination = s->auth_mysql_pass;
+ cv[3].destination = s->auth_mysql_db;
+ cv[4].destination = &s->auth_mysql_port;
+ cv[5].destination = s->auth_mysql_socket;
+ cv[6].destination = s->auth_mysql_users_table;
+ cv[7].destination = s->auth_mysql_col_user;
+ cv[8].destination = s->auth_mysql_col_pass;
+ cv[9].destination = s->auth_mysql_col_realm;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_is_empty(s->auth_mysql_col_user)
+ && buffer_string_is_empty(s->auth_mysql_col_user)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "auth.backend.mysql.col_user must not be blank");
+ return HANDLER_ERROR;
+ }
+ if (!buffer_is_empty(s->auth_mysql_col_pass)
+ && buffer_string_is_empty(s->auth_mysql_col_pass)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "auth.backend.mysql.col_pass must not be blank");
+ return HANDLER_ERROR;
+ }
+ if (!buffer_is_empty(s->auth_mysql_col_realm)
+ && buffer_string_is_empty(s->auth_mysql_col_realm)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "auth.backend.mysql.col_realm must not be blank");
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (p->config_storage[0]) { /*(always true)*/
+ plugin_config *s = p->config_storage[0];
+ if (buffer_is_empty(s->auth_mysql_col_user)) {
+ buffer_copy_string_len(s->auth_mysql_col_user, CONST_STR_LEN("user"));
+ }
+ if (buffer_is_empty(s->auth_mysql_col_pass)) {
+ buffer_copy_string_len(s->auth_mysql_col_pass, CONST_STR_LEN("password"));
+ }
+ if (buffer_is_empty(s->auth_mysql_col_realm)) {
+ buffer_copy_string_len(s->auth_mysql_col_realm, CONST_STR_LEN("realm"));
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_authn_mysql_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(auth_mysql_host);
+ PATCH(auth_mysql_user);
+ PATCH(auth_mysql_pass);
+ PATCH(auth_mysql_db);
+ PATCH(auth_mysql_port);
+ PATCH(auth_mysql_socket);
+ PATCH(auth_mysql_users_table);
+ PATCH(auth_mysql_col_user);
+ PATCH(auth_mysql_col_pass);
+ PATCH(auth_mysql_col_realm);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.host"))) {
+ PATCH(auth_mysql_host);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.user"))) {
+ PATCH(auth_mysql_user);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.pass"))) {
+ PATCH(auth_mysql_pass);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.db"))) {
+ PATCH(auth_mysql_db);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.port"))) {
+ PATCH(auth_mysql_port);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.socket"))) {
+ PATCH(auth_mysql_socket);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.users_table"))) {
+ PATCH(auth_mysql_users_table);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_user"))) {
+ PATCH(auth_mysql_col_user);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_pass"))) {
+ PATCH(auth_mysql_col_pass);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_realm"))) {
+ PATCH(auth_mysql_col_realm);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpwlen, const char *reqpw) {
+ #if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
+ if (userpwlen >= 3 && userpw[0] == '$' && userpw[2] == '$') {
+ /* md5 crypt()
+ * request by Nicola Tiling <nti@w4w.net> */
+ const char *saltb = userpw+3;
+ const char *salte = strchr(saltb, '$');
+ char salt[32];
+ size_t slen = (NULL != salte) ? (size_t)(salte - saltb) : sizeof(salt);
+
+ if (slen < sizeof(salt)) {
+ char *crypted;
+ #if defined(HAVE_CRYPT_R)
+ struct crypt_data crypt_tmp_data;
+ #ifdef _AIX
+ memset(&crypt_tmp_data, 0, sizeof(crypt_tmp_data));
+ #else
+ crypt_tmp_data.initialized = 0;
+ #endif
+ #endif
+ memcpy(salt, saltb, slen);
+ salt[slen] = '\0';
+
+ #if defined(HAVE_CRYPT_R)
+ crypted = crypt_r(reqpw, salt, &crypt_tmp_data);
+ #else
+ crypted = crypt(reqpw, salt);
+ #endif
+ if (NULL != crypted) {
+ return strcmp(userpw, crypted);
+ }
+ }
+ }
+ else
+ #endif
+ if (32 == userpwlen) {
+ /* plain md5 */
+ li_MD5_CTX Md5Ctx;
+ unsigned char HA1[16];
+ unsigned char md5pw[16];
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)reqpw, strlen(reqpw));
+ li_MD5_Final(HA1, &Md5Ctx);
+
+ /*(compare 16-byte MD5 binary instead of converting to hex strings
+ * in order to then have to do case-insensitive hex str comparison)*/
+ return (0 == http_auth_md5_hex2bin(userpw, 32 /*(userpwlen)*/, md5pw))
+ ? memcmp(HA1, md5pw, sizeof(md5pw))
+ : -1;
+ }
+
+ return -1;
+}
+
+static int mod_authn_mysql_result(server *srv, plugin_data *p, const char *pw, unsigned char HA1[16]) {
+ MYSQL_RES *result = mysql_store_result(p->conf.mysql_conn);
+ int rc = -1;
+ my_ulonglong num_rows;
+
+ if (NULL == result) {
+ /*(future: might log mysql_error() string)*/
+ #if 0
+ log_error_write(srv, __FILE__, __LINE__, "ss", "mysql_store_result:",
+ mysql_error(p->conf.mysql_conn));
+ #endif
+ mod_authn_mysql_sock_error(srv, &p->conf);
+ return -1;
+ }
+
+ num_rows = mysql_num_rows(result);
+ if (1 == num_rows) {
+ MYSQL_ROW row = mysql_fetch_row(result);
+ unsigned long *lengths = mysql_fetch_lengths(result);
+ if (NULL == lengths) {
+ /*(error; should not happen)*/
+ }
+ else if (pw) { /* used with HTTP Basic auth */
+ rc = mod_authn_mysql_password_cmp(row[0], lengths[0], pw);
+ }
+ else { /* used with HTTP Digest auth */
+ rc = http_auth_md5_hex2bin(row[0], lengths[0], HA1);
+ }
+ }
+ else if (0 == num_rows) {
+ /* user,realm not found */
+ }
+ else {
+ /* (multiple rows returned, which should not happen) */
+ /* (future: might log if multiple rows returned; unexpected result) */
+ }
+ mysql_free_result(result);
+ return rc;
+}
+
+static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d, const char *username, const char *realm, const char *pw, unsigned char HA1[16]) {
+ plugin_data *p = (plugin_data *)p_d;
+ int rc = -1;
+
+ mod_authn_mysql_patch_connection(srv, con, p);
+
+ if (buffer_string_is_empty(p->conf.auth_mysql_users_table)) {
+ /*(auth.backend.mysql.host, auth.backend.mysql.db might be NULL; do not log)*/
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "auth config missing auth.backend.mysql.users_table for uri:",
+ con->request.uri);
+ return HANDLER_ERROR;
+ }
+
+ do {
+ size_t unamelen = strlen(username);
+ size_t urealmlen = strlen(realm);
+ char q[1024], uname[512], urealm[512];
+ unsigned long mrc;
+
+ if (unamelen > sizeof(uname)/2-1)
+ return HANDLER_ERROR;
+ if (urealmlen > sizeof(urealm)/2-1)
+ return HANDLER_ERROR;
+
+ if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
+ return HANDLER_ERROR;
+ }
+
+ #if 0
+ mrc = mysql_real_escape_string_quote(p->conf.mysql_conn,uname,username,
+ (unsigned long)unamelen, '\'');
+ if ((unsigned long)~0 == mrc) break;
+
+ mrc = mysql_real_escape_string_quote(p->conf.mysql_conn,urealm,realm,
+ (unsigned long)urealmlen, '\'');
+ if ((unsigned long)~0 == mrc) break;
+ #else
+ mrc = mysql_real_escape_string(p->conf.mysql_conn, uname,
+ username, (unsigned long)unamelen);
+ if ((unsigned long)~0 == mrc) break;
+
+ mrc = mysql_real_escape_string(p->conf.mysql_conn, urealm,
+ realm, (unsigned long)urealmlen);
+ if ((unsigned long)~0 == mrc) break;
+ #endif
+
+ rc = snprintf(q, sizeof(q),
+ "SELECT %s FROM %s WHERE %s='%s' AND %s='%s'",
+ p->conf.auth_mysql_col_pass->ptr,
+ p->conf.auth_mysql_users_table->ptr,
+ p->conf.auth_mysql_col_user->ptr,
+ uname,
+ p->conf.auth_mysql_col_realm->ptr,
+ urealm);
+
+ if (rc >= (int)sizeof(q)) {
+ rc = -1;
+ break;
+ }
+
+ /* for now we stay synchronous */
+ if (0 != mysql_query(p->conf.mysql_conn, q)) {
+ /* reconnect to db and retry once if query error occurs */
+ mod_authn_mysql_sock_error(srv, &p->conf);
+ if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
+ rc = -1;
+ break;
+ }
+ if (0 != mysql_query(p->conf.mysql_conn, q)) {
+ /*(note: any of these params might be bufs w/ b->ptr == NULL)*/
+ log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbssss",
+ "mysql_query host:", p->conf.auth_mysql_host,
+ "user:", p->conf.auth_mysql_user,
+ /*(omit pass from logs)*/
+ /*"pass:", p->conf.auth_mysql_pass,*/
+ "db:", p->conf.auth_mysql_db,
+ "query:", q,
+ "failed:", mysql_error(p->conf.mysql_conn));
+ rc = -1;
+ break;
+ }
+ }
+
+ rc = mod_authn_mysql_result(srv, p, pw, HA1);
+
+ } while (0);
+
+ mod_authn_mysql_sock_release(srv, &p->conf);
+
+ return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
+
+static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ /*(HA1 is not written since pw passed should not be NULL;
+ * avoid passing NULL since subroutine expects unsigned char HA1[16] arg)*/
+ static unsigned char HA1[16];
+ char *realm = require->realm->ptr;
+ handler_t rc =mod_authn_mysql_query(srv,con,p_d,username->ptr,realm,pw,HA1);
+ if (HANDLER_GO_ON != rc) return rc;
+ return http_auth_match_rules(require, username->ptr, NULL, NULL)
+ ? HANDLER_GO_ON /* access granted */
+ : HANDLER_ERROR;
+}
+
+static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d, const char *username, const char *realm, unsigned char HA1[16]) {
+ return mod_authn_mysql_query(srv,con,p_d,username,realm,NULL,HA1);
+}
+
+int mod_authn_mysql_plugin_init(plugin *p);
+int mod_authn_mysql_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("authn_mysql");
+ p->init = mod_authn_mysql_init;
+ p->set_defaults= mod_authn_mysql_set_defaults;
+ p->cleanup = mod_authn_mysql_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_authn_pam.c b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_pam.c
new file mode 100644
index 000000000..2439f1dfe
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_pam.c
@@ -0,0 +1,185 @@
+#include "first.h"
+
+/* mod_authn_pam
+ *
+ * FUTURE POTENTIAL PERFORMANCE ENHANCEMENTS:
+ * - database response is not cached
+ * TODO: db response caching (for limited time) to reduce load on db
+ * (only cache successful logins to prevent cache bloat?)
+ * (or limit number of entries (size) of cache)
+ * (maybe have negative cache (limited size) of names not found in database)
+ * - database query is synchronous and blocks waiting for response
+ */
+
+#include <security/pam_appl.h>
+
+#include "base.h"
+#include "http_auth.h"
+#include "log.h"
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ array *opts;
+ const char *service;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static handler_t mod_authn_pam_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+
+INIT_FUNC(mod_authn_pam_init) {
+ static http_auth_backend_t http_auth_backend_pam =
+ { "pam", mod_authn_pam_basic, NULL, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_auth_backend_pam */
+ http_auth_backend_pam.p_d = p;
+ http_auth_backend_set(&http_auth_backend_pam);
+
+ return p;
+}
+
+FREE_FUNC(mod_authn_pam_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ array_free(s->opts);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
+ plugin_data *p = p_d;
+ config_values_t cv[] = {
+ { "auth.backend.pam.opts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ data_string *ds;
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+ s->opts = array_init();
+
+ cv[0].destination = s->opts;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (0 == s->opts->used) continue;
+
+ ds = (data_string *)
+ array_get_element_klen(s->opts, CONST_STR_LEN("service"));
+ s->service = (NULL != ds) ? ds->value->ptr : "http";
+ }
+
+ if (p->config_storage[0]->service == NULL)
+ p->config_storage[0]->service = "http";
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_authn_pam_patch_connection(server *srv, connection *con, plugin_data *p) {
+ plugin_config *s = p->config_storage[0];
+ PATCH(service);
+
+ /* skip the first, the global context */
+ for (size_t i = 1; i < srv->config_context->used; ++i) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ s = p->config_storage[i];
+ for (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.pam.opts"))) {
+ PATCH(service);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_authn_pam_fn_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
+ const char * const pw = (char *)appdata_ptr;
+ struct pam_response * const pr = *resp =
+ (struct pam_response *)malloc(num_msg * sizeof(struct pam_response));
+ for (int i = 0; i < num_msg; ++i) {
+ const int style = msg[i]->msg_style;
+ pr[i].resp_retcode = 0;
+ pr[i].resp = (style==PAM_PROMPT_ECHO_OFF || style==PAM_PROMPT_ECHO_ON)
+ ? strdup(pw)
+ : NULL;
+ }
+ return PAM_SUCCESS;
+}
+
+static handler_t mod_authn_pam_query(server *srv, connection *con, void *p_d, const buffer *username, const char *realm, const char *pw) {
+ plugin_data *p = (plugin_data *)p_d;
+ pam_handle_t *pamh = NULL;
+ struct pam_conv conv = { mod_authn_pam_fn_conv, NULL };
+ const int flags = PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK;
+ int rc;
+ UNUSED(realm);
+ *(const char **)&conv.appdata_ptr = pw; /*(cast away const)*/
+
+ mod_authn_pam_patch_connection(srv, con, p);
+
+ rc = pam_start(p->conf.service, username->ptr, &conv, &pamh);
+ if (PAM_SUCCESS != rc
+ || PAM_SUCCESS !=(rc = pam_set_item(pamh,PAM_RHOST,con->dst_addr_buf->ptr))
+ || PAM_SUCCESS !=(rc = pam_authenticate(pamh, flags))
+ || PAM_SUCCESS !=(rc = pam_acct_mgmt(pamh, flags)))
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "pam:", pam_strerror(pamh, rc));
+ pam_end(pamh, rc);
+ return (PAM_SUCCESS == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
+
+static handler_t mod_authn_pam_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ char *realm = require->realm->ptr;
+ handler_t rc = mod_authn_pam_query(srv, con, p_d, username, realm, pw);
+ if (HANDLER_GO_ON != rc) return rc;
+ return http_auth_match_rules(require, username->ptr, NULL, NULL)
+ ? HANDLER_GO_ON /* access granted */
+ : HANDLER_ERROR;
+}
+
+int mod_authn_pam_plugin_init(plugin *p);
+int mod_authn_pam_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("authn_pam");
+ p->data = NULL;
+ p->init = mod_authn_pam_init;
+ p->cleanup = mod_authn_pam_free;
+ p->set_defaults= mod_authn_pam_set_defaults;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_authn_sasl.c b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_sasl.c
new file mode 100644
index 000000000..d4c46e3a9
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_authn_sasl.c
@@ -0,0 +1,284 @@
+#include "first.h"
+
+/* mod_authn_sasl
+ *
+ * FUTURE POTENTIAL PERFORMANCE ENHANCEMENTS:
+ * - database response is not cached
+ * TODO: db response caching (for limited time) to reduce load on db
+ * (only cache successful logins to prevent cache bloat?)
+ * (or limit number of entries (size) of cache)
+ * (maybe have negative cache (limited size) of names not found in database)
+ * - database query is synchronous and blocks waiting for response
+ */
+
+#include <sasl/sasl.h>
+
+#include "base.h"
+#include "http_auth.h"
+#include "log.h"
+#include "plugin.h"
+
+#include <sys/utsname.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ array *opts;
+ const char *service;
+ const char *fqdn;
+ const buffer *pwcheck_method;
+ const buffer *sasldb_path;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+ buffer *fqdn;
+ int initonce;
+} plugin_data;
+
+static handler_t mod_authn_sasl_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
+
+INIT_FUNC(mod_authn_sasl_init) {
+ static http_auth_backend_t http_auth_backend_sasl =
+ { "sasl", mod_authn_sasl_basic, NULL, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_auth_backend_sasl */
+ http_auth_backend_sasl.p_d = p;
+ http_auth_backend_set(&http_auth_backend_sasl);
+
+ return p;
+}
+
+FREE_FUNC(mod_authn_sasl_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->initonce) sasl_done();
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ array_free(s->opts);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ buffer_free(p->fqdn);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_authn_sasl_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+ config_values_t cv[] = {
+ { "auth.backend.sasl.opts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ data_string *ds;
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+ s->opts = array_init();
+
+ cv[0].destination = s->opts;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (0 == s->opts->used) continue;
+
+ ds = (data_string *)
+ array_get_element_klen(s->opts, CONST_STR_LEN("service"));
+ s->service = (NULL != ds) ? ds->value->ptr : "http";
+
+ ds = (data_string *)
+ array_get_element_klen(s->opts, CONST_STR_LEN("fqdn"));
+ if (NULL != ds) s->fqdn = ds->value->ptr;
+ if (NULL == s->fqdn) {
+ if (NULL == p->fqdn) {
+ struct utsname uts;
+ if (0 != uname(&uts)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "uname():", strerror(errno));
+ return HANDLER_ERROR;
+ }
+ p->fqdn = buffer_init_string(uts.nodename);
+ }
+ s->fqdn = p->fqdn->ptr;
+ }
+
+ ds = (data_string *)
+ array_get_element_klen(s->opts, CONST_STR_LEN("pwcheck_method"));
+ if (NULL != ds) {
+ s->pwcheck_method = ds->value;
+ if (!buffer_is_equal_string(ds->value, CONST_STR_LEN("saslauthd"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("auxprop"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("sasldb"))){
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "sasl pwcheck_method must be one of saslauthd, "
+ "sasldb, or auxprop, not:", ds->value);
+ return HANDLER_ERROR;
+ }
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("sasldb"))) {
+ /* Cyrus libsasl2 expects "auxprop" instead of "sasldb"
+ * (mod_authn_sasl_cb_getopt auxprop_plugin returns "sasldb") */
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("auxprop"));
+ }
+ }
+
+ ds = (data_string *)
+ array_get_element_klen(s->opts, CONST_STR_LEN("sasldb_path"));
+ if (NULL != ds) s->sasldb_path = ds->value;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_authn_sasl_patch_connection(server *srv, connection *con, plugin_data *p) {
+ plugin_config *s = p->config_storage[0];
+ PATCH(service);
+ PATCH(fqdn);
+ PATCH(pwcheck_method);
+ PATCH(sasldb_path);
+
+ /* skip the first, the global context */
+ for (size_t i = 1; i < srv->config_context->used; ++i) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ s = p->config_storage[i];
+ for (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.sasl.opts"))) {
+ PATCH(service);
+ PATCH(fqdn);
+ PATCH(pwcheck_method);
+ PATCH(sasldb_path);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_authn_sasl_cb_getopt(void *p_d, const char *plugin_name, const char *opt, const char **res, unsigned *len) {
+ plugin_data *p = (plugin_data *)p_d;
+ size_t sz;
+
+ if (0 == strcmp(opt, "pwcheck_method")) {
+ if (!buffer_string_is_empty(p->conf.pwcheck_method)) {
+ *res = p->conf.pwcheck_method->ptr;
+ sz = buffer_string_length(p->conf.pwcheck_method);
+ }
+ else { /* default */
+ *res = "saslauthd";
+ sz = sizeof("saslauthd")-1;
+ }
+ }
+ else if (0 == strcmp(opt, "sasldb_path")
+ && !buffer_string_is_empty(p->conf.sasldb_path)) {
+ *res = p->conf.sasldb_path->ptr;
+ sz = buffer_string_length(p->conf.sasldb_path);
+ }
+ else if (0 == strcmp(opt, "auxprop_plugin")) {
+ *res = "sasldb";
+ sz = sizeof("sasldb")-1;
+ }
+ else {
+ UNUSED(plugin_name);
+ return SASL_FAIL;
+ }
+
+ if (len) *len = (unsigned int)sz;
+ return SASL_OK;
+}
+
+static int mod_authn_sasl_cb_log(void *vsrv, int level, const char *message) {
+ switch (level) {
+ #if 0
+ case SASL_LOG_NONE:
+ case SASL_LOG_NOTE:
+ case SASL_LOG_DEBUG:
+ case SASL_LOG_TRACE:
+ case SASL_LOG_PASS:
+ #endif
+ default:
+ break;
+ case SASL_LOG_ERR:
+ case SASL_LOG_FAIL:
+ case SASL_LOG_WARN: /* (might omit SASL_LOG_WARN if too noisy in logs) */
+ log_error_write((server *)vsrv, __FILE__, __LINE__, "s", message);
+ break;
+ }
+ return SASL_OK;
+}
+
+static handler_t mod_authn_sasl_query(server *srv, connection *con, void *p_d, const buffer *username, const char *realm, const char *pw) {
+ plugin_data *p = (plugin_data *)p_d;
+ sasl_conn_t *sc;
+ sasl_callback_t const cb[] = {
+ { SASL_CB_GETOPT, (int(*)())mod_authn_sasl_cb_getopt, (void *) p },
+ { SASL_CB_LOG, (int(*)())mod_authn_sasl_cb_log, (void *) srv },
+ { SASL_CB_LIST_END, NULL, NULL }
+ };
+ int rc;
+
+ mod_authn_sasl_patch_connection(srv, con, p);
+
+ if (!p->initonce) {
+ /* must be done once, but after fork() if multiple lighttpd workers */
+ rc = sasl_server_init(cb, NULL);
+ if (SASL_OK != rc) return HANDLER_ERROR;
+ p->initonce = 1;
+ }
+
+ rc = sasl_server_new(p->conf.service, p->conf.fqdn,
+ realm, NULL, NULL, cb, 0, &sc);
+ if (SASL_OK == rc) {
+ rc = sasl_checkpass(sc, CONST_BUF_LEN(username), pw, strlen(pw));
+ sasl_dispose(&sc);
+ }
+
+ return (SASL_OK == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
+
+static handler_t mod_authn_sasl_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
+ char *realm = require->realm->ptr;
+ handler_t rc = mod_authn_sasl_query(srv, con, p_d, username, realm, pw);
+ if (HANDLER_GO_ON != rc) return rc;
+ return http_auth_match_rules(require, username->ptr, NULL, NULL)
+ ? HANDLER_GO_ON /* access granted */
+ : HANDLER_ERROR;
+}
+
+int mod_authn_sasl_plugin_init(plugin *p);
+int mod_authn_sasl_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("authn_sasl");
+ p->init = mod_authn_sasl_init;
+ p->set_defaults= mod_authn_sasl_set_defaults;
+ p->cleanup = mod_authn_sasl_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_cgi.c b/data/lighttpd/lighttpd-1.4.53/src/mod_cgi.c
new file mode 100644
index 000000000..aeec06f98
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_cgi.c
@@ -0,0 +1,1081 @@
+#include "first.h"
+
+#include "base.h"
+#include "stat_cache.h"
+#include "http_kv.h"
+#include "log.h"
+#include "connections.h"
+#include "joblist.h"
+#include "response.h"
+#include "http_chunk.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <sys/types.h>
+#include "sys-mmap.h"
+#include "sys-socket.h"
+# include <sys/wait.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fdevent.h>
+
+#include <fcntl.h>
+#include <signal.h>
+
+static int pipe_cloexec(int pipefd[2]) {
+ #ifdef HAVE_PIPE2
+ if (0 == pipe2(pipefd, O_CLOEXEC)) return 0;
+ #endif
+ return 0 == pipe(pipefd)
+ #ifdef FD_CLOEXEC
+ && 0 == fcntl(pipefd[0], F_SETFD, FD_CLOEXEC)
+ && 0 == fcntl(pipefd[1], F_SETFD, FD_CLOEXEC)
+ #endif
+ ? 0
+ : -1;
+}
+
+typedef struct {
+ char *ptr;
+ size_t used;
+ size_t size;
+ size_t *offsets;
+ size_t osize;
+ size_t oused;
+ char **eptr;
+ size_t esize;
+ buffer *ld_preload;
+ buffer *ld_library_path;
+ #ifdef __CYGWIN__
+ buffer *systemroot;
+ #endif
+} env_accum;
+
+typedef struct {
+ struct { pid_t pid; void *ctx; } *ptr;
+ size_t used;
+ size_t size;
+} buffer_pid_t;
+
+typedef struct {
+ array *cgi;
+ unsigned short execute_x_only;
+ unsigned short local_redir;
+ unsigned short xsendfile_allow;
+ unsigned short upgrade;
+ array *xsendfile_docroot;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+ buffer_pid_t cgi_pid;
+ env_accum env;
+} plugin_data;
+
+typedef struct {
+ pid_t pid;
+ int fd;
+ int fdtocgi;
+ int fde_ndx; /* index into the fd-event buffer */
+ int fde_ndx_tocgi; /* index into the fd-event buffer */
+
+ connection *remote_conn; /* dumb pointer */
+ plugin_data *plugin_data; /* dumb pointer */
+
+ buffer *response;
+ buffer *cgi_handler; /* dumb pointer */
+ http_response_opts opts;
+ plugin_config conf;
+} handler_ctx;
+
+static handler_ctx * cgi_handler_ctx_init(void) {
+ handler_ctx *hctx = calloc(1, sizeof(*hctx));
+
+ force_assert(hctx);
+
+ hctx->response = chunk_buffer_acquire();
+ hctx->fd = -1;
+ hctx->fdtocgi = -1;
+
+ return hctx;
+}
+
+static void cgi_handler_ctx_free(handler_ctx *hctx) {
+ chunk_buffer_release(hctx->response);
+ free(hctx);
+}
+
+INIT_FUNC(mod_cgi_init) {
+ plugin_data *p;
+ const char *s;
+
+ p = calloc(1, sizeof(*p));
+
+ force_assert(p);
+
+ /* for valgrind */
+ s = getenv("LD_PRELOAD");
+ if (s) p->env.ld_preload = buffer_init_string(s);
+ s = getenv("LD_LIBRARY_PATH");
+ if (s) p->env.ld_library_path = buffer_init_string(s);
+ #ifdef __CYGWIN__
+ /* CYGWIN needs SYSTEMROOT */
+ s = getenv("SYSTEMROOT");
+ if (s) p->env.systemroot = buffer_init_string(s);
+ #endif
+
+ return p;
+}
+
+
+FREE_FUNC(mod_cgi_free) {
+ plugin_data *p = p_d;
+ buffer_pid_t *r = &(p->cgi_pid);
+
+ UNUSED(srv);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->cgi);
+ array_free(s->xsendfile_docroot);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+
+ if (r->ptr) free(r->ptr);
+ free(p->env.ptr);
+ free(p->env.offsets);
+ free(p->env.eptr);
+ buffer_free(p->env.ld_preload);
+ buffer_free(p->env.ld_library_path);
+ #ifdef __CYGWIN__
+ buffer_free(p->env.systemroot);
+ #endif
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "cgi.x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "cgi.x-sendfile-docroot", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "cgi.local-redir", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "cgi.upgrade", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+ force_assert(p->config_storage);
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ force_assert(s);
+
+ s->cgi = array_init();
+ s->execute_x_only = 0;
+ s->local_redir = 0;
+ s->xsendfile_allow= 0;
+ s->xsendfile_docroot = array_init();
+ s->upgrade = 0;
+
+ cv[0].destination = s->cgi;
+ cv[1].destination = &(s->execute_x_only);
+ cv[2].destination = &(s->xsendfile_allow);
+ cv[3].destination = s->xsendfile_docroot;
+ cv[4].destination = &(s->local_redir);
+ cv[5].destination = &(s->upgrade);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->cgi)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for cgi.assign; expected list of \"ext\" => \"exepath\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->xsendfile_docroot->used) {
+ size_t j;
+ for (j = 0; j < s->xsendfile_docroot->used; ++j) {
+ data_string *ds = (data_string *)s->xsendfile_docroot->data[j];
+ if (ds->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected type for key cgi.x-sendfile-docroot; expected: cgi.x-sendfile-docroot = ( \"/allowed/path\", ... )");
+ return HANDLER_ERROR;
+ }
+ if (ds->value->ptr[0] != '/') {
+ log_error_write(srv, __FILE__, __LINE__, "SBs",
+ "cgi.x-sendfile-docroot paths must begin with '/'; invalid: \"", ds->value, "\"");
+ return HANDLER_ERROR;
+ }
+ buffer_path_simplify(ds->value, ds->value);
+ buffer_append_slash(ds->value);
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static void cgi_pid_add(plugin_data *p, pid_t pid, void *ctx) {
+ buffer_pid_t *r = &(p->cgi_pid);
+
+ if (r->size == 0) {
+ r->size = 16;
+ r->ptr = malloc(sizeof(*r->ptr) * r->size);
+ force_assert(r->ptr);
+ } else if (r->used == r->size) {
+ r->size += 16;
+ r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
+ force_assert(r->ptr);
+ }
+
+ r->ptr[r->used].pid = pid;
+ r->ptr[r->used].ctx = ctx;
+ ++r->used;
+}
+
+static void cgi_pid_kill(plugin_data *p, pid_t pid) {
+ buffer_pid_t *r = &(p->cgi_pid);
+ for (size_t i = 0; i < r->used; ++i) {
+ if (r->ptr[i].pid == pid) {
+ r->ptr[i].ctx = NULL;
+ kill(pid, SIGTERM);
+ return;
+ }
+ }
+}
+
+static void cgi_pid_del(plugin_data *p, size_t i) {
+ buffer_pid_t *r = &(p->cgi_pid);
+
+ if (i != r->used - 1) {
+ r->ptr[i] = r->ptr[r->used - 1];
+ }
+ r->used--;
+}
+
+
+static void cgi_connection_close_fdtocgi(server *srv, handler_ctx *hctx) {
+ /*(closes only hctx->fdtocgi)*/
+ fdevent_event_del(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi);
+ /*fdevent_unregister(srv->ev, hctx->fdtocgi);*//*(handled below)*/
+ fdevent_sched_close(srv->ev, hctx->fdtocgi, 0);
+ hctx->fdtocgi = -1;
+}
+
+static void cgi_connection_close(server *srv, handler_ctx *hctx) {
+ plugin_data *p = hctx->plugin_data;
+ connection *con = hctx->remote_conn;
+
+ /* the connection to the browser went away, but we still have a connection
+ * to the CGI script
+ *
+ * close cgi-connection
+ */
+
+ if (hctx->fd != -1) {
+ /* close connection to the cgi-script */
+ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+ /*fdevent_unregister(srv->ev, hctx->fd);*//*(handled below)*/
+ fdevent_sched_close(srv->ev, hctx->fd, 0);
+ }
+
+ if (hctx->fdtocgi != -1) {
+ cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
+ }
+
+ if (hctx->pid > 0) {
+ cgi_pid_kill(p, hctx->pid);
+ }
+
+ con->plugin_ctx[p->id] = NULL;
+
+ cgi_handler_ctx_free(hctx);
+
+ /* finish response (if not already con->file_started, con->file_finished) */
+ if (con->mode == p->id) {
+ http_response_backend_done(srv, con);
+ }
+}
+
+static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (hctx) cgi_connection_close(srv, hctx);
+
+ return HANDLER_GO_ON;
+}
+
+
+static int cgi_write_request(server *srv, handler_ctx *hctx, int fd);
+
+
+static handler_t cgi_handle_fdevent_send (server *srv, void *ctx, int revents) {
+ handler_ctx *hctx = ctx;
+ connection *con = hctx->remote_conn;
+
+ /*(joblist only actually necessary here in mod_cgi fdevent send if returning HANDLER_ERROR)*/
+ joblist_append(srv, con);
+
+ if (revents & FDEVENT_OUT) {
+ if (0 != cgi_write_request(srv, hctx, hctx->fdtocgi)) {
+ cgi_connection_close(srv, hctx);
+ return HANDLER_ERROR;
+ }
+ /* more request body to be sent to CGI */
+ }
+
+ if (revents & FDEVENT_HUP) {
+ /* skip sending remaining data to CGI */
+ if (con->request.content_length) {
+ chunkqueue *cq = con->request_content_queue;
+ chunkqueue_mark_written(cq, chunkqueue_length(cq));
+ if (cq->bytes_in != (off_t)con->request.content_length) {
+ con->keep_alive = 0;
+ }
+ }
+
+ cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
+ } else if (revents & FDEVENT_ERR) {
+ /* kill all connections to the cgi process */
+#if 1
+ log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
+#endif
+ cgi_connection_close(srv, hctx);
+ return HANDLER_ERROR;
+ }
+
+ return HANDLER_FINISHED;
+}
+
+
+static handler_t cgi_response_headers(server *srv, connection *con, struct http_response_opts_t *opts) {
+ /* response headers just completed */
+ handler_ctx *hctx = (handler_ctx *)opts->pdata;
+
+ if (con->response.htags & HTTP_HEADER_UPGRADE) {
+ if (hctx->conf.upgrade && con->http_status == 101) {
+ /* 101 Switching Protocols; transition to transparent proxy */
+ http_response_upgrade_read_body_unknown(srv, con);
+ }
+ else {
+ con->response.htags &= ~HTTP_HEADER_UPGRADE;
+ #if 0
+ /* preserve prior questionable behavior; likely broken behavior
+ * anyway if backend thinks connection is being upgraded but client
+ * does not receive Connection: upgrade */
+ http_header_response_unset(con, HTTP_HEADER_UPGRADE,
+ CONST_STR_LEN("Upgrade"));
+ #endif
+ }
+ }
+
+ if (hctx->conf.upgrade && !(con->response.htags & HTTP_HEADER_UPGRADE)) {
+ chunkqueue *cq = con->request_content_queue;
+ hctx->conf.upgrade = 0;
+ if (cq->bytes_out == (off_t)con->request.content_length) {
+ cgi_connection_close_fdtocgi(srv, hctx); /*(closes hctx->fdtocgi)*/
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static int cgi_recv_response(server *srv, handler_ctx *hctx) {
+ switch (http_response_read(srv, hctx->remote_conn, &hctx->opts,
+ hctx->response, hctx->fd, &hctx->fde_ndx)) {
+ default:
+ return HANDLER_GO_ON;
+ case HANDLER_ERROR:
+ http_response_backend_error(srv, hctx->remote_conn);
+ /* fall through */
+ case HANDLER_FINISHED:
+ cgi_connection_close(srv, hctx);
+ return HANDLER_FINISHED;
+ case HANDLER_COMEBACK:
+ /* hctx->conf.local_redir */
+ buffer_clear(hctx->response);
+ connection_response_reset(srv, hctx->remote_conn); /*(includes con->http_status = 0)*/
+ plugins_call_connection_reset(srv, hctx->remote_conn);
+ /*cgi_connection_close(srv, hctx);*//*(already cleaned up and hctx is now invalid)*/
+ return HANDLER_COMEBACK;
+ }
+}
+
+
+static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
+ handler_ctx *hctx = ctx;
+ connection *con = hctx->remote_conn;
+
+ joblist_append(srv, con);
+
+ if (revents & FDEVENT_IN) {
+ handler_t rc = cgi_recv_response(srv, hctx);/*(might invalidate hctx)*/
+ if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/
+ }
+
+ /* perhaps this issue is already handled */
+ if (revents & (FDEVENT_HUP|FDEVENT_RDHUP)) {
+ if (con->file_started) {
+ /* drain any remaining data from kernel pipe buffers
+ * even if (con->conf.stream_response_body
+ * & FDEVENT_STREAM_RESPONSE_BUFMIN)
+ * since event loop will spin on fd FDEVENT_HUP event
+ * until unregistered. */
+ handler_t rc;
+ const unsigned short flags = con->conf.stream_response_body;
+ con->conf.stream_response_body &= ~FDEVENT_STREAM_RESPONSE_BUFMIN;
+ con->conf.stream_response_body |= FDEVENT_STREAM_RESPONSE_POLLRDHUP;
+ do {
+ rc = cgi_recv_response(srv,hctx);/*(might invalidate hctx)*/
+ } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/
+ con->conf.stream_response_body = flags;
+ return rc; /* HANDLER_FINISHED or HANDLER_COMEBACK or HANDLER_ERROR */
+ } else if (!buffer_string_is_empty(hctx->response)) {
+ /* unfinished header package which is a body in reality */
+ con->file_started = 1;
+ if (0 != http_chunk_append_buffer(srv, con, hctx->response)) {
+ cgi_connection_close(srv, hctx);
+ return HANDLER_ERROR;
+ }
+ if (0 == con->http_status) con->http_status = 200; /* OK */
+ }
+ cgi_connection_close(srv, hctx);
+ } else if (revents & FDEVENT_ERR) {
+ /* kill all connections to the cgi process */
+ cgi_connection_close(srv, hctx);
+ return HANDLER_ERROR;
+ }
+
+ return HANDLER_FINISHED;
+}
+
+
+static int cgi_env_add(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
+ env_accum *env = venv;
+ char *dst;
+
+ if (!key || !val) return -1;
+
+ if (env->size - env->used < key_len + val_len + 2) {
+ if (0 == env->size) env->size = 4096;
+ do { env->size *= 2; } while (env->size - env->used < key_len + val_len + 2);
+ env->ptr = realloc(env->ptr, env->size);
+ force_assert(env->ptr);
+ }
+
+ dst = env->ptr + env->used;
+ memcpy(dst, key, key_len);
+ dst[key_len] = '=';
+ memcpy(dst + key_len + 1, val, val_len);
+ dst[key_len + 1 + val_len] = '\0';
+
+ if (env->osize == env->oused) {
+ env->osize += 16;
+ env->offsets = realloc(env->offsets, env->osize * sizeof(*env->offsets));
+ force_assert(env->offsets);
+ }
+ env->offsets[env->oused++] = env->used;
+ env->used += key_len + val_len + 2;
+
+ return 0;
+}
+
+/*(improved from network_write_mmap.c)*/
+static off_t mmap_align_offset(off_t start) {
+ static off_t pagemask = 0;
+ if (0 == pagemask) {
+ long pagesize = sysconf(_SC_PAGESIZE);
+ if (-1 == pagesize) pagesize = 4096;
+ pagemask = ~((off_t)pagesize - 1); /* pagesize always power-of-2 */
+ }
+ return (start & pagemask);
+}
+
+/* returns: 0: continue, -1: fatal error, -2: connection reset */
+/* similar to network_write_file_chunk_mmap, but doesn't use send on windows (because we're on pipes),
+ * also mmaps and sends complete chunk instead of only small parts - the files
+ * are supposed to be temp files with reasonable chunk sizes.
+ *
+ * Also always use mmap; the files are "trusted", as we created them.
+ */
+static ssize_t cgi_write_file_chunk_mmap(server *srv, connection *con, int fd, chunkqueue *cq) {
+ chunk* const c = cq->first;
+ off_t offset, toSend, file_end;
+ ssize_t r;
+ size_t mmap_offset, mmap_avail;
+ char *data = NULL;
+
+ force_assert(NULL != c);
+ force_assert(FILE_CHUNK == c->type);
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ file_end = c->file.start + c->file.length; /* offset to file end in this chunk */
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ /*(simplified from chunk.c:chunkqueue_open_file_chunk())*/
+ UNUSED(con);
+ if (-1 == c->file.fd) {
+ if (-1 == (c->file.fd = fdevent_open_cloexec(c->mem->ptr, O_RDONLY, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "open failed:", strerror(errno), c->mem);
+ return -1;
+ }
+ }
+
+ /* (re)mmap the buffer if range is not covered completely */
+ if (MAP_FAILED == c->file.mmap.start
+ || offset < c->file.mmap.offset
+ || file_end > (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
+
+ if (MAP_FAILED != c->file.mmap.start) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ }
+
+ c->file.mmap.offset = mmap_align_offset(offset);
+ c->file.mmap.length = file_end - c->file.mmap.offset;
+
+ if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, MAP_PRIVATE, c->file.fd, c->file.mmap.offset))) {
+ if (toSend > 65536) toSend = 65536;
+ data = malloc(toSend);
+ force_assert(data);
+ if (-1 == lseek(c->file.fd, offset, SEEK_SET)
+ || 0 >= (toSend = read(c->file.fd, data, toSend))) {
+ if (-1 == toSend) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbdo", "lseek/read failed:",
+ strerror(errno), c->mem, c->file.fd, offset);
+ } else { /*(0 == toSend)*/
+ log_error_write(srv, __FILE__, __LINE__, "sbdo", "unexpected EOF (input truncated?):",
+ c->mem, c->file.fd, offset);
+ }
+ free(data);
+ return -1;
+ }
+ }
+ }
+
+ if (MAP_FAILED != c->file.mmap.start) {
+ force_assert(offset >= c->file.mmap.offset);
+ mmap_offset = offset - c->file.mmap.offset;
+ force_assert(c->file.mmap.length > mmap_offset);
+ mmap_avail = c->file.mmap.length - mmap_offset;
+ force_assert(toSend <= (off_t) mmap_avail);
+
+ data = c->file.mmap.start + mmap_offset;
+ }
+
+ r = write(fd, data, toSend);
+
+ if (MAP_FAILED == c->file.mmap.start) free(data);
+
+ if (r < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ return 0;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+ return -1;
+ }
+ }
+
+ if (r >= 0) {
+ chunkqueue_mark_written(cq, r);
+ }
+
+ return r;
+}
+
+static int cgi_write_request(server *srv, handler_ctx *hctx, int fd) {
+ connection *con = hctx->remote_conn;
+ chunkqueue *cq = con->request_content_queue;
+ chunk *c;
+
+ /* old comment: windows doesn't support select() on pipes - wouldn't be easy to fix for all platforms.
+ * solution: if this is still a problem on windows, then substitute
+ * socketpair() for pipe() and closesocket() for close() on windows.
+ */
+
+ for (c = cq->first; c; c = cq->first) {
+ ssize_t r = -1;
+
+ switch(c->type) {
+ case FILE_CHUNK:
+ r = cgi_write_file_chunk_mmap(srv, con, fd, cq);
+ break;
+
+ case MEM_CHUNK:
+ if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
+ switch(errno) {
+ case EAGAIN:
+ case EINTR:
+ /* ignore and try again */
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ /* connection closed */
+ r = -2;
+ break;
+ default:
+ /* fatal error */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "write failed due to: ", strerror(errno));
+ r = -1;
+ break;
+ }
+ } else if (r > 0) {
+ chunkqueue_mark_written(cq, r);
+ }
+ break;
+ }
+
+ if (0 == r) break; /*(might block)*/
+
+ switch (r) {
+ case -1:
+ /* fatal error */
+ return -1;
+ case -2:
+ /* connection reset */
+ log_error_write(srv, __FILE__, __LINE__, "s", "failed to send post data to cgi, connection closed by CGI");
+ /* skip all remaining data */
+ chunkqueue_mark_written(cq, chunkqueue_length(cq));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (cq->bytes_out == (off_t)con->request.content_length && !hctx->conf.upgrade) {
+ /* sent all request body input */
+ /* close connection to the cgi-script */
+ if (-1 == hctx->fdtocgi) { /*(received request body sent in initial send to pipe buffer)*/
+ --srv->cur_fds;
+ if (close(fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "sds", "cgi stdin close failed ", fd, strerror(errno));
+ }
+ } else {
+ cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
+ }
+ } else {
+ off_t cqlen = cq->bytes_in - cq->bytes_out;
+ if (cq->bytes_in != con->request.content_length && cqlen < 65536 - 16384) {
+ /*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/
+ if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) {
+ con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
+ con->is_readable = 1; /* trigger optimistic read from client */
+ }
+ }
+ if (-1 == hctx->fdtocgi) { /*(not registered yet)*/
+ hctx->fdtocgi = fd;
+ hctx->fde_ndx_tocgi = -1;
+ fdevent_register(srv->ev, hctx->fdtocgi, cgi_handle_fdevent_send, hctx);
+ }
+ if (0 == cqlen) { /*(chunkqueue_is_empty(cq))*/
+ if ((fdevent_event_get_interest(srv->ev, hctx->fdtocgi) & FDEVENT_OUT)) {
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi, 0);
+ }
+ } else {
+ /* more request body remains to be sent to CGI so register for fdevents */
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi, FDEVENT_OUT);
+ }
+ }
+
+ return 0;
+}
+
+static struct stat * cgi_stat(server *srv, connection *con, buffer *path, struct stat *st) {
+ /* CGI might be executable even if it is not readable
+ * (stat_cache_get_entry() currently checks file is readable)*/
+ stat_cache_entry *sce;
+ return (HANDLER_ERROR != stat_cache_get_entry(srv, con, path, &sce))
+ ? &sce->st
+ : (0 == stat(path->ptr, st)) ? st : NULL;
+}
+
+static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) {
+ char *args[3];
+ int to_cgi_fds[2];
+ int from_cgi_fds[2];
+ int dfd = -1;
+ UNUSED(p);
+
+ if (!buffer_string_is_empty(cgi_handler)) {
+ /* stat the exec file */
+ struct stat st;
+ if (NULL == cgi_stat(srv, con, cgi_handler, &st)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "stat for cgi-handler", cgi_handler,
+ "failed:", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (pipe_cloexec(to_cgi_fds)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
+ return -1;
+ }
+ if (pipe_cloexec(from_cgi_fds)) {
+ close(to_cgi_fds[0]);
+ close(to_cgi_fds[1]);
+ log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
+ return -1;
+ }
+ fdevent_setfd_cloexec(to_cgi_fds[1]);
+ fdevent_setfd_cloexec(from_cgi_fds[0]);
+
+ {
+ size_t i = 0;
+ http_cgi_opts opts = { 0, 0, NULL, NULL };
+ env_accum *env = &p->env;
+ env->used = 0;
+ env->oused = 0;
+
+ /* create environment */
+
+ http_cgi_headers(srv, con, &opts, cgi_env_add, env);
+
+ /* for valgrind */
+ if (p->env.ld_preload) {
+ cgi_env_add(env, CONST_STR_LEN("LD_PRELOAD"), CONST_BUF_LEN(p->env.ld_preload));
+ }
+ if (p->env.ld_library_path) {
+ cgi_env_add(env, CONST_STR_LEN("LD_LIBRARY_PATH"), CONST_BUF_LEN(p->env.ld_library_path));
+ }
+ #ifdef __CYGWIN__
+ /* CYGWIN needs SYSTEMROOT */
+ if (p->env.systemroot) {
+ cgi_env_add(env, CONST_STR_LEN("SYSTEMROOT"), CONST_BUF_LEN(p->env.systemroot));
+ }
+ #endif
+
+ if (env->esize <= env->oused) {
+ env->esize = (env->oused + 1 + 0xf) & ~(0xfuL);
+ env->eptr = realloc(env->eptr, env->esize * sizeof(*env->eptr));
+ force_assert(env->eptr);
+ }
+ for (i = 0; i < env->oused; ++i) {
+ env->eptr[i] = env->ptr + env->offsets[i];
+ }
+ env->eptr[env->oused] = NULL;
+
+ /* set up args */
+ i = 0;
+
+ if (!buffer_string_is_empty(cgi_handler)) {
+ args[i++] = cgi_handler->ptr;
+ }
+ args[i++] = con->physical.path->ptr;
+ args[i ] = NULL;
+ }
+
+ dfd = fdevent_open_dirname(con->physical.path->ptr);
+ if (-1 == dfd) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "open dirname failed:", strerror(errno), con->physical.path);
+ }
+
+ hctx->pid = (dfd >= 0) ? fdevent_fork_execve(args[0], args, p->env.eptr, to_cgi_fds[0], from_cgi_fds[1], -1, dfd) : -1;
+
+ if (-1 == hctx->pid) {
+ /* log error with errno prior to calling close() (might change errno) */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
+ if (-1 != dfd) close(dfd);
+ close(from_cgi_fds[0]);
+ close(from_cgi_fds[1]);
+ close(to_cgi_fds[0]);
+ close(to_cgi_fds[1]);
+ return -1;
+ } else {
+ if (-1 != dfd) close(dfd);
+ close(from_cgi_fds[1]);
+ close(to_cgi_fds[0]);
+
+ hctx->fd = from_cgi_fds[0];
+ hctx->fde_ndx = -1;
+
+ ++srv->cur_fds;
+
+ cgi_pid_add(p, hctx->pid, hctx);
+
+ if (0 == con->request.content_length) {
+ close(to_cgi_fds[1]);
+ } else {
+ /* there is content to send */
+ if (-1 == fdevent_fcntl_set_nb(srv->ev, to_cgi_fds[1])) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
+ close(to_cgi_fds[1]);
+ cgi_connection_close(srv, hctx);
+ return -1;
+ }
+
+ if (0 != cgi_write_request(srv, hctx, to_cgi_fds[1])) {
+ close(to_cgi_fds[1]);
+ cgi_connection_close(srv, hctx);
+ return -1;
+ }
+
+ ++srv->cur_fds;
+ }
+
+ fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
+ if (-1 == fdevent_fcntl_set_nb(srv->ev, hctx->fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
+ cgi_connection_close(srv, hctx);
+ return -1;
+ }
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN | FDEVENT_RDHUP);
+
+ return 0;
+ }
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(cgi);
+ PATCH(execute_x_only);
+ PATCH(local_redir);
+ PATCH(upgrade);
+ PATCH(xsendfile_allow);
+ PATCH(xsendfile_docroot);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
+ PATCH(cgi);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) {
+ PATCH(execute_x_only);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.local-redir"))) {
+ PATCH(local_redir);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.upgrade"))) {
+ PATCH(upgrade);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile"))) {
+ PATCH(xsendfile_allow);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile-docroot"))) {
+ PATCH(xsendfile_docroot);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(cgi_is_handled) {
+ plugin_data *p = p_d;
+ struct stat stbuf;
+ struct stat *st;
+ data_string *ds;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_cgi_patch_connection(srv, con, p);
+
+ ds = (data_string *)array_match_key_suffix(p->conf.cgi, con->physical.path);
+ if (NULL == ds) return HANDLER_GO_ON;
+
+ st = cgi_stat(srv, con, con->physical.path, &stbuf);
+ if (NULL == st) return HANDLER_GO_ON;
+
+ if (!S_ISREG(st->st_mode)) return HANDLER_GO_ON;
+ if (p->conf.execute_x_only == 1 && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
+
+ {
+ handler_ctx *hctx = cgi_handler_ctx_init();
+ hctx->remote_conn = con;
+ hctx->plugin_data = p;
+ hctx->cgi_handler = ds->value;
+ memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
+ hctx->conf.upgrade =
+ hctx->conf.upgrade
+ && con->request.http_version == HTTP_VERSION_1_1
+ && NULL != http_header_request_get(con, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade"));
+ hctx->opts.fdfmt = S_IFIFO;
+ hctx->opts.backend = BACKEND_CGI;
+ hctx->opts.authorizer = 0;
+ hctx->opts.local_redir = hctx->conf.local_redir;
+ hctx->opts.xsendfile_allow = hctx->conf.xsendfile_allow;
+ hctx->opts.xsendfile_docroot = hctx->conf.xsendfile_docroot;
+ hctx->opts.pdata = hctx;
+ hctx->opts.headers = cgi_response_headers;
+ con->plugin_ctx[p->id] = hctx;
+ con->mode = p->id;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/*
+ * - HANDLER_GO_ON : not our job
+ * - HANDLER_FINISHED: got response
+ * - HANDLER_WAIT_FOR_EVENT: waiting for response
+ */
+SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ chunkqueue *cq = con->request_content_queue;
+
+ if (con->mode != p->id) return HANDLER_GO_ON;
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
+ && con->file_started) {
+ if (chunkqueue_length(con->write_queue) > 65536 - 4096) {
+ fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ } else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) {
+ /* optimistic read from backend */
+ handler_t rc = cgi_recv_response(srv, hctx); /*(might invalidate hctx)*/
+ if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/
+ fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ }
+ }
+
+ if (cq->bytes_in != (off_t)con->request.content_length) {
+ /*(64k - 4k to attempt to avoid temporary files
+ * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/
+ if (cq->bytes_in - cq->bytes_out > 65536 - 4096
+ && (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)){
+ con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
+ if (-1 != hctx->fd) return HANDLER_WAIT_FOR_EVENT;
+ } else {
+ handler_t r = connection_handle_read_post_state(srv, con);
+ if (!chunkqueue_is_empty(cq)) {
+ if (fdevent_event_get_interest(srv->ev, hctx->fdtocgi) & FDEVENT_OUT) {
+ return (r == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : r;
+ }
+ }
+ if (r != HANDLER_GO_ON) return r;
+
+ /* CGI environment requires that Content-Length be set.
+ * Send 411 Length Required if Content-Length missing.
+ * (occurs here if client sends Transfer-Encoding: chunked
+ * and module is flagged to stream request body to backend) */
+ if (-1 == con->request.content_length) {
+ return connection_handle_read_post_error(srv, con, 411);
+ }
+ }
+ }
+
+ if (-1 == hctx->fd) {
+ if (cgi_create_env(srv, con, p, hctx, hctx->cgi_handler)) {
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+ } else if (!chunkqueue_is_empty(con->request_content_queue)) {
+ if (0 != cgi_write_request(srv, hctx, hctx->fdtocgi)) {
+ cgi_connection_close(srv, hctx);
+ return HANDLER_ERROR;
+ }
+ }
+
+ /* if not done, wait for CGI to close stdout, so we read EOF on pipe */
+ return HANDLER_WAIT_FOR_EVENT;
+}
+
+
+static handler_t cgi_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) {
+ plugin_data *p = (plugin_data *)p_d;
+ for (size_t i = 0; i < p->cgi_pid.used; ++i) {
+ handler_ctx *hctx;
+ if (pid != p->cgi_pid.ptr[i].pid) continue;
+
+ hctx = (handler_ctx *)p->cgi_pid.ptr[i].ctx;
+ if (hctx) hctx->pid = -1;
+ cgi_pid_del(p, i);
+
+ if (WIFEXITED(status)) {
+ /* (skip logging (non-zero) CGI exit; might be very noisy) */
+ }
+ else if (WIFSIGNALED(status)) {
+ /* ignore SIGTERM if sent by cgi_connection_close() (NULL == hctx)*/
+ if (WTERMSIG(status) != SIGTERM || NULL != hctx) {
+ log_error_write(srv, __FILE__, __LINE__, "sdsd", "CGI pid", pid,
+ "died with signal", WTERMSIG(status));
+ }
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "CGI pid", pid, "ended unexpectedly");
+ }
+
+ return HANDLER_FINISHED;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_cgi_plugin_init(plugin *p);
+int mod_cgi_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("cgi");
+
+ p->connection_reset = cgi_connection_close_callback;
+ p->handle_subrequest_start = cgi_is_handled;
+ p->handle_subrequest = mod_cgi_handle_subrequest;
+ p->handle_waitpid = cgi_waitpid_cb;
+ p->init = mod_cgi_init;
+ p->cleanup = mod_cgi_free;
+ p->set_defaults = mod_fastcgi_set_defaults;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_cml.c b/data/lighttpd/lighttpd-1.4.53/src/mod_cml.c
new file mode 100644
index 000000000..c82a4c27b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_cml.c
@@ -0,0 +1,340 @@
+#include "first.h"
+
+#include "mod_cml.h"
+
+#include "base.h"
+#include "buffer.h"
+#include "log.h"
+#include "plugin.h"
+
+#include <sys/stat.h>
+#include <time.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* init the plugin data */
+INIT_FUNC(mod_cml_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->basedir = buffer_init();
+ p->baseurl = buffer_init();
+ p->trigger_handler = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_cml_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->ext);
+
+ buffer_free(s->mc_namespace);
+ buffer_free(s->power_magnet);
+ array_free(s->mc_hosts);
+
+#if defined(USE_MEMCACHED)
+ if (s->memc) memcached_free(s->memc);
+#endif
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->trigger_handler);
+ buffer_free(p->basedir);
+ buffer_free(p->baseurl);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_cml_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->ext = buffer_init();
+ s->mc_hosts = array_init();
+ s->mc_namespace = buffer_init();
+ s->power_magnet = buffer_init();
+#if defined(USE_MEMCACHED)
+ s->memc = NULL;
+#endif
+
+ cv[0].destination = s->ext;
+ cv[1].destination = s->mc_hosts;
+ cv[2].destination = s->mc_namespace;
+ cv[3].destination = s->power_magnet;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->mc_hosts)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for cml.memcache-hosts; expected list of \"host\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->mc_hosts->used) {
+#if defined(USE_MEMCACHED)
+ buffer *option_string = buffer_init();
+ size_t k;
+
+ {
+ data_string *ds = (data_string *)s->mc_hosts->data[0];
+
+ buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER="));
+ buffer_append_string_buffer(option_string, ds->value);
+ }
+
+ for (k = 1; k < s->mc_hosts->used; k++) {
+ data_string *ds = (data_string *)s->mc_hosts->data[k];
+
+ buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
+ buffer_append_string_buffer(option_string, ds->value);
+ }
+
+ s->memc = memcached(CONST_BUF_LEN(option_string));
+
+ if (NULL == s->memc) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "configuring memcached failed for option string:",
+ option_string);
+ }
+ buffer_free(option_string);
+
+ if (NULL == s->memc) return HANDLER_ERROR;
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
+ return HANDLER_ERROR;
+#endif
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(ext);
+#if defined(USE_MEMCACHED)
+ PATCH(memc);
+#endif
+ PATCH(mc_namespace);
+ PATCH(power_magnet);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
+ PATCH(ext);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
+#if defined(USE_MEMCACHED)
+ PATCH(memc);
+#endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
+ PATCH(mc_namespace);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
+ PATCH(power_magnet);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
+ buffer *b;
+ char *c;
+
+ /* cleanup basedir */
+ b = p->baseurl;
+ buffer_copy_buffer(b, con->uri.path);
+ for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
+
+ if (*c == '/') {
+ buffer_string_set_length(b, c - b->ptr + 1);
+ }
+
+ b = p->basedir;
+ buffer_copy_buffer(b, con->physical.path);
+ for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
+
+ if (*c == '/') {
+ buffer_string_set_length(b, c - b->ptr + 1);
+ }
+
+
+ /* prepare variables
+ * - cookie-based
+ * - get-param-based
+ */
+ return cache_parse_lua(srv, con, p, cml_file);
+}
+
+URIHANDLER_FUNC(mod_cml_power_magnet) {
+ plugin_data *p = p_d;
+
+ mod_cml_patch_connection(srv, con, p);
+
+ buffer_clear(p->basedir);
+ buffer_clear(p->baseurl);
+ buffer_clear(p->trigger_handler);
+
+ if (buffer_string_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
+
+ /*
+ * power-magnet:
+ * cml.power-magnet = server.docroot + "/rewrite.cml"
+ *
+ * is called on EACH request, take the original REQUEST_URI and modifies the
+ * request header as neccesary.
+ *
+ * First use:
+ * if file_exists("/maintainance.html") {
+ * output_include = ( "/maintainance.html" )
+ * return CACHE_HIT
+ * }
+ *
+ * as we only want to rewrite HTML like requests we should cover it in a conditional
+ *
+ * */
+
+ switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
+ case -1:
+ /* error */
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
+ }
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ case 0:
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
+ }
+ /* cache-hit */
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ case 1:
+ /* cache miss */
+ return HANDLER_GO_ON;
+ default:
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ }
+}
+
+URIHANDLER_FUNC(mod_cml_is_handled) {
+ plugin_data *p = p_d;
+
+ if (buffer_string_is_empty(con->physical.path)) return HANDLER_ERROR;
+
+ mod_cml_patch_connection(srv, con, p);
+
+ buffer_clear(p->basedir);
+ buffer_clear(p->baseurl);
+ buffer_clear(p->trigger_handler);
+
+ if (buffer_string_is_empty(p->conf.ext)) return HANDLER_GO_ON;
+
+ if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, buffer_string_length(p->conf.ext))) {
+ return HANDLER_GO_ON;
+ }
+
+ switch(cache_call_lua(srv, con, p, con->physical.path)) {
+ case -1:
+ /* error */
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
+ }
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ case 0:
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
+ }
+ /* cache-hit */
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ case 1:
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-miss");
+ }
+ /* cache miss */
+ return HANDLER_COMEBACK;
+ default:
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ }
+}
+
+int mod_cml_plugin_init(plugin *p);
+int mod_cml_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("cache");
+
+ p->init = mod_cml_init;
+ p->cleanup = mod_cml_free;
+ p->set_defaults = mod_cml_set_defaults;
+
+ p->handle_subrequest_start = mod_cml_is_handled;
+ p->handle_physical = mod_cml_power_magnet;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_cml.h b/data/lighttpd/lighttpd-1.4.53/src/mod_cml.h
new file mode 100644
index 000000000..d1d0c52a8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_cml.h
@@ -0,0 +1,42 @@
+#ifndef _MOD_CACHE_H_
+#define _MOD_CACHE_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#if defined(USE_MEMCACHED)
+#include <libmemcached/memcached.h>
+#endif
+
+#define plugin_data mod_cache_plugin_data
+
+typedef struct {
+ buffer *ext;
+
+ array *mc_hosts;
+ buffer *mc_namespace;
+#if defined(USE_MEMCACHED)
+ memcached_st *memc;
+#endif
+ buffer *power_magnet;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *basedir;
+ buffer *baseurl;
+
+ buffer *trigger_handler;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.c b/data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.c
new file mode 100644
index 000000000..cc674a2f0
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.c
@@ -0,0 +1,269 @@
+#include "first.h"
+
+#include <sys/stat.h>
+#include <time.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <lauxlib.h>
+
+#include "mod_cml_funcs.h"
+#include "mod_cml.h"
+
+#include "buffer.h"
+#include "log.h"
+#include "plugin.h"
+
+#include "md5.h"
+
+#define HASHLEN 16
+typedef unsigned char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+
+int f_crypto_md5(lua_State *L) {
+ li_MD5_CTX Md5Ctx;
+ HASH HA1;
+ char hex[33];
+ int n = lua_gettop(L);
+ size_t s_len;
+ const char *s;
+
+ if (n != 1) {
+ lua_pushstring(L, "md5: expected one argument");
+ lua_error(L);
+ }
+
+ if (!lua_isstring(L, 1)) {
+ lua_pushstring(L, "md5: argument has to be a string");
+ lua_error(L);
+ }
+
+ s = lua_tolstring(L, 1, &s_len);
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *) s, (unsigned int) s_len);
+ li_MD5_Final(HA1, &Md5Ctx);
+
+ li_tohex(hex, sizeof(hex), (const char*) HA1, 16);
+
+ lua_pushstring(L, hex);
+
+ return 1;
+}
+
+
+int f_file_mtime(lua_State *L) {
+ struct stat st;
+ int n = lua_gettop(L);
+
+ if (n != 1) {
+ lua_pushstring(L, "file_mtime: expected one argument");
+ lua_error(L);
+ }
+
+ if (!lua_isstring(L, 1)) {
+ lua_pushstring(L, "file_mtime: argument has to be a string");
+ lua_error(L);
+ }
+
+ if (-1 == stat(lua_tostring(L, 1), &st)) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_pushinteger(L, st.st_mtime);
+
+ return 1;
+}
+
+static int f_dir_files_iter(lua_State *L) {
+ DIR *d;
+ struct dirent *de;
+
+ d = lua_touserdata(L, lua_upvalueindex(1));
+
+ if (NULL == (de = readdir(d))) {
+ /* EOF */
+ closedir(d);
+
+ return 0;
+ } else {
+ lua_pushstring(L, de->d_name);
+ return 1;
+ }
+}
+
+int f_dir_files(lua_State *L) {
+ DIR *d;
+ int n = lua_gettop(L);
+
+ if (n != 1) {
+ lua_pushstring(L, "dir_files: expected one argument");
+ lua_error(L);
+ }
+
+ if (!lua_isstring(L, 1)) {
+ lua_pushstring(L, "dir_files: argument has to be a string");
+ lua_error(L);
+ }
+
+ /* check if there is a valid DIR handle on the stack */
+ if (NULL == (d = opendir(lua_tostring(L, 1)))) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ /* push d into userdata */
+ lua_pushlightuserdata(L, d);
+ lua_pushcclosure(L, f_dir_files_iter, 1);
+
+ return 1;
+}
+
+int f_file_isreg(lua_State *L) {
+ struct stat st;
+ int n = lua_gettop(L);
+
+ if (n != 1) {
+ lua_pushstring(L, "file_isreg: expected one argument");
+ lua_error(L);
+ }
+
+ if (!lua_isstring(L, 1)) {
+ lua_pushstring(L, "file_isreg: argument has to be a string");
+ lua_error(L);
+ }
+
+ if (-1 == stat(lua_tostring(L, 1), &st)) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_pushinteger(L, S_ISREG(st.st_mode));
+
+ return 1;
+}
+
+int f_file_isdir(lua_State *L) {
+ struct stat st;
+ int n = lua_gettop(L);
+
+ if (n != 1) {
+ lua_pushstring(L, "file_isreg: expected one argument");
+ lua_error(L);
+ }
+
+ if (!lua_isstring(L, 1)) {
+ lua_pushstring(L, "file_isreg: argument has to be a string");
+ lua_error(L);
+ }
+
+ if (-1 == stat(lua_tostring(L, 1), &st)) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_pushinteger(L, S_ISDIR(st.st_mode));
+
+ return 1;
+}
+
+
+
+#ifdef USE_MEMCACHED
+int f_memcache_exists(lua_State *L) {
+ size_t key_len;
+ const char *key;
+ memcached_st *memc;
+
+ if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
+ lua_pushstring(L, "where is my userdata ?");
+ lua_error(L);
+ }
+
+ memc = lua_touserdata(L, lua_upvalueindex(1));
+
+ if (1 != lua_gettop(L)) {
+ lua_pushstring(L, "expected one argument");
+ lua_error(L);
+ }
+
+ key = luaL_checklstring(L, 1, &key_len);
+ lua_pushboolean(L, (MEMCACHED_SUCCESS == memcached_exist(memc, key, key_len)));
+ return 1;
+}
+
+int f_memcache_get_string(lua_State *L) {
+ size_t key_len, value_len;
+ char *value;
+ const char *key;
+ memcached_st *memc;
+
+ if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
+ lua_pushstring(L, "where is my userdata ?");
+ lua_error(L);
+ }
+
+ memc = lua_touserdata(L, lua_upvalueindex(1));
+
+ if (1 != lua_gettop(L)) {
+ lua_pushstring(L, "expected one argument");
+ lua_error(L);
+ }
+
+ key = luaL_checklstring(L, 1, &key_len);
+ if (NULL == (value = memcached_get(memc, key, key_len, &value_len, NULL, NULL))) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_pushlstring(L, value, value_len);
+
+ free(value);
+
+ return 1;
+}
+
+int f_memcache_get_long(lua_State *L) {
+ size_t key_len, value_len;
+ char *value;
+ const char *key;
+ memcached_st *memc;
+ char *endptr;
+ long v;
+
+ if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
+ lua_pushstring(L, "where is my userdata ?");
+ lua_error(L);
+ }
+
+ memc = lua_touserdata(L, lua_upvalueindex(1));
+
+ if (1 != lua_gettop(L)) {
+ lua_pushstring(L, "expected one argument");
+ lua_error(L);
+ }
+
+ key = luaL_checklstring(L, 1, &key_len);
+ if (NULL == (value = memcached_get(memc, key, key_len, &value_len, NULL, NULL))) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ errno = 0;
+ v = strtol(value, &endptr, 10);
+ if (0 == errno && *endptr == '\0') {
+ lua_pushinteger(L, v);
+ } else {
+ lua_pushnil(L);
+ }
+
+ free(value);
+
+ return 1;
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.h b/data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.h
new file mode 100644
index 000000000..49243350b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_cml_funcs.h
@@ -0,0 +1,16 @@
+#ifndef _MOD_CML_FUNCS_H_
+#define _MOD_CML_FUNCS_H_
+#include "first.h"
+
+#include <lua.h>
+
+int f_crypto_md5(lua_State *L);
+int f_file_mtime(lua_State *L);
+int f_file_isreg(lua_State *L);
+int f_file_isdir(lua_State *L);
+int f_dir_files(lua_State *L);
+
+int f_memcache_exists(lua_State *L);
+int f_memcache_get_string(lua_State *L);
+int f_memcache_get_long(lua_State *L);
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_cml_lua.c b/data/lighttpd/lighttpd-1.4.53/src/mod_cml_lua.c
new file mode 100644
index 000000000..41b554363
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_cml_lua.c
@@ -0,0 +1,325 @@
+#include "first.h"
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+
+#include "mod_cml_funcs.h"
+#include "mod_cml.h"
+
+#include "base.h"
+#include "chunk.h"
+#include "log.h"
+#include "http_header.h"
+#include "response.h"
+#include "stat_cache.h"
+
+#define HASHLEN 16
+typedef unsigned char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+
+static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
+ int curelem = lua_gettop(L);
+ int result;
+
+ lua_getglobal(L, varname);
+
+ if (lua_isstring(L, curelem)) {
+ buffer_copy_string(b, lua_tostring(L, curelem));
+ result = 0;
+ } else {
+ result = -1;
+ }
+
+ lua_pop(L, 1);
+ force_assert(curelem == lua_gettop(L));
+ return result;
+}
+
+static int lua_to_c_is_table(lua_State *L, const char *varname) {
+ int curelem = lua_gettop(L);
+ int result;
+
+ lua_getglobal(L, varname);
+
+ result = lua_istable(L, curelem) ? 1 : 0;
+
+ lua_pop(L, 1);
+ force_assert(curelem == lua_gettop(L));
+ return result;
+}
+
+static int c_to_lua_push(lua_State *L, int tbl, const char *key, size_t key_len, const char *val, size_t val_len) {
+ lua_pushlstring(L, key, key_len);
+ lua_pushlstring(L, val, val_len);
+ lua_settable(L, tbl);
+
+ return 0;
+}
+
+static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) {
+ size_t is_key = 1;
+ size_t i, len, klen = 0;
+ char *key = NULL, *val = NULL;
+
+ if (buffer_string_is_empty(qrystr)) return 0;
+ key = qrystr->ptr;
+
+ /* we need the \0 */
+ len = buffer_string_length(qrystr);
+ for (i = 0; i <= len; i++) {
+ switch(qrystr->ptr[i]) {
+ case '=':
+ if (is_key) {
+ val = qrystr->ptr + i + 1;
+ klen = (size_t)(val - key - 1);
+ is_key = 0;
+ }
+
+ break;
+ case '&':
+ case '\0': /* fin symbol */
+ if (!is_key) {
+ /* we need at least a = since the last & */
+ c_to_lua_push(L, tbl,
+ key, klen,
+ val, (size_t)(qrystr->ptr + i - val));
+ }
+
+ key = qrystr->ptr + i + 1;
+ val = NULL;
+ is_key = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ lua_State *L;
+ int ret = -1;
+ buffer *b;
+
+ b = buffer_init();
+ /* push the lua file to the interpreter and see what happends */
+ L = luaL_newstate();
+ luaL_openlibs(L);
+
+ /* register functions */
+ lua_register(L, "md5", f_crypto_md5);
+ lua_register(L, "file_mtime", f_file_mtime);
+ lua_register(L, "file_isreg", f_file_isreg);
+ lua_register(L, "file_isdir", f_file_isreg);
+ lua_register(L, "dir_files", f_dir_files);
+
+#ifdef USE_MEMCACHED
+ lua_pushlightuserdata(L, p->conf.memc);
+ lua_pushcclosure(L, f_memcache_get_long, 1);
+ lua_setglobal(L, "memcache_get_long");
+
+ lua_pushlightuserdata(L, p->conf.memc);
+ lua_pushcclosure(L, f_memcache_get_string, 1);
+ lua_setglobal(L, "memcache_get_string");
+
+ lua_pushlightuserdata(L, p->conf.memc);
+ lua_pushcclosure(L, f_memcache_exists, 1);
+ lua_setglobal(L, "memcache_exists");
+#endif
+
+ /* register CGI environment */
+ lua_newtable(L);
+ {
+ int header_tbl = lua_gettop(L);
+
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
+ if (!buffer_string_is_empty(con->request.pathinfo)) {
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
+ }
+
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
+ }
+ lua_setglobal(L, "request");
+
+ /* register GET parameter */
+ lua_newtable(L);
+ cache_export_get_params(L, lua_gettop(L), con->uri.query);
+ lua_setglobal(L, "get");
+
+ /* 2 default constants */
+ lua_pushinteger(L, 0);
+ lua_setglobal(L, "CACHE_HIT");
+
+ lua_pushinteger(L, 1);
+ lua_setglobal(L, "CACHE_MISS");
+
+ /* load lua program */
+ ret = luaL_loadfile(L, fn->ptr);
+ if (0 != ret) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsS",
+ "failed loading cml_lua script",
+ fn,
+ ":",
+ lua_tostring(L, -1));
+ goto error;
+ }
+
+ if (lua_pcall(L, 0, 1, 0)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsS",
+ "failed running cml_lua script",
+ fn,
+ ":",
+ lua_tostring(L, -1));
+ goto error;
+ }
+
+ /* get return value */
+ ret = (int)lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ /* fetch the data from lua */
+ lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
+
+ if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
+ }
+
+ if (ret == 0) {
+ /* up to now it is a cache-hit, check if all files exist */
+
+ int curelem;
+ time_t mtime = 0;
+
+ if (!lua_to_c_is_table(L, "output_include")) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "output_include is missing or not a table");
+ ret = -1;
+
+ goto error;
+ }
+
+ lua_getglobal(L, "output_include");
+ curelem = lua_gettop(L);
+
+ /* HOW-TO build a etag ?
+ * as we don't just have one file we have to take the stat()
+ * from all base files, merge them and build the etag from
+ * it later.
+ *
+ * The mtime of the content is the mtime of the freshest base file
+ *
+ * */
+
+ lua_pushnil(L); /* first key */
+ while (lua_next(L, curelem) != 0) {
+ /* key' is at index -2 and value' at index -1 */
+
+ if (lua_isstring(L, -1)) {
+ const char *s = lua_tostring(L, -1);
+ struct stat st;
+ int fd;
+
+ /* the file is relative, make it absolute */
+ if (s[0] != '/') {
+ buffer_copy_buffer(b, p->basedir);
+ buffer_append_string(b, lua_tostring(L, -1));
+ } else {
+ buffer_copy_string(b, lua_tostring(L, -1));
+ }
+
+ fd = stat_cache_open_rdonly_fstat(srv, con, b, &st);
+ if (fd < 0) {
+ /* stat failed */
+
+ switch(errno) {
+ case ENOENT:
+ /* a file is missing, call the handler to generate it */
+ if (!buffer_string_is_empty(p->trigger_handler)) {
+ ret = 1; /* cache-miss */
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "a file is missing, calling handler");
+
+ break;
+ } else {
+ /* handler not set -> 500 */
+ ret = -1;
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "a file missing and no handler set");
+
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ chunkqueue_append_file_fd(con->write_queue, b, fd, 0, st.st_size);
+ if (st.st_mtime > mtime) mtime = st.st_mtime;
+ }
+ } else {
+ /* not a string */
+ ret = -1;
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "not a string");
+ break;
+ }
+
+ lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
+ }
+
+ lua_settop(L, curelem - 1);
+
+ if (ret == 0) {
+ buffer *vb = http_header_response_get(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"));
+ if (NULL == vb) { /* no Last-Modified specified */
+ char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
+ if (0 == mtime) mtime = time(NULL); /* default last-modified to now */
+ strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
+ http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
+ vb = http_header_response_get(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"));
+ force_assert(NULL != vb);
+ }
+
+ con->file_finished = 1;
+
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, vb)) {
+ /* ok, the client already has our content,
+ * no need to send it again */
+
+ chunkqueue_reset(con->write_queue);
+ ret = 0; /* cache-hit */
+ }
+ } else {
+ chunkqueue_reset(con->write_queue);
+ }
+ }
+
+ if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) {
+ /* cache-miss */
+ buffer_copy_buffer(con->uri.path, p->baseurl);
+ buffer_append_string_buffer(con->uri.path, p->trigger_handler);
+
+ buffer_copy_buffer(con->physical.path, p->basedir);
+ buffer_append_string_buffer(con->physical.path, p->trigger_handler);
+
+ chunkqueue_reset(con->write_queue);
+ }
+
+error:
+ lua_close(L);
+
+ buffer_free(b);
+
+ return ret /* cache-error */;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_compress.c b/data/lighttpd/lighttpd-1.4.53/src/mod_compress.c
new file mode 100644
index 000000000..dc8babcd8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_compress.c
@@ -0,0 +1,1034 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+#include "response.h"
+#include "stat_cache.h"
+
+#include "plugin.h"
+
+#include "crc32.h"
+#include "etag.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sys-strings.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
+# define USE_ZLIB
+# include <zlib.h>
+#endif
+
+#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
+# define USE_BZ2LIB
+/* we don't need stdio interface */
+# define BZ_NO_STDIO
+# include <bzlib.h>
+#endif
+
+#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP && defined ENABLE_MMAP
+#define USE_MMAP
+
+#include "sys-mmap.h"
+#include <setjmp.h>
+#include <signal.h>
+
+static volatile int sigbus_jmp_valid;
+static sigjmp_buf sigbus_jmp;
+
+static void sigbus_handler(int sig) {
+ UNUSED(sig);
+ if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
+ log_failed_assert(__FILE__, __LINE__, "SIGBUS");
+}
+#endif
+
+/* request: accept-encoding */
+#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
+#define HTTP_ACCEPT_ENCODING_GZIP BV(1)
+#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2)
+#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3)
+#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4)
+#define HTTP_ACCEPT_ENCODING_X_GZIP BV(5)
+#define HTTP_ACCEPT_ENCODING_X_BZIP2 BV(6)
+
+#ifdef __WIN32
+# define mkdir(x,y) mkdir(x)
+#endif
+
+typedef struct {
+ buffer *compress_cache_dir;
+ array *compress;
+ off_t compress_max_filesize; /** max filesize in kb */
+ int allowed_encodings;
+ double max_loadavg;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ buffer *ofn;
+ buffer *b;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_compress_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->ofn = buffer_init();
+ p->b = buffer_init();
+
+ return p;
+}
+
+FREE_FUNC(mod_compress_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ buffer_free(p->ofn);
+ buffer_free(p->b);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->compress);
+ buffer_free(s->compress_cache_dir);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* 0 on success, -1 for error */
+static int mkdir_recursive(char *dir) {
+ char *p = dir;
+
+ if (!dir || !dir[0])
+ return 0;
+
+ while ((p = strchr(p + 1, '/')) != NULL) {
+
+ *p = '\0';
+ if ((mkdir(dir, 0700) != 0) && (errno != EEXIST)) {
+ *p = '/';
+ return -1;
+ }
+
+ *p++ = '/';
+ if (!*p) return 0; /* Ignore trailing slash */
+ }
+
+ return (mkdir(dir, 0700) != 0) && (errno != EEXIST) ? -1 : 0;
+}
+
+/* 0 on success, -1 for error */
+static int mkdir_for_file(char *filename) {
+ char *p = filename;
+
+ if (!filename || !filename[0])
+ return -1;
+
+ while ((p = strchr(p + 1, '/')) != NULL) {
+
+ *p = '\0';
+ if ((mkdir(filename, 0700) != 0) && (errno != EEXIST)) {
+ *p = '/';
+ return -1;
+ }
+
+ *p++ = '/';
+ if (!*p) return -1; /* Unexpected trailing slash in filename */
+ }
+
+ return 0;
+}
+
+SETDEFAULTS_FUNC(mod_compress_setdefaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "compress.allowed-encodings", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "compress.max-loadavg", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+ array *encodings_arr = array_init();
+
+ s = calloc(1, sizeof(plugin_config));
+ s->compress_cache_dir = buffer_init();
+ s->compress = array_init();
+ s->compress_max_filesize = 0;
+ s->allowed_encodings = 0;
+ s->max_loadavg = 0.0;
+
+ cv[0].destination = s->compress_cache_dir;
+ cv[1].destination = s->compress;
+ cv[2].destination = &(s->compress_max_filesize);
+ cv[3].destination = encodings_arr; /* temp array for allowed encodings list */
+ cv[4].destination = srv->tmp_buf;
+ buffer_clear(srv->tmp_buf);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(srv->tmp_buf)) {
+ s->max_loadavg = strtod(srv->tmp_buf->ptr, NULL);
+ }
+
+ if (!array_is_vlist(s->compress)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for compress.filetype; expected list of \"mimetype\"");
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(encodings_arr)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for compress.allowed-encodings; expected list of \"encoding\"");
+ return HANDLER_ERROR;
+ }
+
+ if (encodings_arr->used) {
+ size_t j = 0;
+ for (j = 0; j < encodings_arr->used; j++) {
+#if defined(USE_ZLIB) || defined(USE_BZ2LIB)
+ data_string *ds = (data_string *)encodings_arr->data[j];
+#endif
+#ifdef USE_ZLIB
+ if (NULL != strstr(ds->value->ptr, "gzip"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value->ptr, "x-gzip"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value->ptr, "deflate"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ /*
+ if (NULL != strstr(ds->value->ptr, "compress"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
+ */
+#endif
+#ifdef USE_BZ2LIB
+ if (NULL != strstr(ds->value->ptr, "bzip2"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ if (NULL != strstr(ds->value->ptr, "x-bzip2"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+#endif
+ }
+ } else {
+ /* default encodings */
+ s->allowed_encodings = 0
+#ifdef USE_ZLIB
+ | HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP | HTTP_ACCEPT_ENCODING_DEFLATE
+#endif
+#ifdef USE_BZ2LIB
+ | HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2
+#endif
+ ;
+ }
+
+ array_free(encodings_arr);
+
+ if (!buffer_string_is_empty(s->compress_cache_dir)) {
+ struct stat st;
+ mkdir_recursive(s->compress_cache_dir->ptr);
+
+ if (0 != stat(s->compress_cache_dir->ptr, &st)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
+ s->compress_cache_dir, strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+
+}
+
+#ifdef USE_ZLIB
+static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data *p, char *start, off_t st_size, time_t mtime) {
+ unsigned char *c;
+ unsigned long crc;
+ z_stream z;
+ size_t outlen;
+
+ UNUSED(srv);
+ UNUSED(con);
+
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ z.opaque = Z_NULL;
+
+ if (Z_OK != deflateInit2(&z,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ -MAX_WBITS, /* supress zlib-header */
+ 8,
+ Z_DEFAULT_STRATEGY)) {
+ return -1;
+ }
+
+ z.next_in = (unsigned char *)start;
+ z.avail_in = st_size;
+ z.total_in = 0;
+
+
+ buffer_string_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
+
+ /* write gzip header */
+
+ c = (unsigned char *)p->b->ptr;
+ c[0] = 0x1f;
+ c[1] = 0x8b;
+ c[2] = Z_DEFLATED;
+ c[3] = 0; /* options */
+ c[4] = (mtime >> 0) & 0xff;
+ c[5] = (mtime >> 8) & 0xff;
+ c[6] = (mtime >> 16) & 0xff;
+ c[7] = (mtime >> 24) & 0xff;
+ c[8] = 0x00; /* extra flags */
+ c[9] = 0x03; /* UNIX */
+
+ outlen = 10;
+ z.next_out = (unsigned char *)p->b->ptr + outlen;
+ z.avail_out = p->b->size - outlen - 9;
+ z.total_out = 0;
+
+ if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
+ deflateEnd(&z);
+ return -1;
+ }
+
+ /* trailer */
+ outlen += z.total_out;
+
+ crc = generate_crc32c(start, st_size);
+
+ c = (unsigned char *)p->b->ptr + outlen;
+
+ c[0] = (crc >> 0) & 0xff;
+ c[1] = (crc >> 8) & 0xff;
+ c[2] = (crc >> 16) & 0xff;
+ c[3] = (crc >> 24) & 0xff;
+ c[4] = (z.total_in >> 0) & 0xff;
+ c[5] = (z.total_in >> 8) & 0xff;
+ c[6] = (z.total_in >> 16) & 0xff;
+ c[7] = (z.total_in >> 24) & 0xff;
+ outlen += 8;
+ buffer_commit(p->b, outlen);
+
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
+ z_stream z;
+
+ UNUSED(srv);
+ UNUSED(con);
+
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ z.opaque = Z_NULL;
+
+ if (Z_OK != deflateInit2(&z,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ -MAX_WBITS, /* supress zlib-header */
+ 8,
+ Z_DEFAULT_STRATEGY)) {
+ return -1;
+ }
+
+ z.next_in = start;
+ z.avail_in = st_size;
+ z.total_in = 0;
+
+ buffer_string_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
+
+ z.next_out = (unsigned char *)p->b->ptr;
+ z.avail_out = p->b->size - 1;
+ z.total_out = 0;
+
+ if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
+ deflateEnd(&z);
+ return -1;
+ }
+
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+ }
+
+ /* trailer */
+ buffer_commit(p->b, z.total_out);
+
+ return 0;
+}
+
+#endif
+
+#ifdef USE_BZ2LIB
+static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
+ bz_stream bz;
+
+ UNUSED(srv);
+ UNUSED(con);
+
+ bz.bzalloc = NULL;
+ bz.bzfree = NULL;
+ bz.opaque = NULL;
+
+ if (BZ_OK != BZ2_bzCompressInit(&bz,
+ 9, /* blocksize = 900k */
+ 0, /* no output */
+ 0)) { /* workFactor: default */
+ return -1;
+ }
+
+ bz.next_in = (char *)start;
+ bz.avail_in = st_size;
+ bz.total_in_lo32 = 0;
+ bz.total_in_hi32 = 0;
+
+ buffer_string_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
+
+ bz.next_out = p->b->ptr;
+ bz.avail_out = p->b->size - 1;
+ bz.total_out_lo32 = 0;
+ bz.total_out_hi32 = 0;
+
+ if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
+ BZ2_bzCompressEnd(&bz);
+ return -1;
+ }
+
+ if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
+ return -1;
+ }
+
+ /* file is too large for now */
+ if (bz.total_out_hi32) return -1;
+
+ /* trailer */
+ buffer_commit(p->b, bz.total_out_lo32);
+
+ return 0;
+}
+#endif
+
+static void mod_compress_note_ratio(server *srv, connection *con, off_t in, off_t out) {
+ /* store compression ratio in environment
+ * for possible logging by mod_accesslog
+ * (late in response handling, so not seen by most other modules) */
+ /*(should be called only at end of successful response compression)*/
+ char ratio[LI_ITOSTRING_LENGTH];
+ if (0 == in) return;
+ li_itostrn(ratio, sizeof(ratio), out * 100 / in);
+ http_header_env_set(con, CONST_STR_LEN("ratio"), ratio, strlen(ratio));
+ UNUSED(srv);
+}
+
+static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, buffer *fn, stat_cache_entry *sce, int type) {
+ int ifd, ofd;
+ int ret;
+#ifdef USE_MMAP
+ volatile int mapped = 0;/* quiet warning: might be clobbered by 'longjmp' */
+#endif
+ void *start;
+ const char *filename = fn->ptr;
+ stat_cache_entry *sce_ofn;
+ ssize_t r;
+
+ /* overflow */
+ if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
+
+ /* don't mmap files > 128Mb
+ *
+ * we could use a sliding window, but currently there is no need for it
+ */
+
+ if (sce->st.st_size > 128 * 1024 * 1024) return -1;
+
+ buffer_reset(p->ofn);
+ buffer_copy_buffer(p->ofn, p->conf.compress_cache_dir);
+ buffer_append_slash(p->ofn);
+
+ if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, buffer_string_length(con->physical.doc_root))) {
+ buffer_append_string(p->ofn, con->physical.path->ptr + buffer_string_length(con->physical.doc_root));
+ } else {
+ buffer_append_string_buffer(p->ofn, con->uri.path);
+ }
+
+ switch(type) {
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_X_GZIP:
+ buffer_append_string_len(p->ofn, CONST_STR_LEN("-gzip-"));
+ break;
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ buffer_append_string_len(p->ofn, CONST_STR_LEN("-deflate-"));
+ break;
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_X_BZIP2:
+ buffer_append_string_len(p->ofn, CONST_STR_LEN("-bzip2-"));
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
+ return -1;
+ }
+
+ buffer_append_string_buffer(p->ofn, sce->etag);
+
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &sce_ofn)) {
+ if (0 == sce->st.st_size) return -1; /* cache file being created */
+ /* cache-entry exists */
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
+#endif
+ mod_compress_note_ratio(srv, con, sce->st.st_size, sce_ofn->st.st_size);
+ buffer_copy_buffer(con->physical.path, p->ofn);
+ return 0;
+ }
+
+ if (0.0 < p->conf.max_loadavg && p->conf.max_loadavg < srv->srvconf.loadavg[0]) {
+ return -1;
+ }
+
+ if (-1 == mkdir_for_file(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "couldn't create directory for file", p->ofn);
+ return -1;
+ }
+
+ if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
+ if (errno == EEXIST) {
+ return -1; /* cache file being created */
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
+
+ return -1;
+ }
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
+#endif
+ if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
+
+ close(ofd);
+
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
+ return -1;
+ }
+
+#ifdef USE_MMAP
+ if (MAP_FAILED != (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))
+ || (errno == EINVAL && MAP_FAILED != (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_PRIVATE, ifd, 0)))) {
+ mapped = 1;
+ signal(SIGBUS, sigbus_handler);
+ sigbus_jmp_valid = 1;
+ if (0 != sigsetjmp(sigbus_jmp, 1)) {
+ sigbus_jmp_valid = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:",
+ fn, ifd);
+
+ munmap(start, sce->st.st_size);
+ close(ofd);
+ close(ifd);
+
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
+ return -1;
+ }
+ } else
+#endif /* FIXME: might attempt to read very large file completely into memory; see compress.max-filesize config option */
+ if (NULL == (start = malloc(sce->st.st_size)) || sce->st.st_size != read(ifd, start, sce->st.st_size)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "reading", fn, "failed", strerror(errno));
+
+ close(ofd);
+ close(ifd);
+ free(start);
+
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
+ return -1;
+ }
+
+ ret = -1;
+ switch(type) {
+#ifdef USE_ZLIB
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_X_GZIP:
+ ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
+ break;
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
+ break;
+#endif
+#ifdef USE_BZ2LIB
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_X_BZIP2:
+ ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
+ break;
+#endif
+ }
+
+ if (ret == 0) {
+ r = write(ofd, CONST_BUF_LEN(p->b));
+ if (-1 == r) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "writing cachefile", p->ofn, "failed:", strerror(errno));
+ ret = -1;
+ } else if ((size_t)r != buffer_string_length(p->b)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "writing cachefile", p->ofn, "failed: not enough bytes written");
+ ret = -1;
+ }
+ }
+
+#ifdef USE_MMAP
+ if (mapped) {
+ sigbus_jmp_valid = 0;
+ munmap(start, sce->st.st_size);
+ } else
+#endif
+ free(start);
+
+ close(ifd);
+
+ if (0 != close(ofd) || ret != 0) {
+ if (0 == ret) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "writing cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
+ return -1;
+ }
+
+ buffer_copy_buffer(con->physical.path, p->ofn);
+ mod_compress_note_ratio(srv, con, sce->st.st_size,
+ (off_t)buffer_string_length(p->b));
+
+ return 0;
+}
+
+static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, buffer *fn, stat_cache_entry *sce, int type) {
+ int ifd;
+ int ret = -1;
+#ifdef USE_MMAP
+ volatile int mapped = 0;/* quiet warning: might be clobbered by 'longjmp' */
+#endif
+ void *start;
+
+ /* overflow */
+ if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
+
+ /* don't mmap files > 128M
+ *
+ * we could use a sliding window, but currently there is no need for it
+ */
+
+ if (sce->st.st_size > 128 * 1024 * 1024) return -1;
+
+ if (0.0 < p->conf.max_loadavg && p->conf.max_loadavg < srv->srvconf.loadavg[0]) {
+ return -1;
+ }
+
+ if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
+
+ return -1;
+ }
+
+#ifdef USE_MMAP
+ if (MAP_FAILED != (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))
+ || (errno == EINVAL && MAP_FAILED != (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_PRIVATE, ifd, 0)))) {
+ mapped = 1;
+ signal(SIGBUS, sigbus_handler);
+ sigbus_jmp_valid = 1;
+ if (0 != sigsetjmp(sigbus_jmp, 1)) {
+ sigbus_jmp_valid = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:",
+ fn, ifd);
+
+ munmap(start, sce->st.st_size);
+ close(ifd);
+ return -1;
+ }
+ } else
+#endif /* FIXME: might attempt to read very large file completely into memory; see compress.max-filesize config option */
+ if (NULL == (start = malloc(sce->st.st_size)) || sce->st.st_size != read(ifd, start, sce->st.st_size)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "reading", fn, "failed", strerror(errno));
+
+ close(ifd);
+ free(start);
+ return -1;
+ }
+
+ switch(type) {
+#ifdef USE_ZLIB
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_X_GZIP:
+ ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
+ break;
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
+ break;
+#endif
+#ifdef USE_BZ2LIB
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_X_BZIP2:
+ ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
+ break;
+#endif
+ default:
+ ret = -1;
+ break;
+ }
+
+#ifdef USE_MMAP
+ if (mapped) {
+ sigbus_jmp_valid = 0;
+ munmap(start, sce->st.st_size);
+ } else
+#endif
+ free(start);
+
+ close(ifd);
+
+ if (ret != 0) return -1;
+
+ mod_compress_note_ratio(srv, con, sce->st.st_size,
+ (off_t)buffer_string_length(p->b));
+ chunkqueue_reset(con->write_queue);
+ chunkqueue_append_buffer(con->write_queue, p->b);
+
+ buffer_reset(con->physical.path);
+
+ con->file_finished = 1;
+ con->file_started = 1;
+
+ return 0;
+}
+
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(compress_cache_dir);
+ PATCH(compress);
+ PATCH(compress_max_filesize);
+ PATCH(allowed_encodings);
+ PATCH(max_loadavg);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
+ PATCH(compress_cache_dir);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
+ PATCH(compress);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
+ PATCH(compress_max_filesize);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.allowed-encodings"))) {
+ PATCH(allowed_encodings);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-loadavg"))) {
+ PATCH(max_loadavg);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_compress_contains_encoding(const char *headervalue, const char *encoding, size_t len) {
+ const char *m = headervalue;
+ do {
+ while (*m == ',' || *m == ' ' || *m == '\t') {
+ ++m;
+ }
+ if (0 == strncasecmp(m, encoding, len)) {
+ /*(not a full HTTP field parse: not parsing for q-values and not handling q=0)*/
+ m += len;
+ if (*m == '\0' || *m == ',' || *m == ';' || *m == ' ' || *m == '\t')
+ return 1;
+ } else if (*m != '\0') {
+ ++m;
+ }
+ } while ((m = strchr(m, ',')));
+ return 0;
+}
+
+PHYSICALPATH_FUNC(mod_compress_physical) {
+ plugin_data *p = p_d;
+ size_t m;
+ off_t max_fsize;
+ stat_cache_entry *sce = NULL;
+ buffer *mtime = NULL;
+ buffer *content_type;
+
+ if (con->mode != DIRECT || con->http_status) return HANDLER_GO_ON;
+
+ /* only GET and POST can get compressed */
+ if (con->request.http_method != HTTP_METHOD_GET &&
+ con->request.http_method != HTTP_METHOD_POST) {
+ return HANDLER_GO_ON;
+ }
+
+ if (buffer_string_is_empty(con->physical.path)) {
+ return HANDLER_GO_ON;
+ }
+
+ mod_compress_patch_connection(srv, con, p);
+
+ max_fsize = p->conf.compress_max_filesize;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ con->http_status = 403;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "not a regular file:", con->uri.path,
+ "->", con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we only handle regular files */
+#ifdef HAVE_LSTAT
+ if ((sce->is_symlink == 1) && !con->conf.follow_symlink) {
+ return HANDLER_GO_ON;
+ }
+#endif
+ if (!S_ISREG(sce->st.st_mode)) {
+ return HANDLER_GO_ON;
+ }
+
+ /* don't compress files that are too large as we need to much time to handle them */
+ if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
+
+ /* don't try to compress files less than 128 bytes
+ *
+ * - extra overhead for compression
+ * - mmap() fails for st_size = 0 :)
+ */
+ if (sce->st.st_size < 128) return HANDLER_GO_ON;
+
+ stat_cache_etag_get(sce, con->etag_flags);
+
+ /* check if mimetype is in compress-config */
+ content_type = NULL;
+ stat_cache_content_type_get(srv, con, con->physical.path, sce);
+ if (!buffer_is_empty(sce->content_type)) {
+ char *c;
+ if ( (c = strchr(sce->content_type->ptr, ';')) != NULL) {
+ content_type = srv->tmp_buf;
+ buffer_copy_string_len(content_type, sce->content_type->ptr, c - sce->content_type->ptr);
+ }
+ }
+ else {
+ content_type = srv->tmp_buf;
+ buffer_copy_string_len(content_type, CONST_STR_LEN(""));
+ }
+
+ for (m = 0; m < p->conf.compress->used; m++) {
+ data_string *compress_ds = (data_string *)p->conf.compress->data[m];
+
+ if (buffer_is_equal(compress_ds->value, sce->content_type)
+ || (content_type && buffer_is_equal(compress_ds->value, content_type))) {
+ /* mimetype found */
+ buffer *vb;
+
+ /* the response might change according to Accept-Encoding */
+ http_header_response_append(con, HTTP_HEADER_VARY, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
+
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_ACCEPT_ENCODING, CONST_STR_LEN("Accept-Encoding")))) {
+ int accept_encoding = 0;
+ char *value = vb->ptr;
+ int matched_encodings = 0;
+ int use_etag = sce->etag != NULL && sce->etag->ptr != NULL;
+
+ /* get client side support encodings */
+#ifdef USE_ZLIB
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("gzip"))) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("x-gzip"))) accept_encoding |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("deflate"))) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("compress"))) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
+#endif
+#ifdef USE_BZ2LIB
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("bzip2"))) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("x-bzip2"))) accept_encoding |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+#endif
+ if (mod_compress_contains_encoding(value, CONST_STR_LEN("identity"))) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
+
+ /* find matching entries */
+ matched_encodings = accept_encoding & p->conf.allowed_encodings;
+
+ if (matched_encodings) {
+ static const char dflt_gzip[] = "gzip";
+ static const char dflt_x_gzip[] = "x-gzip";
+ static const char dflt_deflate[] = "deflate";
+ static const char dflt_bzip2[] = "bzip2";
+ static const char dflt_x_bzip2[] = "x-bzip2";
+
+ const char *compression_name = NULL;
+ int compression_type = 0;
+
+ mtime = strftime_cache_get(srv, sce->st.st_mtime);
+
+ /* try matching original etag of uncompressed version */
+ if (use_etag) {
+ etag_mutate(con->physical.etag, sce->etag);
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ return HANDLER_FINISHED;
+ }
+ }
+
+ /* select best matching encoding */
+ if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
+ compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
+ compression_name = dflt_bzip2;
+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_X_BZIP2) {
+ compression_type = HTTP_ACCEPT_ENCODING_X_BZIP2;
+ compression_name = dflt_x_bzip2;
+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_GZIP) {
+ compression_type = HTTP_ACCEPT_ENCODING_GZIP;
+ compression_name = dflt_gzip;
+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_X_GZIP) {
+ compression_type = HTTP_ACCEPT_ENCODING_X_GZIP;
+ compression_name = dflt_x_gzip;
+ } else {
+ force_assert(matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE);
+ compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
+ compression_name = dflt_deflate;
+ }
+
+ if (use_etag) {
+ /* try matching etag of compressed version */
+ buffer_copy_buffer(srv->tmp_buf, sce->etag);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("-"));
+ buffer_append_string(srv->tmp_buf, compression_name);
+ etag_mutate(con->physical.etag, srv->tmp_buf);
+ }
+
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ if (use_etag) {
+ http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ }
+ return HANDLER_FINISHED;
+ }
+
+ /* deflate it */
+ if (use_etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) {
+ if (0 != deflate_file_to_file(srv, con, p, con->physical.path, sce, compression_type))
+ return HANDLER_GO_ON;
+ } else {
+ if (0 != deflate_file_to_buffer(srv, con, p, con->physical.path, sce, compression_type))
+ return HANDLER_GO_ON;
+ }
+ http_header_response_set(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
+ http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ if (use_etag) {
+ http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ }
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ /* let mod_staticfile handle the cached compressed files, physical path was modified */
+ return (use_etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) ? HANDLER_GO_ON : HANDLER_FINISHED;
+ }
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+int mod_compress_plugin_init(plugin *p);
+int mod_compress_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("compress");
+
+ p->init = mod_compress_init;
+ p->set_defaults = mod_compress_setdefaults;
+ p->handle_subrequest_start = mod_compress_physical;
+ p->cleanup = mod_compress_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_deflate.c b/data/lighttpd/lighttpd-1.4.53/src/mod_deflate.c
new file mode 100644
index 000000000..d7a7ea95d
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_deflate.c
@@ -0,0 +1,1243 @@
+/* mod_deflate
+ *
+ *
+ * bug fix on Robert Jakabosky from alphatrade.com's lighttp 1.4.10 mod_deflate patch
+ *
+ * Bug fix and new features:
+ * 1) fix loop bug when content-length is bigger than work-block-size*k
+ *
+ * -------
+ *
+ * lighttpd-1.4.26.mod_deflate.patch from
+ * https://redmine.lighttpd.net/projects/1/wiki/Docs_ModDeflate
+ *
+ * -------
+ *
+ * Patch further modified in this incarnation.
+ *
+ * Note: this patch only handles completed responses (con->file_finished);
+ * this patch does not currently handle streaming dynamic responses,
+ * and therefore also does not worry about Transfer-Encoding: chunked
+ * (or having separate con->output_queue for chunked-encoded output)
+ * (or using separate buffers per connection instead of p->tmp_buf)
+ * (or handling interactions with block buffering and write timeouts)
+ *
+ * Bug fix:
+ * - fixed major bug with compressing chunks with offset > 0
+ * x-ref:
+ * "Response breaking in mod_deflate"
+ * https://redmine.lighttpd.net/issues/986
+ * - fix broken (in some cases) chunk accounting in deflate_compress_response()
+ * - fix broken bzip2
+ * x-ref:
+ * "mod_deflate's bzip2 broken by default"
+ * https://redmine.lighttpd.net/issues/2035
+ * - fix mismatch with current chunk interfaces
+ * x-ref:
+ * "Weird things in chunk.c (functions only handling specific cases, unexpected behaviour)"
+ * https://redmine.lighttpd.net/issues/1510
+ *
+ * Behavior changes from prior patch:
+ * - deflate.mimetypes must now be configured to enable compression
+ * deflate.mimetypes = ( ) # compress nothing (disabled; default)
+ * deflate.mimetypes = ( "" ) # compress all mimetypes
+ * deflate.mimetypes = ( "text/" ) # compress text/... mimetypes
+ * x-ref:
+ * "mod_deflate enabled by default"
+ * https://redmine.lighttpd.net/issues/1394
+ * - deflate.enabled directive removed (see new behavior of deflate.mimetypes)
+ * - deflate.debug removed (was developer debug trace, not end-user debug)
+ * - deflate.bzip2 replaced with deflate.allowed-encodings (like mod_compress)
+ * x-ref:
+ * "mod_deflate should allow limiting of compression algorithm from the configuration file"
+ * https://redmine.lighttpd.net/issues/996
+ * "mod_compress disabling methods"
+ * https://redmine.lighttpd.net/issues/1773
+ * - deflate.nocompress-url removed since disabling compression for a URL
+ * can now easily be done by setting to a blank list either directive
+ * deflate.accept_encodings = () or deflate.mimetypes = () in a conditional
+ * block, e.g. $HTTP["url"] =~ "....." { deflate.mimetypes = ( ) }
+ * - deflate.sync-flush removed; controlled by con->conf.stream_response_body
+ * (though streaming compression not currently implemented in mod_deflate)
+ * - inactive directives in this patch (since con->file_finished required)
+ * deflate.work-block-size
+ * deflate.output-buffer-size
+ * - remove weak file size check; SIGBUS is trapped, file that shrink will error
+ * x-ref:
+ * "mod_deflate: filesize check is too weak"
+ * https://redmine.lighttpd.net/issues/1512
+ * - change default deflate.min-compress-size from 0 to now be 256
+ * http://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits
+ * Apache 2.4 mod_deflate minimum is 68 bytes
+ * Akamai recommends minimum 860 bytes
+ * Google recommends minimum be somewhere in range between 150 and 1024 bytes
+ * - deflate.max-compress-size new directive (in kb like compress.max_filesize)
+ * - deflate.mem-level removed (too many knobs for little benefit)
+ * - deflate.window-size removed (too many knobs for little benefit)
+ *
+ * Future:
+ * - config directives may be changed, renamed, or removed
+ * e.g. A set of reasonable defaults might be chosen
+ * instead of making them configurable.
+ * deflate.min-compress-size
+ * - might add deflate.mimetypes-exclude = ( ... ) for list of mimetypes
+ * to avoid compressing, even if a broader deflate.mimetypes matched,
+ * e.g. to compress all "text/" except "text/special".
+ * - mod_compress and mod_deflate might merge overlapping feature sets
+ * (mod_compress.cache-dir does not yet have an equivalent in mod_deflate)
+ *
+ * Implementation notes:
+ * - http_chunk_append_mem() used instead of http_chunk_append_buffer()
+ * so that p->tmp_buf can be large and re-used. This results in an extra copy
+ * of compressed data before data is sent to network, though if the compressed
+ * size is larger than 64k, it ends up being sent to a temporary file on
+ * disk without suffering an extra copy in memory, and without extra chunk
+ * create and destroy. If this is ever changed to give away buffers, then use
+ * a unique hctx->output buffer per hctx; do not reuse p->tmp_buf across
+ * multiple requests being handled in parallel.
+ */
+#include "first.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sys-mmap.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h> /* read() */
+
+#include "base.h"
+#include "fdevent.h"
+#include "log.h"
+#include "buffer.h"
+#include "etag.h"
+#include "http_chunk.h"
+#include "http_header.h"
+#include "response.h"
+
+#include "plugin.h"
+
+#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
+# define USE_ZLIB
+# include <zlib.h>
+#endif
+#ifndef Z_DEFAULT_COMPRESSION
+#define Z_DEFAULT_COMPRESSION -1
+#endif
+#ifndef MAX_WBITS
+#define MAX_WBITS 15
+#endif
+
+#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
+# define USE_BZ2LIB
+/* we don't need stdio interface */
+# define BZ_NO_STDIO
+# include <bzlib.h>
+#endif
+
+#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP && defined ENABLE_MMAP
+#define USE_MMAP
+
+#include "sys-mmap.h"
+#include <setjmp.h>
+#include <signal.h>
+
+static volatile int sigbus_jmp_valid;
+static sigjmp_buf sigbus_jmp;
+
+static void sigbus_handler(int sig) {
+ UNUSED(sig);
+ if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
+ log_failed_assert(__FILE__, __LINE__, "SIGBUS");
+}
+#endif
+
+/* request: accept-encoding */
+#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
+#define HTTP_ACCEPT_ENCODING_GZIP BV(1)
+#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2)
+#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3)
+#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4)
+#define HTTP_ACCEPT_ENCODING_X_GZIP BV(5)
+#define HTTP_ACCEPT_ENCODING_X_BZIP2 BV(6)
+
+#define KByte * 1024
+#define MByte * 1024 KByte
+#define GByte * 1024 MByte
+
+typedef struct {
+ array *mimetypes;
+ int allowed_encodings;
+ unsigned int max_compress_size;
+ unsigned short min_compress_size;
+ unsigned short output_buffer_size;
+ unsigned short work_block_size;
+ unsigned short sync_flush;
+ short compression_level;
+ double max_loadavg;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ buffer *tmp_buf;
+ array *encodings;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+typedef struct {
+ union {
+ #ifdef USE_ZLIB
+ z_stream z;
+ #endif
+ #ifdef USE_BZ2LIB
+ bz_stream bz;
+ #endif
+ int dummy;
+ } u;
+ off_t bytes_in;
+ off_t bytes_out;
+ chunkqueue *in_queue;
+ buffer *output;
+ plugin_data *plugin_data;
+ int compression_type;
+} handler_ctx;
+
+static handler_ctx *handler_ctx_init() {
+ handler_ctx *hctx;
+
+ hctx = calloc(1, sizeof(*hctx));
+ hctx->in_queue = chunkqueue_init();
+
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ #if 0
+ if (hctx->output != p->tmp_buf) {
+ buffer_free(hctx->output);
+ }
+ #endif
+ chunkqueue_free(hctx->in_queue);
+ free(hctx);
+}
+
+INIT_FUNC(mod_deflate_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->encodings = array_init();
+ p->tmp_buf = buffer_init();
+ buffer_string_prepare_copy(p->tmp_buf, 64 KByte);
+
+ return p;
+}
+
+FREE_FUNC(mod_deflate_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->mimetypes);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+ array_free(p->encodings);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "deflate.mimetypes", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.allowed-encodings", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.max-compress-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.min-compress-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.compression-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.output-buffer-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.work-block-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "deflate.max-loadavg", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->mimetypes = array_init();
+ s->allowed_encodings = 0;
+ s->max_compress_size = 128*1024; /*(128 MB measured as num KB)*/
+ s->min_compress_size = 256;
+ s->output_buffer_size = 0;
+ s->work_block_size = 2048;
+ s->sync_flush = 0;
+ s->compression_level = -1;
+ s->max_loadavg = 0.0;
+
+ array_reset_data_strings(p->encodings); /* temp array for allowed encodings list */
+
+ cv[0].destination = s->mimetypes;
+ cv[1].destination = p->encodings;
+ cv[2].destination = &(s->max_compress_size);
+ cv[3].destination = &(s->min_compress_size);
+ cv[4].destination = &(s->compression_level);
+ cv[5].destination = &(s->output_buffer_size);
+ cv[6].destination = &(s->work_block_size);
+ cv[7].destination = p->tmp_buf;
+ buffer_clear(p->tmp_buf);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if ((s->compression_level < 1 || s->compression_level > 9) &&
+ s->compression_level != -1) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "compression-level must be between 1 and 9:", s->compression_level);
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(p->tmp_buf)) {
+ s->max_loadavg = strtod(p->tmp_buf->ptr, NULL);
+ }
+
+ if (!array_is_vlist(s->mimetypes)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for deflate.mimetypes; expected list of \"mimetype\"");
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(p->encodings)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for deflate.allowed-encodings; expected list of \"encoding\"");
+ return HANDLER_ERROR;
+ }
+
+ if (p->encodings->used) {
+ size_t j = 0;
+ for (j = 0; j < p->encodings->used; j++) {
+#if defined(USE_ZLIB) || defined(USE_BZ2LIB)
+ data_string *ds = (data_string *)p->encodings->data[j];
+#endif
+#ifdef USE_ZLIB
+ if (NULL != strstr(ds->value->ptr, "gzip"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value->ptr, "x-gzip"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value->ptr, "deflate"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ /*
+ if (NULL != strstr(ds->value->ptr, "compress"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
+ */
+#endif
+#ifdef USE_BZ2LIB
+ if (NULL != strstr(ds->value->ptr, "bzip2"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ if (NULL != strstr(ds->value->ptr, "x-bzip2"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+#endif
+ }
+ } else {
+ /* default encodings */
+#ifdef USE_ZLIB
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP
+ | HTTP_ACCEPT_ENCODING_X_GZIP
+ | HTTP_ACCEPT_ENCODING_DEFLATE;
+#endif
+#ifdef USE_BZ2LIB
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2
+ | HTTP_ACCEPT_ENCODING_X_BZIP2;
+#endif
+ }
+
+ /* mod_deflate matches mimetype as prefix of Content-Type
+ * so ignore '*' at end of mimetype for end-user flexibility
+ * in specifying trailing wildcard to grouping of mimetypes */
+ for (size_t m = 0; m < s->mimetypes->used; ++m) {
+ buffer *mimetype = ((data_string *)s->mimetypes->data[m])->value;
+ size_t len = buffer_string_length(mimetype);
+ if (len > 2 && mimetype->ptr[len-1] == '*') {
+ buffer_string_set_length(mimetype, len-1);
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+
+}
+
+
+#if defined(USE_ZLIB) || defined(USE_BZ2LIB)
+static int stream_http_chunk_append_mem(server *srv, connection *con, handler_ctx *hctx, size_t len) {
+ /* future: might also write stream to hctx temporary file in compressed file cache */
+ return http_chunk_append_mem(srv, con, hctx->output->ptr, len);
+}
+#endif
+
+
+#ifdef USE_ZLIB
+
+static int stream_deflate_init(handler_ctx *hctx) {
+ z_stream * const z = &hctx->u.z;
+ const plugin_data * const p = hctx->plugin_data;
+ z->zalloc = Z_NULL;
+ z->zfree = Z_NULL;
+ z->opaque = Z_NULL;
+ z->total_in = 0;
+ z->total_out = 0;
+ z->next_out = (unsigned char *)hctx->output->ptr;
+ z->avail_out = hctx->output->size;
+
+ if (Z_OK != deflateInit2(z,
+ p->conf.compression_level > 0
+ ? p->conf.compression_level
+ : Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ (hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP)
+ ? (MAX_WBITS | 16) /*(0x10 flags gzip header, trailer)*/
+ : -MAX_WBITS, /*(negate to suppress zlib header)*/
+ 8, /* default memLevel */
+ Z_DEFAULT_STRATEGY)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int stream_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
+ z_stream * const z = &(hctx->u.z);
+ size_t len;
+
+ z->next_in = start;
+ z->avail_in = st_size;
+ hctx->bytes_in += st_size;
+
+ /* compress data */
+ do {
+ if (Z_OK != deflate(z, Z_NO_FLUSH)) return -1;
+
+ if (z->avail_out == 0 || z->avail_in > 0) {
+ len = hctx->output->size - z->avail_out;
+ hctx->bytes_out += len;
+ stream_http_chunk_append_mem(srv, con, hctx, len);
+ z->next_out = (unsigned char *)hctx->output->ptr;
+ z->avail_out = hctx->output->size;
+ }
+ } while (z->avail_in > 0);
+
+ return 0;
+}
+
+static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
+ z_stream * const z = &(hctx->u.z);
+ const plugin_data *p = hctx->plugin_data;
+ size_t len;
+ int rc = 0;
+ int done;
+
+ /* compress data */
+ do {
+ done = 1;
+ if (end) {
+ rc = deflate(z, Z_FINISH);
+ if (rc == Z_OK) {
+ done = 0;
+ } else if (rc != Z_STREAM_END) {
+ return -1;
+ }
+ } else {
+ if (p->conf.sync_flush) {
+ rc = deflate(z, Z_SYNC_FLUSH);
+ if (rc != Z_OK) return -1;
+ } else if (z->avail_in > 0) {
+ rc = deflate(z, Z_NO_FLUSH);
+ if (rc != Z_OK) return -1;
+ }
+ }
+
+ len = hctx->output->size - z->avail_out;
+ if (z->avail_out == 0 || (len > 0 && (end || p->conf.sync_flush))) {
+ hctx->bytes_out += len;
+ stream_http_chunk_append_mem(srv, con, hctx, len);
+ z->next_out = (unsigned char *)hctx->output->ptr;
+ z->avail_out = hctx->output->size;
+ }
+ } while (z->avail_in != 0 || !done);
+
+ return 0;
+}
+
+static int stream_deflate_end(server *srv, handler_ctx *hctx) {
+ z_stream * const z = &(hctx->u.z);
+ int rc = deflateEnd(z);
+ if (Z_OK == rc || Z_DATA_ERROR == rc) return 0;
+
+ if (z->msg != NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "sdss",
+ "deflateEnd error ret=", rc, ", msg=", z->msg);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "deflateEnd error ret=", rc);
+ }
+ return -1;
+}
+
+#endif
+
+
+#ifdef USE_BZ2LIB
+
+static int stream_bzip2_init(handler_ctx *hctx) {
+ bz_stream * const bz = &hctx->u.bz;
+ const plugin_data * const p = hctx->plugin_data;
+ bz->bzalloc = NULL;
+ bz->bzfree = NULL;
+ bz->opaque = NULL;
+ bz->total_in_lo32 = 0;
+ bz->total_in_hi32 = 0;
+ bz->total_out_lo32 = 0;
+ bz->total_out_hi32 = 0;
+ bz->next_out = hctx->output->ptr;
+ bz->avail_out = hctx->output->size;
+
+ if (BZ_OK != BZ2_bzCompressInit(bz,
+ p->conf.compression_level > 0
+ ? p->conf.compression_level
+ : 9, /* blocksize = 900k */
+ 0, /* verbosity */
+ 0)) { /* workFactor: default */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int stream_bzip2_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
+ bz_stream * const bz = &(hctx->u.bz);
+ size_t len;
+
+ bz->next_in = (char *)start;
+ bz->avail_in = st_size;
+ hctx->bytes_in += st_size;
+
+ /* compress data */
+ do {
+ if (BZ_RUN_OK != BZ2_bzCompress(bz, BZ_RUN)) return -1;
+
+ if (bz->avail_out == 0 || bz->avail_in > 0) {
+ len = hctx->output->size - bz->avail_out;
+ hctx->bytes_out += len;
+ stream_http_chunk_append_mem(srv, con, hctx, len);
+ bz->next_out = hctx->output->ptr;
+ bz->avail_out = hctx->output->size;
+ }
+ } while (bz->avail_in > 0);
+
+ return 0;
+}
+
+static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
+ bz_stream * const bz = &(hctx->u.bz);
+ const plugin_data *p = hctx->plugin_data;
+ size_t len;
+ int rc;
+ int done;
+
+ /* compress data */
+ do {
+ done = 1;
+ if (end) {
+ rc = BZ2_bzCompress(bz, BZ_FINISH);
+ if (rc == BZ_FINISH_OK) {
+ done = 0;
+ } else if (rc != BZ_STREAM_END) {
+ return -1;
+ }
+ } else if (bz->avail_in > 0) {
+ /* p->conf.sync_flush not implemented here,
+ * which would loop on BZ_FLUSH while BZ_FLUSH_OK
+ * until BZ_RUN_OK returned */
+ rc = BZ2_bzCompress(bz, BZ_RUN);
+ if (rc != BZ_RUN_OK) {
+ return -1;
+ }
+ }
+
+ len = hctx->output->size - bz->avail_out;
+ if (bz->avail_out == 0 || (len > 0 && (end || p->conf.sync_flush))) {
+ hctx->bytes_out += len;
+ stream_http_chunk_append_mem(srv, con, hctx, len);
+ bz->next_out = hctx->output->ptr;
+ bz->avail_out = hctx->output->size;
+ }
+ } while (bz->avail_in != 0 || !done);
+
+ return 0;
+}
+
+static int stream_bzip2_end(server *srv, handler_ctx *hctx) {
+ bz_stream * const bz = &(hctx->u.bz);
+ int rc = BZ2_bzCompressEnd(bz);
+ if (BZ_OK == rc || BZ_DATA_ERROR == rc) return 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "BZ2_bzCompressEnd error ret=", rc);
+ return -1;
+}
+
+#endif
+
+
+static int mod_deflate_stream_init(handler_ctx *hctx) {
+ switch(hctx->compression_type) {
+#ifdef USE_ZLIB
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ return stream_deflate_init(hctx);
+#endif
+#ifdef USE_BZ2LIB
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ return stream_bzip2_init(hctx);
+#endif
+ default:
+ return -1;
+ }
+}
+
+static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
+ if (0 == st_size) return 0;
+ switch(hctx->compression_type) {
+#ifdef USE_ZLIB
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ return stream_deflate_compress(srv, con, hctx, start, st_size);
+#endif
+#ifdef USE_BZ2LIB
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ return stream_bzip2_compress(srv, con, hctx, start, st_size);
+#endif
+ default:
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(start);
+ return -1;
+ }
+}
+
+static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
+ if (0 == hctx->bytes_in) return 0;
+ switch(hctx->compression_type) {
+#ifdef USE_ZLIB
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ return stream_deflate_flush(srv, con, hctx, end);
+#endif
+#ifdef USE_BZ2LIB
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ return stream_bzip2_flush(srv, con, hctx, end);
+#endif
+ default:
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(end);
+ return -1;
+ }
+}
+
+static void mod_deflate_note_ratio(server *srv, connection *con, handler_ctx *hctx) {
+ /* store compression ratio in environment
+ * for possible logging by mod_accesslog
+ * (late in response handling, so not seen by most other modules) */
+ /*(should be called only at end of successful response compression)*/
+ char ratio[LI_ITOSTRING_LENGTH];
+ if (0 == hctx->bytes_in) return;
+ li_itostrn(ratio, sizeof(ratio), hctx->bytes_out * 100 / hctx->bytes_in);
+ http_header_env_set(con, CONST_STR_LEN("ratio"), ratio, strlen(ratio));
+ UNUSED(srv);
+}
+
+static int mod_deflate_stream_end(server *srv, handler_ctx *hctx) {
+ switch(hctx->compression_type) {
+#ifdef USE_ZLIB
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
+ return stream_deflate_end(srv, hctx);
+#endif
+#ifdef USE_BZ2LIB
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ return stream_bzip2_end(srv, hctx);
+#endif
+ default:
+ UNUSED(srv);
+ return -1;
+ }
+}
+
+static void deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) {
+ const plugin_data *p = hctx->plugin_data;
+ con->plugin_ctx[p->id] = NULL;
+
+ if (0 != mod_deflate_stream_end(srv, hctx)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "error closing stream");
+ }
+
+ #if 1 /* unnecessary if deflate.min-compress-size is set to a reasonable value */
+ if (hctx->bytes_in < hctx->bytes_out) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsd",
+ "uri ", con->uri.path_raw, " in=", hctx->bytes_in, " smaller than out=", hctx->bytes_out);
+ }
+ #endif
+
+ handler_ctx_free(hctx);
+}
+
+
+static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hctx, chunk *c, off_t st_size) {
+ off_t abs_offset;
+ off_t toSend = -1;
+ char *start;
+#ifdef USE_MMAP
+ off_t we_want_to_mmap = 2 MByte;
+ off_t we_want_to_send = st_size;
+ volatile int mapped = 0;/* quiet warning: might be clobbered by 'longjmp' */
+#else
+ start = NULL;
+#endif
+
+ if (-1 == c->file.fd) { /* open the file if not already open */
+ if (-1 == (c->file.fd = fdevent_open_cloexec(c->mem->ptr, O_RDONLY, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->mem, strerror(errno));
+
+ return -1;
+ }
+ }
+
+ abs_offset = c->file.start + c->offset;
+
+#ifdef USE_MMAP
+ /* mmap the buffer
+ * - first mmap
+ * - new mmap as the we are at the end of the last one */
+ if (c->file.mmap.start == MAP_FAILED ||
+ abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
+
+ /* Optimizations for the future:
+ *
+ * adaptive mem-mapping
+ * the problem:
+ * we mmap() the whole file. If someone has alot large files and 32bit
+ * machine the virtual address area will be unrun and we will have a failing
+ * mmap() call.
+ * solution:
+ * only mmap 16M in one chunk and move the window as soon as we have finished
+ * the first 8M
+ *
+ * read-ahead buffering
+ * the problem:
+ * sending out several large files in parallel trashes the read-ahead of the
+ * kernel leading to long wait-for-seek times.
+ * solutions: (increasing complexity)
+ * 1. use madvise
+ * 2. use a internal read-ahead buffer in the chunk-structure
+ * 3. use non-blocking IO for file-transfers
+ * */
+
+ /* all mmap()ed areas are 512kb expect the last which might be smaller */
+ off_t to_mmap;
+
+ /* this is a remap, move the mmap-offset */
+ if (c->file.mmap.start != MAP_FAILED) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.offset += we_want_to_mmap;
+ } else {
+ /* in case the range-offset is after the first mmap()ed area we skip the area */
+ c->file.mmap.offset = 0;
+
+ while (c->file.mmap.offset + we_want_to_mmap < c->file.start) {
+ c->file.mmap.offset += we_want_to_mmap;
+ }
+ }
+
+ /* length is rel, c->offset too, assume there is no limit at the mmap-boundaries */
+ to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset;
+ if (to_mmap > we_want_to_mmap) to_mmap = we_want_to_mmap;
+ /* we have more to send than we can mmap() at once */
+ if (we_want_to_send > to_mmap) we_want_to_send = to_mmap;
+
+ if (MAP_FAILED == (c->file.mmap.start = mmap(0, (size_t)to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))
+ && (errno != EINVAL || MAP_FAILED == (c->file.mmap.start = mmap(0, (size_t)to_mmap, PROT_READ, MAP_PRIVATE, c->file.fd, c->file.mmap.offset)))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
+ strerror(errno), c->mem, c->file.fd);
+
+ return -1;
+ }
+
+ c->file.mmap.length = to_mmap;
+#ifdef HAVE_MADVISE
+ /* don't advise files < 64Kb */
+ if (c->file.mmap.length > (64 KByte) &&
+ 0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "madvise failed:",
+ strerror(errno), c->mem, c->file.fd);
+ }
+#endif
+
+ /* chunk_reset() or chunk_free() will cleanup for us */
+ }
+
+ /* to_send = abs_mmap_end - abs_offset */
+ toSend = (c->file.mmap.offset + c->file.mmap.length) - abs_offset;
+ if (toSend > we_want_to_send) toSend = we_want_to_send;
+
+ if (toSend < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "soooo",
+ "toSend is negative:",
+ toSend,
+ c->file.mmap.length,
+ abs_offset,
+ c->file.mmap.offset);
+ force_assert(toSend < 0);
+ }
+
+ start = c->file.mmap.start;
+ mapped = 1;
+#endif
+
+ if (MAP_FAILED == c->file.mmap.start) {
+ toSend = st_size;
+ if (toSend > 2 MByte) toSend = 2 MByte;
+ if (NULL == (start = malloc((size_t)toSend)) || -1 == lseek(c->file.fd, abs_offset, SEEK_SET) || toSend != read(c->file.fd, start, (size_t)toSend)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "reading", c->mem, "failed:", strerror(errno));
+
+ free(start);
+ return -1;
+ }
+ abs_offset = 0;
+ }
+
+#ifdef USE_MMAP
+ if (mapped) {
+ signal(SIGBUS, sigbus_handler);
+ sigbus_jmp_valid = 1;
+ if (0 != sigsetjmp(sigbus_jmp, 1)) {
+ sigbus_jmp_valid = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:",
+ c->mem, c->file.fd);
+ return -1;
+ }
+ }
+#endif
+
+ if (mod_deflate_compress(srv, con, hctx,
+ (unsigned char *)start + (abs_offset - c->file.mmap.offset), toSend) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "compress failed.");
+ toSend = -1;
+ }
+
+#ifdef USE_MMAP
+ if (mapped)
+ sigbus_jmp_valid = 0;
+ else
+#endif
+ free(start);
+
+ return toSend;
+}
+
+
+static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx) {
+ off_t len, max;
+ int close_stream;
+
+ /* move all chunk from write_queue into our in_queue, then adjust
+ * counters since con->write_queue is reused for compressed output */
+ len = chunkqueue_length(con->write_queue);
+ chunkqueue_remove_finished_chunks(con->write_queue);
+ chunkqueue_append_chunkqueue(hctx->in_queue, con->write_queue);
+ con->write_queue->bytes_in -= len;
+ con->write_queue->bytes_out -= len;
+
+ max = chunkqueue_length(hctx->in_queue);
+ #if 0
+ /* calculate max bytes to compress for this call */
+ if (p->conf.sync_flush && max > (len = p->conf.work_block_size << 10)) {
+ max = len;
+ }
+ #endif
+
+ /* Compress chunks from in_queue into chunks for write_queue */
+ while (max) {
+ chunk *c = hctx->in_queue->first;
+
+ switch(c->type) {
+ case MEM_CHUNK:
+ len = buffer_string_length(c->mem) - c->offset;
+ if (len > max) len = max;
+ if (mod_deflate_compress(srv, con, hctx, (unsigned char *)c->mem->ptr+c->offset, len) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "compress failed.");
+ return HANDLER_ERROR;
+ }
+ break;
+ case FILE_CHUNK:
+ len = c->file.length - c->offset;
+ if (len > max) len = max;
+ if ((len = mod_deflate_file_chunk(srv, con, hctx, c, len)) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "compress file chunk failed.");
+ return HANDLER_ERROR;
+ }
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
+ return HANDLER_ERROR;
+ }
+
+ max -= len;
+ chunkqueue_mark_written(hctx->in_queue, len);
+ }
+
+ /*(currently should always be true)*/
+ /*(current implementation requires response be complete)*/
+ close_stream = (con->file_finished && chunkqueue_is_empty(hctx->in_queue));
+ if (mod_deflate_stream_flush(srv, con, hctx, close_stream) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "flush error");
+ return HANDLER_ERROR;
+ }
+
+ return close_stream ? HANDLER_FINISHED : HANDLER_GO_ON;
+}
+
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_deflate_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(mimetypes);
+ PATCH(allowed_encodings);
+ PATCH(max_compress_size);
+ PATCH(min_compress_size);
+ PATCH(compression_level);
+ PATCH(output_buffer_size);
+ PATCH(work_block_size);
+ PATCH(max_loadavg);
+
+ /* 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("deflate.mimetypes"))) {
+ PATCH(mimetypes);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.allowed-encodings"))) {
+ PATCH(allowed_encodings);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.max-compress-size"))) {
+ PATCH(max_compress_size);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.min-compress-size"))) {
+ PATCH(min_compress_size);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.compression-level"))) {
+ PATCH(compression_level);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.output-buffer-size"))) {
+ PATCH(output_buffer_size);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.work-block-size"))) {
+ PATCH(work_block_size);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("deflate.max-loadavg"))) {
+ PATCH(max_loadavg);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_deflate_choose_encoding (const char *value, plugin_data *p, const char **label) {
+ /* get client side support encodings */
+ int accept_encoding = 0;
+#if !defined(USE_ZLIB) && !defined(USE_BZ2LIB)
+ UNUSED(value);
+#endif
+#ifdef USE_ZLIB
+ if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
+ else if (NULL != strstr(value, "x-gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
+#endif
+ /* if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; */
+#ifdef USE_BZ2LIB
+ if (p->conf.allowed_encodings & (HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2)) {
+ if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
+ else if (NULL != strstr(value, "x-bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+ }
+#endif
+ /* if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY; */
+
+ /* mask to limit to allowed_encodings */
+ accept_encoding &= p->conf.allowed_encodings;
+
+ /* select best matching encoding */
+#ifdef USE_BZ2LIB
+ if (accept_encoding & HTTP_ACCEPT_ENCODING_BZIP2) {
+ *label = "bzip2";
+ return HTTP_ACCEPT_ENCODING_BZIP2;
+ } else if (accept_encoding & HTTP_ACCEPT_ENCODING_X_BZIP2) {
+ *label = "x-bzip2";
+ return HTTP_ACCEPT_ENCODING_BZIP2;
+ } else
+#endif
+ if (accept_encoding & HTTP_ACCEPT_ENCODING_GZIP) {
+ *label = "gzip";
+ return HTTP_ACCEPT_ENCODING_GZIP;
+ } else if (accept_encoding & HTTP_ACCEPT_ENCODING_X_GZIP) {
+ *label = "x-gzip";
+ return HTTP_ACCEPT_ENCODING_GZIP;
+ } else if (accept_encoding & HTTP_ACCEPT_ENCODING_DEFLATE) {
+ *label = "deflate";
+ return HTTP_ACCEPT_ENCODING_DEFLATE;
+ } else {
+ return 0;
+ }
+}
+
+CONNECTION_FUNC(mod_deflate_handle_response_start) {
+ plugin_data *p = p_d;
+ buffer *vb;
+ handler_ctx *hctx;
+ const char *label;
+ off_t len;
+ size_t etaglen = 0;
+ int compression_type;
+ handler_t rc;
+
+ /*(current implementation requires response be complete)*/
+ if (!con->file_finished) return HANDLER_GO_ON;
+ if (con->request.http_method == HTTP_METHOD_HEAD) return HANDLER_GO_ON;
+ if (con->response.htags & HTTP_HEADER_TRANSFER_ENCODING) return HANDLER_GO_ON;
+
+ /* disable compression for some http status types. */
+ switch(con->http_status) {
+ case 100:
+ case 101:
+ case 204:
+ case 205:
+ case 304:
+ /* disable compression as we have no response entity */
+ return HANDLER_GO_ON;
+ default:
+ break;
+ }
+
+ mod_deflate_patch_connection(srv, con, p);
+
+ /* check if deflate configured for any mimetypes */
+ if (!p->conf.mimetypes->used) return HANDLER_GO_ON;
+
+ /* check if size of response is below min-compress-size or exceeds max*/
+ /* (con->file_finished checked at top of routine) */
+ len = chunkqueue_length(con->write_queue);
+ if (len <= (off_t)p->conf.min_compress_size) return HANDLER_GO_ON;
+ if (p->conf.max_compress_size /*(max_compress_size in KB)*/
+ && len > ((off_t)p->conf.max_compress_size << 10)) {
+ return HANDLER_GO_ON;
+ }
+
+ /* Check if response has a Content-Encoding. */
+ vb = http_header_response_get(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"));
+ if (NULL != vb) return HANDLER_GO_ON;
+
+ /* Check Accept-Encoding for supported encoding. */
+ vb = http_header_request_get(con, HTTP_HEADER_ACCEPT_ENCODING, CONST_STR_LEN("Accept-Encoding"));
+ if (NULL == vb) return HANDLER_GO_ON;
+
+ /* find matching encodings */
+ compression_type = mod_deflate_choose_encoding(vb->ptr, p, &label);
+ if (!compression_type) return HANDLER_GO_ON;
+
+ /* Check mimetype in response header "Content-Type" */
+ if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type")))) {
+ if (NULL == array_match_value_prefix(p->conf.mimetypes, vb)) return HANDLER_GO_ON;
+ } else {
+ /* If no Content-Type set, compress only if first p->conf.mimetypes value is "" */
+ data_string *mimetype = (data_string *)p->conf.mimetypes->data[0];
+ if (!buffer_string_is_empty(mimetype->value)) return HANDLER_GO_ON;
+ }
+
+ /* Vary: Accept-Encoding (response might change according to request Accept-Encoding) */
+ if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_VARY, CONST_STR_LEN("Vary")))) {
+ if (NULL == strstr(vb->ptr, "Accept-Encoding")) {
+ buffer_append_string_len(vb, CONST_STR_LEN(",Accept-Encoding"));
+ }
+ } else {
+ http_header_response_append(con, HTTP_HEADER_VARY,
+ CONST_STR_LEN("Vary"),
+ CONST_STR_LEN("Accept-Encoding"));
+ }
+
+ /* check ETag as is done in http_response_handle_cachable()
+ * (slightly imperfect (close enough?) match of ETag "000000" to "000000-gzip") */
+ vb = http_header_response_get(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"));
+ if (NULL != vb && (con->request.htags & HTTP_HEADER_IF_NONE_MATCH)) {
+ buffer *if_none_match = http_header_response_get(con, HTTP_HEADER_IF_NONE_MATCH, CONST_STR_LEN("If-None-Match"));
+ etaglen = buffer_string_length(vb);
+ if (etaglen
+ && con->http_status < 300 /*(want 2xx only)*/
+ && NULL != if_none_match
+ && 0 == strncmp(if_none_match->ptr, vb->ptr, etaglen-1)
+ && if_none_match->ptr[etaglen-1] == '-'
+ && 0 == strncmp(if_none_match->ptr+etaglen, label, strlen(label))) {
+
+ if ( HTTP_METHOD_GET == con->request.http_method
+ || HTTP_METHOD_HEAD == con->request.http_method) {
+ /* modify ETag response header in-place to remove '"' and append '-label"' */
+ vb->ptr[etaglen-1] = '-'; /*(overwrite end '"')*/
+ buffer_append_string(vb, label);
+ buffer_append_string_len(vb, CONST_STR_LEN("\""));
+ /*buffer_copy_buffer(con->physical.etag, vb);*//*(keep in sync?)*/
+ con->http_status = 304;
+ } else {
+ con->http_status = 412;
+ }
+
+ /* response_start hook occurs after error docs have been handled.
+ * For now, send back empty response body.
+ * In the future, might extract the error doc code so that it
+ * might be run again if response_start hooks return with
+ * changed http_status and con->mode = DIRECT */
+ /* clear content length even if 304 since compressed length unknown */
+ http_response_body_clear(con, 0);
+
+ con->file_finished = 1;
+ con->mode = DIRECT;
+ return HANDLER_GO_ON;
+ }
+ }
+
+ if (0.0 < p->conf.max_loadavg && p->conf.max_loadavg < srv->srvconf.loadavg[0]) {
+ return HANDLER_GO_ON;
+ }
+
+ /* update ETag, if ETag response header is set */
+ if (etaglen) {
+ /* modify ETag response header in-place to remove '"' and append '-label"' */
+ vb->ptr[etaglen-1] = '-'; /*(overwrite end '"')*/
+ buffer_append_string(vb, label);
+ buffer_append_string_len(vb, CONST_STR_LEN("\""));
+ /*buffer_copy_buffer(con->physical.etag, vb);*//*(keep in sync?)*/
+ }
+
+ /* set Content-Encoding to show selected compression type */
+ http_header_response_set(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"), label, strlen(label));
+
+ /* clear Content-Length and con->write_queue if HTTP HEAD request
+ * (alternatively, could return original Content-Length with HEAD
+ * request if ETag not modified and Content-Encoding not added) */
+ if (HTTP_METHOD_HEAD == con->request.http_method) {
+ /* ensure that uncompressed Content-Length is not sent in HEAD response */
+ http_response_body_clear(con, 0);
+ return HANDLER_GO_ON;
+ }
+
+ /* future: might use ETag to check if compressed content is in compressed file cache */
+ /*if (etaglen) { ... } *//* return if in file cache after updating con->write_queue */
+
+ /* enable compression */
+ p->conf.sync_flush =
+ (con->conf.stream_response_body && 0 == p->conf.output_buffer_size);
+ hctx = handler_ctx_init();
+ hctx->plugin_data = p;
+ hctx->compression_type = compression_type;
+ /* setup output buffer */
+ buffer_clear(p->tmp_buf);
+ hctx->output = p->tmp_buf;
+ if (0 != mod_deflate_stream_init(hctx)) {
+ /*(should not happen unless ENOMEM)*/
+ handler_ctx_free(hctx);
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "Failed to initialize compression", label);
+ /* restore prior Etag and unset Content-Encoding */
+ if (etaglen) {
+ vb->ptr[etaglen-1] = '"'; /*(overwrite '-')*/
+ buffer_string_set_length(vb, etaglen);
+ }
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"));
+ return HANDLER_GO_ON;
+ }
+
+ if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ }
+ con->plugin_ctx[p->id] = hctx;
+
+ rc = deflate_compress_response(srv, con, hctx);
+ if (HANDLER_GO_ON != rc) {
+ if (HANDLER_FINISHED == rc) {
+ mod_deflate_note_ratio(srv, con, hctx);
+ }
+ deflate_compress_cleanup(srv, con, hctx);
+ if (HANDLER_ERROR == rc) return HANDLER_ERROR;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_deflate_cleanup(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (NULL != hctx) deflate_compress_cleanup(srv, con, hctx);
+
+ return HANDLER_GO_ON;
+}
+
+int mod_deflate_plugin_init(plugin *p);
+int mod_deflate_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("deflate");
+
+ p->init = mod_deflate_init;
+ p->cleanup = mod_deflate_free;
+ p->set_defaults = mod_deflate_setdefaults;
+ p->connection_reset = mod_deflate_cleanup;
+ p->handle_response_start = mod_deflate_handle_response_start;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_dirlisting.c b/data/lighttpd/lighttpd-1.4.53/src/mod_dirlisting.c
new file mode 100644
index 000000000..2f746740f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_dirlisting.c
@@ -0,0 +1,1216 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#ifdef HAVE_PCRE_H
+#include <pcre.h>
+#endif
+
+/**
+ * this is a dirlisting for a lighttpd plugin
+ */
+
+#ifdef HAVE_ATTR_ATTRIBUTES_H
+#include <attr/attributes.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
+/* plugin config for all request/connections */
+
+typedef struct {
+#ifdef HAVE_PCRE_H
+ pcre *regex;
+#endif
+ buffer *string;
+} excludes;
+
+typedef struct {
+ excludes **ptr;
+
+ size_t used;
+ size_t size;
+} excludes_buffer;
+
+typedef struct {
+ unsigned short dir_listing;
+ unsigned short hide_dot_files;
+ unsigned short hide_readme_file;
+ unsigned short encode_readme;
+ unsigned short hide_header_file;
+ unsigned short encode_header;
+ unsigned short auto_layout;
+
+ excludes_buffer *excludes;
+
+ buffer *show_readme;
+ buffer *show_header;
+ buffer *external_css;
+ buffer *external_js;
+ buffer *encoding;
+ buffer *set_footer;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+ buffer *content_charset;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+static excludes_buffer *excludes_buffer_init(void) {
+ excludes_buffer *exb;
+
+ exb = calloc(1, sizeof(*exb));
+
+ return exb;
+}
+
+#ifdef HAVE_PCRE_H
+static int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
+ size_t i;
+ const char *errptr;
+ int erroff;
+
+ if (!string) return -1;
+
+ if (exb->size == 0) {
+ exb->size = 4;
+ exb->used = 0;
+
+ exb->ptr = malloc(exb->size * sizeof(*exb->ptr));
+
+ for(i = 0; i < exb->size ; i++) {
+ exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
+ }
+ } else if (exb->used == exb->size) {
+ exb->size += 4;
+
+ exb->ptr = realloc(exb->ptr, exb->size * sizeof(*exb->ptr));
+
+ for(i = exb->used; i < exb->size; i++) {
+ exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
+ }
+ }
+
+
+ if (NULL == (exb->ptr[exb->used]->regex = pcre_compile(string->ptr, 0,
+ &errptr, &erroff, NULL))) {
+ return -1;
+ }
+
+ exb->ptr[exb->used]->string = buffer_init();
+ buffer_copy_buffer(exb->ptr[exb->used]->string, string);
+
+ exb->used++;
+
+ return 0;
+}
+#endif
+
+static void excludes_buffer_free(excludes_buffer *exb) {
+#ifdef HAVE_PCRE_H
+ size_t i;
+
+ for (i = 0; i < exb->size; i++) {
+ if (exb->ptr[i]->regex) pcre_free(exb->ptr[i]->regex);
+ if (exb->ptr[i]->string) buffer_free(exb->ptr[i]->string);
+ free(exb->ptr[i]);
+ }
+
+ if (exb->ptr) free(exb->ptr);
+#endif
+
+ free(exb);
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_dirlisting_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+ p->content_charset = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_dirlisting_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!s) continue;
+
+ excludes_buffer_free(s->excludes);
+ buffer_free(s->show_readme);
+ buffer_free(s->show_header);
+ buffer_free(s->external_css);
+ buffer_free(s->external_js);
+ buffer_free(s->encoding);
+ buffer_free(s->set_footer);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+ buffer_free(p->content_charset);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+#define CONFIG_EXCLUDE "dir-listing.exclude"
+#define CONFIG_ACTIVATE "dir-listing.activate"
+#define CONFIG_HIDE_DOTFILES "dir-listing.hide-dotfiles"
+#define CONFIG_EXTERNAL_CSS "dir-listing.external-css"
+#define CONFIG_EXTERNAL_JS "dir-listing.external-js"
+#define CONFIG_ENCODING "dir-listing.encoding"
+#define CONFIG_SHOW_README "dir-listing.show-readme"
+#define CONFIG_HIDE_README_FILE "dir-listing.hide-readme-file"
+#define CONFIG_SHOW_HEADER "dir-listing.show-header"
+#define CONFIG_HIDE_HEADER_FILE "dir-listing.hide-header-file"
+#define CONFIG_DIR_LISTING "server.dir-listing"
+#define CONFIG_SET_FOOTER "dir-listing.set-footer"
+#define CONFIG_ENCODE_README "dir-listing.encode-readme"
+#define CONFIG_ENCODE_HEADER "dir-listing.encode-header"
+#define CONFIG_AUTO_LAYOUT "dir-listing.auto-layout"
+
+
+SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { CONFIG_EXCLUDE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { CONFIG_ACTIVATE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { CONFIG_HIDE_DOTFILES, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { CONFIG_EXTERNAL_CSS, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { CONFIG_ENCODING, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { CONFIG_SHOW_README, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { CONFIG_HIDE_README_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { CONFIG_SHOW_HEADER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { CONFIG_HIDE_HEADER_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { CONFIG_DIR_LISTING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { CONFIG_SET_FOOTER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
+ { CONFIG_ENCODE_README, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
+ { CONFIG_ENCODE_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { CONFIG_AUTO_LAYOUT, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+ { CONFIG_EXTERNAL_JS, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
+
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+ data_unset *du_excludes;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->excludes = excludes_buffer_init();
+ s->dir_listing = 0;
+ s->show_readme = buffer_init();
+ s->show_header = buffer_init();
+ s->external_css = buffer_init();
+ s->external_js = buffer_init();
+ s->hide_dot_files = 1;
+ s->hide_readme_file = 0;
+ s->hide_header_file = 0;
+ s->encode_readme = 1;
+ s->encode_header = 1;
+ s->auto_layout = 1;
+
+ s->encoding = buffer_init();
+ s->set_footer = buffer_init();
+
+ cv[0].destination = s->excludes;
+ cv[1].destination = &(s->dir_listing);
+ cv[2].destination = &(s->hide_dot_files);
+ cv[3].destination = s->external_css;
+ cv[4].destination = s->encoding;
+ cv[5].destination = s->show_readme;
+ cv[6].destination = &(s->hide_readme_file);
+ cv[7].destination = s->show_header;
+ cv[8].destination = &(s->hide_header_file);
+ cv[9].destination = &(s->dir_listing); /* old name */
+ cv[10].destination = s->set_footer;
+ cv[11].destination = &(s->encode_readme);
+ cv[12].destination = &(s->encode_header);
+ cv[13].destination = &(s->auto_layout);
+ cv[14].destination = s->external_js;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (NULL != (du_excludes = array_get_element(config->value, CONFIG_EXCLUDE))) {
+ array *excludes_list;
+
+ excludes_list = ((data_array*)du_excludes)->value;
+
+ if (du_excludes->type != TYPE_ARRAY || !array_is_vlist(excludes_list)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected type for " CONFIG_EXCLUDE "; expected list of \"regex\"");
+ return HANDLER_ERROR;
+ }
+
+#ifndef HAVE_PCRE_H
+ if (excludes_list->used > 0) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "pcre support is missing for: ", CONFIG_EXCLUDE, ", please install libpcre and the headers");
+ return HANDLER_ERROR;
+ }
+#else
+ for (size_t j = 0; j < excludes_list->used; ++j) {
+ data_unset *du_exclude = excludes_list->data[j];
+
+ if (du_exclude->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ", CONFIG_EXCLUDE, "[",
+ du_exclude->key, "](string)");
+ return HANDLER_ERROR;
+ }
+
+ if (0 != excludes_buffer_append(s->excludes, ((data_string*)(du_exclude))->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre-compile failed for", ((data_string*)(du_exclude))->value);
+ return HANDLER_ERROR;
+ }
+ }
+#endif
+ }
+
+ if (!buffer_string_is_empty(s->show_readme)) {
+ if (buffer_is_equal_string(s->show_readme, CONST_STR_LEN("enable"))) {
+ buffer_copy_string_len(s->show_readme, CONST_STR_LEN("README.txt"));
+ }
+ else if (buffer_is_equal_string(s->show_readme, CONST_STR_LEN("disable"))) {
+ buffer_clear(s->show_readme);
+ }
+ }
+
+ if (!buffer_string_is_empty(s->show_header)) {
+ if (buffer_is_equal_string(s->show_header, CONST_STR_LEN("enable"))) {
+ buffer_copy_string_len(s->show_header, CONST_STR_LEN("HEADER.txt"));
+ }
+ else if (buffer_is_equal_string(s->show_header, CONST_STR_LEN("disable"))) {
+ buffer_clear(s->show_header);
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(dir_listing);
+ PATCH(external_css);
+ PATCH(external_js);
+ PATCH(hide_dot_files);
+ PATCH(encoding);
+ PATCH(show_readme);
+ PATCH(hide_readme_file);
+ PATCH(show_header);
+ PATCH(hide_header_file);
+ PATCH(excludes);
+ PATCH(set_footer);
+ PATCH(encode_readme);
+ PATCH(encode_header);
+ PATCH(auto_layout);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ACTIVATE)) ||
+ buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DIR_LISTING))) {
+ PATCH(dir_listing);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_DOTFILES))) {
+ PATCH(hide_dot_files);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXTERNAL_CSS))) {
+ PATCH(external_css);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXTERNAL_JS))) {
+ PATCH(external_js);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODING))) {
+ PATCH(encoding);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_README))) {
+ PATCH(show_readme);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_README_FILE))) {
+ PATCH(hide_readme_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_HEADER))) {
+ PATCH(show_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_HEADER_FILE))) {
+ PATCH(hide_header_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SET_FOOTER))) {
+ PATCH(set_footer);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXCLUDE))) {
+ PATCH(excludes);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODE_README))) {
+ PATCH(encode_readme);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODE_HEADER))) {
+ PATCH(encode_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_AUTO_LAYOUT))) {
+ PATCH(auto_layout);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+typedef struct {
+ size_t namelen;
+ time_t mtime;
+ off_t size;
+} dirls_entry_t;
+
+typedef struct {
+ dirls_entry_t **ent;
+ size_t used;
+ size_t size;
+} dirls_list_t;
+
+#define DIRLIST_ENT_NAME(ent) ((char*)(ent) + sizeof(dirls_entry_t))
+#define DIRLIST_BLOB_SIZE 16
+
+/* simple combsort algorithm */
+static void http_dirls_sort(dirls_entry_t **ent, int num) {
+ int gap = num;
+ int i, j;
+ int swapped;
+ dirls_entry_t *tmp;
+
+ do {
+ gap = (gap * 10) / 13;
+ if (gap == 9 || gap == 10)
+ gap = 11;
+ if (gap < 1)
+ gap = 1;
+ swapped = 0;
+
+ for (i = 0; i < num - gap; i++) {
+ j = i + gap;
+ if (strcmp(DIRLIST_ENT_NAME(ent[i]), DIRLIST_ENT_NAME(ent[j])) > 0) {
+ tmp = ent[i];
+ ent[i] = ent[j];
+ ent[j] = tmp;
+ swapped = 1;
+ }
+ }
+
+ } while (gap > 1 || swapped);
+}
+
+/* buffer must be able to hold "999.9K"
+ * conversion is simple but not perfect
+ */
+static int http_list_directory_sizefmt(char *buf, size_t bufsz, off_t size) {
+ const char unit[] = " KMGTPE"; /* Kilo, Mega, Giga, Tera, Peta, Exa */
+ const char *u = unit; /* u will always increment at least once */
+ int remain;
+ size_t buflen;
+
+ if (size < 100)
+ size += 99;
+ if (size < 100)
+ size = 0;
+
+ while (1) {
+ remain = (int) size & 1023;
+ size >>= 10;
+ u++;
+ if ((size & (~0 ^ 1023)) == 0)
+ break;
+ }
+
+ remain /= 100;
+ if (remain > 9)
+ remain = 9;
+ if (size > 999) {
+ size = 0;
+ remain = 9;
+ u++;
+ }
+
+ li_itostrn(buf, bufsz, size);
+ buflen = strlen(buf);
+ if (buflen + 3 >= bufsz) return buflen;
+ buf[buflen+0] = '.';
+ buf[buflen+1] = remain + '0';
+ buf[buflen+2] = *u;
+ buf[buflen+3] = '\0';
+
+ return buflen + 3;
+}
+
+/* don't want to block when open()ing a fifo */
+#if defined(O_NONBLOCK)
+# define FIFO_NONBLOCK O_NONBLOCK
+#else
+# define FIFO_NONBLOCK 0
+#endif
+
+static void http_list_directory_include_file(buffer *out, buffer *path, const char *classname, int encode) {
+ int fd = open(path->ptr, O_RDONLY | FIFO_NONBLOCK);
+ ssize_t rd;
+ char buf[8192];
+
+ if (-1 == fd) return;
+
+ if (encode) {
+ buffer_append_string_len(out, CONST_STR_LEN("<pre class=\""));
+ buffer_append_string(out, classname);
+ buffer_append_string_len(out, CONST_STR_LEN("\">"));
+ }
+
+ while ((rd = read(fd, buf, sizeof(buf))) > 0) {
+ if (encode) {
+ buffer_append_string_encoded(out, buf, (size_t)rd, ENCODING_MINIMAL_XML);
+ } else {
+ buffer_append_string_len(out, buf, (size_t)rd);
+ }
+ }
+ close(fd);
+
+ if (encode) {
+ buffer_append_string_len(out, CONST_STR_LEN("</pre>"));
+ }
+}
+
+/* portions copied from mod_status
+ * modified and specialized for stable dirlist sorting by name */
+static const char js_simple_table_resort[] = \
+"var click_column;\n" \
+"var name_column = 0;\n" \
+"var date_column = 1;\n" \
+"var size_column = 2;\n" \
+"var type_column = 3;\n" \
+"var prev_span = null;\n" \
+"\n" \
+"if (typeof(String.prototype.localeCompare) === 'undefined') {\n" \
+" String.prototype.localeCompare = function(str, locale, options) {\n" \
+" return ((this == str) ? 0 : ((this > str) ? 1 : -1));\n" \
+" };\n" \
+"}\n" \
+"\n" \
+"if (typeof(String.prototype.toLocaleUpperCase) === 'undefined') {\n" \
+" String.prototype.toLocaleUpperCase = function() {\n" \
+" return this.toUpperCase();\n" \
+" };\n" \
+"}\n" \
+"\n" \
+"function get_inner_text(el) {\n" \
+" if((typeof el == 'string')||(typeof el == 'undefined'))\n" \
+" return el;\n" \
+" if(el.innerText)\n" \
+" return el.innerText;\n" \
+" else {\n" \
+" var str = \"\";\n" \
+" var cs = el.childNodes;\n" \
+" var l = cs.length;\n" \
+" for (i=0;i<l;i++) {\n" \
+" if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n" \
+" else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n" \
+" }\n" \
+" }\n" \
+" return str;\n" \
+"}\n" \
+"\n" \
+"function isdigit(c) {\n" \
+" return (c >= '0' && c <= '9');\n" \
+"}\n" \
+"\n" \
+"function unit_multiplier(unit) {\n" \
+" return (unit=='K') ? 1000\n" \
+" : (unit=='M') ? 1000000\n" \
+" : (unit=='G') ? 1000000000\n" \
+" : (unit=='T') ? 1000000000000\n" \
+" : (unit=='P') ? 1000000000000000\n" \
+" : (unit=='E') ? 1000000000000000000 : 1;\n" \
+"}\n" \
+"\n" \
+"var li_date_regex=/(\\d{4})-(\\w{3})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/;\n" \
+"\n" \
+"var li_mon = ['Jan','Feb','Mar','Apr','May','Jun',\n" \
+" 'Jul','Aug','Sep','Oct','Nov','Dec'];\n" \
+"\n" \
+"function li_mon_num(mon) {\n" \
+" var i; for (i = 0; i < 12 && mon != li_mon[i]; ++i); return i;\n" \
+"}\n" \
+"\n" \
+"function li_date_cmp(s1, s2) {\n" \
+" var dp1 = li_date_regex.exec(s1)\n" \
+" var dp2 = li_date_regex.exec(s2)\n" \
+" for (var i = 1; i < 7; ++i) {\n" \
+" var cmp = (2 != i)\n" \
+" ? parseInt(dp1[i]) - parseInt(dp2[i])\n" \
+" : li_mon_num(dp1[2]) - li_mon_num(dp2[2]);\n" \
+" if (0 != cmp) return cmp;\n" \
+" }\n" \
+" return 0;\n" \
+"}\n" \
+"\n" \
+"function sortfn_then_by_name(a,b,sort_column) {\n" \
+" if (sort_column == name_column || sort_column == type_column) {\n" \
+" var ad = (a.cells[type_column].innerHTML === 'Directory');\n" \
+" var bd = (b.cells[type_column].innerHTML === 'Directory');\n" \
+" if (ad != bd) return (ad ? -1 : 1);\n" \
+" }\n" \
+" var at = get_inner_text(a.cells[sort_column]);\n" \
+" var bt = get_inner_text(b.cells[sort_column]);\n" \
+" var cmp;\n" \
+" if (sort_column == name_column) {\n" \
+" if (at == '..') return -1;\n" \
+" if (bt == '..') return 1;\n" \
+" }\n" \
+" if (a.cells[sort_column].className == 'int') {\n" \
+" cmp = parseInt(at)-parseInt(bt);\n" \
+" } else if (sort_column == date_column) {\n" \
+" var ad = isdigit(at.substr(0,1));\n" \
+" var bd = isdigit(bt.substr(0,1));\n" \
+" if (ad != bd) return (!ad ? -1 : 1);\n" \
+" cmp = li_date_cmp(at,bt);\n" \
+" } else if (sort_column == size_column) {\n" \
+" var ai = parseInt(at, 10) * unit_multiplier(at.substr(-1,1));\n" \
+" var bi = parseInt(bt, 10) * unit_multiplier(bt.substr(-1,1));\n" \
+" if (at.substr(0,1) == '-') ai = -1;\n" \
+" if (bt.substr(0,1) == '-') bi = -1;\n" \
+" cmp = ai - bi;\n" \
+" } else {\n" \
+" cmp = at.toLocaleUpperCase().localeCompare(bt.toLocaleUpperCase());\n" \
+" if (0 != cmp) return cmp;\n" \
+" cmp = at.localeCompare(bt);\n" \
+" }\n" \
+" if (0 != cmp || sort_column == name_column) return cmp;\n" \
+" return sortfn_then_by_name(a,b,name_column);\n" \
+"}\n" \
+"\n" \
+"function sortfn(a,b) {\n" \
+" return sortfn_then_by_name(a,b,click_column);\n" \
+"}\n" \
+"\n" \
+"function resort(lnk) {\n" \
+" var span = lnk.childNodes[1];\n" \
+" var table = lnk.parentNode.parentNode.parentNode.parentNode;\n" \
+" var rows = new Array();\n" \
+" for (j=1;j<table.rows.length;j++)\n" \
+" rows[j-1] = table.rows[j];\n" \
+" click_column = lnk.parentNode.cellIndex;\n" \
+" rows.sort(sortfn);\n" \
+"\n" \
+" if (prev_span != null) prev_span.innerHTML = '';\n" \
+" if (span.getAttribute('sortdir')=='down') {\n" \
+" span.innerHTML = '&uarr;';\n" \
+" span.setAttribute('sortdir','up');\n" \
+" rows.reverse();\n" \
+" } else {\n" \
+" span.innerHTML = '&darr;';\n" \
+" span.setAttribute('sortdir','down');\n" \
+" }\n" \
+" for (i=0;i<rows.length;i++)\n" \
+" table.tBodies[0].appendChild(rows[i]);\n" \
+" prev_span = span;\n" \
+"}\n";
+
+/* portions copied from mod_dirlist (lighttpd2) */
+static const char js_simple_table_init_sort[] = \
+"\n" \
+"function init_sort(init_sort_column, ascending) {\n" \
+" var tables = document.getElementsByTagName(\"table\");\n" \
+" for (var i = 0; i < tables.length; i++) {\n" \
+" var table = tables[i];\n" \
+" //var c = table.getAttribute(\"class\")\n" \
+" //if (-1 != c.split(\" \").indexOf(\"sort\")) {\n" \
+" var row = table.rows[0].cells;\n" \
+" for (var j = 0; j < row.length; j++) {\n" \
+" var n = row[j];\n" \
+" if (n.childNodes.length == 1 && n.childNodes[0].nodeType == 3) {\n" \
+" var link = document.createElement(\"a\");\n" \
+" var title = n.childNodes[0].nodeValue.replace(/:$/, \"\");\n" \
+" link.appendChild(document.createTextNode(title));\n" \
+" link.setAttribute(\"href\", \"#\");\n" \
+" link.setAttribute(\"class\", \"sortheader\");\n" \
+" link.setAttribute(\"onclick\", \"resort(this);return false;\");\n" \
+" var arrow = document.createElement(\"span\");\n" \
+" arrow.setAttribute(\"class\", \"sortarrow\");\n" \
+" arrow.appendChild(document.createTextNode(\":\"));\n" \
+" link.appendChild(arrow)\n" \
+" n.replaceChild(link, n.firstChild);\n" \
+" }\n" \
+" }\n" \
+" var lnk = row[init_sort_column].firstChild;\n" \
+" if (ascending) {\n" \
+" var span = lnk.childNodes[1];\n" \
+" span.setAttribute('sortdir','down');\n" \
+" }\n" \
+" resort(lnk);\n" \
+" //}\n" \
+" }\n" \
+"}\n";
+
+static void http_dirlist_append_js_table_resort (buffer *b, connection *con) {
+ char col = '0';
+ char ascending = '0';
+ if (!buffer_string_is_empty(con->uri.query)) {
+ const char *qs = con->uri.query->ptr;
+ do {
+ if (qs[0] == 'C' && qs[1] == '=') {
+ switch (qs[2]) {
+ case 'N': col = '0'; break;
+ case 'M': col = '1'; break;
+ case 'S': col = '2'; break;
+ case 'T':
+ case 'D': col = '3'; break;
+ default: break;
+ }
+ }
+ else if (qs[0] == 'O' && qs[1] == '=') {
+ switch (qs[2]) {
+ case 'A': ascending = '1'; break;
+ case 'D': ascending = '0'; break;
+ default: break;
+ }
+ }
+ } while ((qs = strchr(qs, '&')) && *++qs);
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("\n<script type=\"text/javascript\">\n// <!--\n\n"));
+ buffer_append_string_len(b, js_simple_table_resort, sizeof(js_simple_table_resort)-1);
+ buffer_append_string_len(b, js_simple_table_init_sort, sizeof(js_simple_table_init_sort)-1);
+ buffer_append_string_len(b, CONST_STR_LEN("\ninit_sort("));
+ buffer_append_string_len(b, &col, 1);
+ buffer_append_string_len(b, CONST_STR_LEN(", "));
+ buffer_append_string_len(b, &ascending, 1);
+ buffer_append_string_len(b, CONST_STR_LEN(");\n\n// -->\n</script>\n\n"));
+}
+
+static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
+ UNUSED(srv);
+
+ if (p->conf.auto_layout) {
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<!DOCTYPE html>\n"
+ "<html>\n"
+ "<head>\n"
+ ));
+ if (!buffer_string_is_empty(p->conf.encoding)) {
+ buffer_append_string_len(out, CONST_STR_LEN("<meta charset=\""));
+ buffer_append_string_buffer(out, p->conf.encoding);
+ buffer_append_string_len(out, CONST_STR_LEN("\">\n"));
+ }
+ buffer_append_string_len(out, CONST_STR_LEN("<title>Index of "));
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</title>\n"));
+
+ if (!buffer_string_is_empty(p->conf.external_css)) {
+ buffer_append_string_len(out, CONST_STR_LEN("<meta name=\"viewport\" content=\"initial-scale=1\">"));
+ buffer_append_string_len(out, CONST_STR_LEN("<link rel=\"stylesheet\" type=\"text/css\" href=\""));
+ buffer_append_string_buffer(out, p->conf.external_css);
+ buffer_append_string_len(out, CONST_STR_LEN("\">\n"));
+ } else {
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<style type=\"text/css\">\n"
+ "a, a:active {text-decoration: none; color: blue;}\n"
+ "a:visited {color: #48468F;}\n"
+ "a:hover, a:focus {text-decoration: underline; color: red;}\n"
+ "body {background-color: #F5F5F5;}\n"
+ "h2 {margin-bottom: 12px;}\n"
+ "table {margin-left: 12px;}\n"
+ "th, td {"
+ " font: 90% monospace;"
+ " text-align: left;"
+ "}\n"
+ "th {"
+ " font-weight: bold;"
+ " padding-right: 14px;"
+ " padding-bottom: 3px;"
+ "}\n"
+ "td {padding-right: 14px;}\n"
+ "td.s, th.s {text-align: right;}\n"
+ "div.list {"
+ " background-color: white;"
+ " border-top: 1px solid #646464;"
+ " border-bottom: 1px solid #646464;"
+ " padding-top: 10px;"
+ " padding-bottom: 14px;"
+ "}\n"
+ "div.foot {"
+ " font: 90% monospace;"
+ " color: #787878;"
+ " padding-top: 4px;"
+ "}\n"
+ "</style>\n"
+ ));
+ }
+
+ buffer_append_string_len(out, CONST_STR_LEN("</head>\n<body>\n"));
+ }
+
+ if (!buffer_string_is_empty(p->conf.show_header)) {
+ /* if we have a HEADER file, display it in <pre class="header"></pre> */
+
+ buffer *hb = p->conf.show_header;
+ if (hb->ptr[0] != '/') {
+ buffer_copy_buffer(p->tmp_buf, con->physical.path);
+ buffer_append_path_len(p->tmp_buf, CONST_BUF_LEN(p->conf.show_header));
+ hb = p->tmp_buf;
+ }
+
+ http_list_directory_include_file(out, hb, "header", p->conf.encode_header);
+ }
+
+ buffer_append_string_len(out, CONST_STR_LEN("<h2>Index of "));
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "</h2>\n"
+ "<div class=\"list\">\n"
+ "<table summary=\"Directory Listing\" cellpadding=\"0\" cellspacing=\"0\">\n"
+ "<thead>"
+ "<tr>"
+ "<th class=\"n\">Name</th>"
+ "<th class=\"m\">Last Modified</th>"
+ "<th class=\"s\">Size</th>"
+ "<th class=\"t\">Type</th>"
+ "</tr>"
+ "</thead>\n"
+ "<tbody>\n"
+ ));
+ if (!buffer_is_equal_string(con->uri.path, CONST_STR_LEN("/"))) {
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<tr class=\"d\">"
+ "<td class=\"n\"><a href=\"../\">..</a>/</td>"
+ "<td class=\"m\">&nbsp;</td>"
+ "<td class=\"s\">- &nbsp;</td>"
+ "<td class=\"t\">Directory</td>"
+ "</tr>\n"
+ ));
+ }
+}
+
+static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
+ UNUSED(srv);
+
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "</tbody>\n"
+ "</table>\n"
+ "</div>\n"
+ ));
+
+ if (!buffer_string_is_empty(p->conf.show_readme)) {
+ /* if we have a README file, display it in <pre class="readme"></pre> */
+
+ buffer *rb = p->conf.show_readme;
+ if (rb->ptr[0] != '/') {
+ buffer_copy_buffer(p->tmp_buf, con->physical.path);
+ buffer_append_path_len(p->tmp_buf, CONST_BUF_LEN(p->conf.show_readme));
+ rb = p->tmp_buf;
+ }
+
+ http_list_directory_include_file(out, rb, "readme", p->conf.encode_readme);
+ }
+
+ if(p->conf.auto_layout) {
+
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<div class=\"foot\">"
+ ));
+
+ if (!buffer_string_is_empty(p->conf.set_footer)) {
+ buffer_append_string_buffer(out, p->conf.set_footer);
+ } else {
+ buffer_append_string_buffer(out, con->conf.server_tag);
+ }
+
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "</div>\n"
+ ));
+
+ if (!buffer_string_is_empty(p->conf.external_js)) {
+ buffer_append_string_len(out, CONST_STR_LEN("<script type=\"text/javascript\" src=\""));
+ buffer_append_string_buffer(out, p->conf.external_js);
+ buffer_append_string_len(out, CONST_STR_LEN("\"></script>\n"));
+ } else if (buffer_is_empty(p->conf.external_js)) {
+ http_dirlist_append_js_table_resort(out, con);
+ }
+
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "</body>\n"
+ "</html>\n"
+ ));
+ }
+}
+
+static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) {
+ DIR *dp;
+ buffer *out;
+ struct dirent *dent;
+ struct stat st;
+ char *path, *path_file;
+ size_t i;
+ int hide_dotfiles = p->conf.hide_dot_files;
+ dirls_list_t dirs, files, *list;
+ dirls_entry_t *tmp;
+ char sizebuf[sizeof("999.9K")];
+ char datebuf[sizeof("2005-Jan-01 22:23:24")];
+ const char *content_type;
+ long name_max;
+#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ char attrval[128];
+ int attrlen;
+#endif
+#ifdef HAVE_LOCALTIME_R
+ struct tm tm;
+#endif
+
+ if (buffer_string_is_empty(dir)) return -1;
+
+ i = buffer_string_length(dir);
+
+#ifdef HAVE_PATHCONF
+ if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
+ /* some broken fs (fuse) return 0 instead of -1 */
+#ifdef NAME_MAX
+ name_max = NAME_MAX;
+#else
+ name_max = 255; /* stupid default */
+#endif
+ }
+#elif defined __WIN32
+ name_max = FILENAME_MAX;
+#else
+ name_max = NAME_MAX;
+#endif
+
+ path = malloc(i + name_max + 1);
+ force_assert(NULL != path);
+ memcpy(path, dir->ptr, i+1);
+ path_file = path + i;
+
+ if (NULL == (dp = opendir(path))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "opendir failed:", dir, strerror(errno));
+
+ free(path);
+ return -1;
+ }
+
+ dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
+ force_assert(dirs.ent);
+ dirs.size = DIRLIST_BLOB_SIZE;
+ dirs.used = 0;
+ files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
+ force_assert(files.ent);
+ files.size = DIRLIST_BLOB_SIZE;
+ files.used = 0;
+
+ while ((dent = readdir(dp)) != NULL) {
+#ifdef HAVE_PCRE_H
+ unsigned short exclude_match = 0;
+#endif
+
+ if (dent->d_name[0] == '.') {
+ if (hide_dotfiles)
+ continue;
+ if (dent->d_name[1] == '\0')
+ continue;
+ if (dent->d_name[1] == '.' && dent->d_name[2] == '\0')
+ continue;
+ }
+
+ if (p->conf.hide_readme_file && !buffer_string_is_empty(p->conf.show_readme)) {
+ if (strcmp(dent->d_name, p->conf.show_readme->ptr) == 0)
+ continue;
+ }
+ if (p->conf.hide_header_file && !buffer_string_is_empty(p->conf.show_header)) {
+ if (strcmp(dent->d_name, p->conf.show_header->ptr) == 0)
+ continue;
+ }
+
+ /* compare d_name against excludes array
+ * elements, skipping any that match.
+ */
+#ifdef HAVE_PCRE_H
+ for(i = 0; i < p->conf.excludes->used; i++) {
+ int n;
+#define N 10
+ int ovec[N * 3];
+ pcre *regex = p->conf.excludes->ptr[i]->regex;
+
+ if ((n = pcre_exec(regex, NULL, dent->d_name,
+ strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching:", n);
+
+ /* aborting would require a lot of manual cleanup here.
+ * skip instead (to not leak names that break pcre matching)
+ */
+ exclude_match = 1;
+ break;
+ }
+ }
+ else {
+ exclude_match = 1;
+ break;
+ }
+ }
+
+ if (exclude_match) {
+ continue;
+ }
+#endif
+
+ i = strlen(dent->d_name);
+
+ /* NOTE: the manual says, d_name is never more than NAME_MAX
+ * so this should actually not be a buffer-overflow-risk
+ */
+ if (i > (size_t)name_max) continue;
+
+ memcpy(path_file, dent->d_name, i + 1);
+ if (stat(path, &st) != 0)
+ continue;
+
+ list = &files;
+ if (S_ISDIR(st.st_mode))
+ list = &dirs;
+
+ if (list->used == list->size) {
+ list->size += DIRLIST_BLOB_SIZE;
+ list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size);
+ force_assert(list->ent);
+ }
+
+ tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i);
+ tmp->mtime = st.st_mtime;
+ tmp->size = st.st_size;
+ tmp->namelen = i;
+ memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1);
+
+ list->ent[list->used++] = tmp;
+ }
+ closedir(dp);
+
+ if (dirs.used) http_dirls_sort(dirs.ent, dirs.used);
+
+ if (files.used) http_dirls_sort(files.ent, files.used);
+
+ out = chunkqueue_append_buffer_open(con->write_queue);
+ http_list_directory_header(srv, con, p, out);
+
+ /* directories */
+ for (i = 0; i < dirs.used; i++) {
+ tmp = dirs.ent[i];
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&(tmp->mtime), &tm);
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
+#else
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
+#endif
+
+ buffer_append_string_len(out, CONST_STR_LEN("<tr class=\"d\"><td class=\"n\"><a href=\""));
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
+ buffer_append_string_len(out, CONST_STR_LEN("/\">"));
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</a>/</td><td class=\"m\">"));
+ buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
+ buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n"));
+
+ free(tmp);
+ }
+
+ /* files */
+ for (i = 0; i < files.used; i++) {
+ tmp = files.ent[i];
+
+ content_type = NULL;
+#if defined(HAVE_XATTR)
+ if (con->conf.use_xattr) {
+ memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
+ attrlen = sizeof(attrval) - 1;
+ if (attr_get(path, srv->srvconf.xattr_name->ptr, attrval, &attrlen, 0) == 0) {
+ attrval[attrlen] = '\0';
+ content_type = attrval;
+ }
+ }
+#elif defined(HAVE_EXTATTR)
+ if (con->conf.use_xattr) {
+ memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
+ if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, srv->srvconf.xattr_name->ptr, attrval, sizeof(attrval)-1))) {
+ attrval[attrlen] = '\0';
+ content_type = attrval;
+ }
+ }
+#endif
+
+ if (content_type == NULL) {
+ const buffer *type = stat_cache_mimetype_by_ext(con, DIRLIST_ENT_NAME(tmp), tmp->namelen);
+ content_type = NULL != type ? type->ptr : "application/octet-stream";
+ }
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&(tmp->mtime), &tm);
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
+#else
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
+#endif
+ http_list_directory_sizefmt(sizebuf, sizeof(sizebuf), tmp->size);
+
+ buffer_append_string_len(out, CONST_STR_LEN("<tr><td class=\"n\"><a href=\""));
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
+ buffer_append_string_len(out, CONST_STR_LEN("\">"));
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</a></td><td class=\"m\">"));
+ buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
+ buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">"));
+ buffer_append_string(out, sizebuf);
+ buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"t\">"));
+ buffer_append_string(out, content_type);
+ buffer_append_string_len(out, CONST_STR_LEN("</td></tr>\n"));
+
+ free(tmp);
+ }
+
+ free(files.ent);
+ free(dirs.ent);
+ free(path);
+
+ http_list_directory_footer(srv, con, p, out);
+
+ /* Insert possible charset to Content-Type */
+ if (buffer_string_is_empty(p->conf.encoding)) {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset="));
+ buffer_append_string_buffer(p->content_charset, p->conf.encoding);
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
+ }
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+ con->file_finished = 1;
+
+ return 0;
+}
+
+
+
+URIHANDLER_FUNC(mod_dirlisting_subrequest) {
+ plugin_data *p = p_d;
+ stat_cache_entry *sce = NULL;
+
+ UNUSED(srv);
+
+ /* we only handle GET and HEAD */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_HEAD:
+ break;
+ default:
+ return HANDLER_GO_ON;
+ }
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+ if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON;
+
+ mod_dirlisting_patch_connection(srv, con, p);
+
+ if (!p->conf.dir_listing) return HANDLER_GO_ON;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "SB", "stat_cache_get_entry failed: ", con->physical.path);
+ SEGFAULT();
+ }
+
+ if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
+
+ if (http_list_directory(srv, con, p, con->physical.path)) {
+ /* dirlisting failed */
+ con->http_status = 403;
+ }
+
+ buffer_reset(con->physical.path);
+
+ /* not found */
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_dirlisting_plugin_init(plugin *p);
+int mod_dirlisting_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("dirlisting");
+
+ p->init = mod_dirlisting_init;
+ p->handle_subrequest_start = mod_dirlisting_subrequest;
+ p->set_defaults = mod_dirlisting_set_defaults;
+ p->cleanup = mod_dirlisting_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_evasive.c b/data/lighttpd/lighttpd-1.4.53/src/mod_evasive.c
new file mode 100644
index 000000000..9171d5c44
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_evasive.c
@@ -0,0 +1,208 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+#include "sock_addr.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * mod_evasive
+ *
+ * we indent to implement all features the mod_evasive from apache has
+ *
+ * - limit of connections per IP
+ * - provide a list of block-listed ip/networks (no access)
+ * - provide a white-list of ips/network which is not affected by the limit
+ * (hmm, conditionals might be enough)
+ * - provide a bandwidth limiter per IP
+ *
+ * started by:
+ * - w1zzard@techpowerup.com
+ */
+
+typedef struct {
+ unsigned short max_conns;
+ unsigned short silent;
+ buffer *location;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_evasive_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+FREE_FUNC(mod_evasive_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->location);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "evasive.silent", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "evasive.location", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->max_conns = 0;
+ s->silent = 0;
+ s->location = buffer_init();
+
+ cv[0].destination = &(s->max_conns);
+ cv[1].destination = &(s->silent);
+ cv[2].destination = s->location;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(max_conns);
+ PATCH(silent);
+ PATCH(location);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
+ PATCH(max_conns);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.silent"))) {
+ PATCH(silent);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.location"))) {
+ PATCH(location);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_evasive_uri_handler) {
+ plugin_data *p = p_d;
+ size_t conns_by_ip = 0;
+ size_t j;
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_evasive_patch_connection(srv, con, p);
+
+ /* no limit set, nothing to block */
+ if (p->conf.max_conns == 0) return HANDLER_GO_ON;
+
+ for (j = 0; j < srv->conns->used; j++) {
+ connection *c = srv->conns->ptr[j];
+
+ /* check if other connections are already actively serving data for the same IP
+ * we can only ban connections which are already behind the 'read request' state
+ * */
+ if (c->state <= CON_STATE_REQUEST_END) continue;
+
+ if (!sock_addr_is_addr_eq(&c->dst_addr, &con->dst_addr)) continue;
+ conns_by_ip++;
+
+ if (conns_by_ip > p->conf.max_conns) {
+ if (!p->conf.silent) {
+ log_error_write(srv, __FILE__, __LINE__, "bs",
+ con->dst_addr_buf,
+ "turned away. Too many connections.");
+ }
+
+ if (!buffer_is_empty(p->conf.location)) {
+ http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.location));
+ con->http_status = 302;
+ con->file_finished = 1;
+ } else {
+ con->http_status = 403;
+ }
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_evasive_plugin_init(plugin *p);
+int mod_evasive_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("evasive");
+
+ p->init = mod_evasive_init;
+ p->set_defaults = mod_evasive_set_defaults;
+ p->handle_uri_clean = mod_evasive_uri_handler;
+ p->cleanup = mod_evasive_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_evhost.c b/data/lighttpd/lighttpd-1.4.53/src/mod_evhost.c
new file mode 100644
index 000000000..ae7076970
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_evhost.c
@@ -0,0 +1,363 @@
+#include "first.h"
+
+#include "base.h"
+#include "plugin.h"
+#include "log.h"
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+typedef struct {
+ /* unparsed pieces */
+ buffer *path_pieces_raw;
+
+ /* pieces for path creation */
+ size_t len;
+ buffer **path_pieces;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_evhost_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+FREE_FUNC(mod_evhost_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ if(s->path_pieces) {
+ size_t j;
+ for (j = 0; j < s->len; j++) {
+ buffer_free(s->path_pieces[j]);
+ }
+
+ free(s->path_pieces);
+ }
+
+ buffer_free(s->path_pieces_raw);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+static int mod_evhost_parse_pattern(plugin_config *s) {
+ char *ptr = s->path_pieces_raw->ptr,*pos;
+
+ s->path_pieces = NULL;
+
+ for(pos=ptr;*ptr;ptr++) {
+ if(*ptr == '%') {
+ size_t len;
+ s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
+ s->path_pieces[s->len] = buffer_init();
+ s->path_pieces[s->len+1] = buffer_init();
+
+ /* "%%" "%_" "%x" "%{x.y}" where x and y are *single digit* 0 - 9 */
+ if (ptr[1] == '%' || ptr[1] == '_' || light_isdigit(ptr[1])) {
+ len = 2;
+ } else if (ptr[1] == '{') {
+ if (!light_isdigit(ptr[2])) return -1;
+ if (ptr[3] == '.') {
+ if (!light_isdigit(ptr[4])) return -1;
+ if (ptr[5] != '}') return -1;
+ len = 6;
+ } else if (ptr[3] == '}') {
+ len = 4;
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+
+ buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
+ pos = ptr + len;
+
+ buffer_copy_string_len(s->path_pieces[s->len+1],ptr,len);
+ ptr += len - 1; /*(ptr++ in for() loop)*/
+
+ s->len += 2;
+ }
+ }
+
+ if(*pos != '\0') {
+ s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
+ s->path_pieces[s->len] = buffer_init();
+
+ buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
+
+ s->len += 1;
+ }
+
+ return 0;
+}
+
+SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ /**
+ *
+ * #
+ * # define a pattern for the host url finding
+ * # %% => % sign
+ * # %0 => domain name + tld
+ * # %1 => tld
+ * # %2 => domain name without tld
+ * # %3 => subdomain 1 name
+ * # %4 => subdomain 2 name
+ * # %_ => fqdn (without port info)
+ * #
+ * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
+ *
+ */
+
+ config_values_t cv[] = {
+ { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->path_pieces_raw = buffer_init();
+ s->path_pieces = NULL;
+ s->len = 0;
+
+ cv[0].destination = s->path_pieces_raw;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->path_pieces_raw)) {
+ if (0 != mod_evhost_parse_pattern(s)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "invalid evhost.path-pattern:", s->path_pieces_raw);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/**
+ * assign the different parts of the domain to array-indezes (sub2.sub1.domain.tld)
+ * - %0 - domain.tld
+ * - %1 - tld
+ * - %2 - domain
+ * - %3 - sub1
+ * - ...
+ */
+
+static void mod_evhost_parse_host(buffer *key, array *host, buffer *authority) {
+ char *ptr = authority->ptr + buffer_string_length(authority);
+ char *colon = ptr; /* needed to filter out the colon (if exists) */
+ int first = 1;
+ int i;
+
+ /* first, find the domain + tld */
+ for(; ptr > authority->ptr; --ptr) {
+ if(*ptr == '.') {
+ if(first) first = 0;
+ else break;
+ } else if(*ptr == ':') {
+ colon = ptr;
+ first = 1;
+ }
+ }
+
+ /* if we stopped at a dot, skip the dot */
+ if (*ptr == '.') ptr++;
+ array_insert_key_value(host, CONST_STR_LEN("%0"), ptr, colon-ptr);
+
+ /* if the : is not the start of the authority, go on parsing the hostname */
+
+ if (colon != authority->ptr) {
+ for(ptr = colon - 1, i = 1; ptr > authority->ptr; --ptr) {
+ if(*ptr == '.') {
+ if (ptr != colon - 1) {
+ /* is something between the dots */
+ buffer_copy_string_len(key, CONST_STR_LEN("%"));
+ buffer_append_int(key, i++);
+ array_insert_key_value(host, CONST_BUF_LEN(key), ptr+1, colon-ptr-1);
+ }
+ colon = ptr;
+ }
+ }
+
+ /* if the . is not the first charactor of the hostname */
+ if (colon != ptr) {
+ buffer_copy_string_len(key, CONST_STR_LEN("%"));
+ buffer_append_int(key, i /* ++ */);
+ array_insert_key_value(host, CONST_BUF_LEN(key), ptr, colon-ptr);
+ }
+ }
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(path_pieces);
+ PATCH(len);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
+ PATCH(path_pieces);
+ PATCH(len);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static void mod_evhost_build_doc_root_path(buffer *b, array *parsed_host, buffer *authority, buffer **path_pieces, const size_t npieces) {
+ array_reset_data_strings(parsed_host);
+ mod_evhost_parse_host(b, parsed_host, authority);
+ buffer_clear(b);
+
+ for (size_t i = 0; i < npieces; ++i) {
+ const char *ptr = path_pieces[i]->ptr;
+ if (*ptr == '%') {
+ data_string *ds;
+
+ if (*(ptr+1) == '%') {
+ /* %% */
+ buffer_append_string_len(b, CONST_STR_LEN("%"));
+ } else if (*(ptr+1) == '_' ) {
+ /* %_ == full hostname */
+ char *colon = strchr(authority->ptr, ':');
+
+ if(colon == NULL) {
+ buffer_append_string_buffer(b, authority); /* adds fqdn */
+ } else {
+ /* strip the port out of the authority-part of the URI scheme */
+ buffer_append_string_len(b, authority->ptr, colon - authority->ptr); /* adds fqdn */
+ }
+ } else if (ptr[1] == '{' ) {
+ char s[3] = "% ";
+ s[1] = ptr[2]; /*(assumes single digit before '.', and, optionally, '.' and single digit after '.')*/
+ if (NULL != (ds = (data_string *)array_get_element_klen(parsed_host, s, 2))) {
+ if (ptr[3] != '.' || ptr[4] == '0') {
+ buffer_append_string_buffer(b, ds->value);
+ } else {
+ if ((size_t)(ptr[4]-'0') <= buffer_string_length(ds->value)) {
+ buffer_append_string_len(b, ds->value->ptr+(ptr[4]-'0')-1, 1);
+ }
+ }
+ } else {
+ /* unhandled %-sequence */
+ }
+ } else if (NULL != (ds = (data_string *)array_get_element_klen(parsed_host, CONST_BUF_LEN(path_pieces[i])))) {
+ buffer_append_string_buffer(b, ds->value);
+ } else {
+ /* unhandled %-sequence */
+ }
+ } else {
+ buffer_append_string_buffer(b, path_pieces[i]);
+ }
+ }
+
+ buffer_append_slash(b);
+}
+
+static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ stat_cache_entry *sce = NULL;
+
+ /* not authority set */
+ if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
+
+ mod_evhost_patch_connection(srv, con, p);
+
+ /* missing even default(global) conf */
+ if (0 == p->conf.len) {
+ return HANDLER_GO_ON;
+ }
+
+ mod_evhost_build_doc_root_path(p->tmp_buf, srv->split_vals, con->uri.authority, p->conf.path_pieces, p->conf.len);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
+ } else if(!S_ISDIR(sce->st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
+ } else {
+ buffer_copy_buffer(con->physical.doc_root, p->tmp_buf);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+int mod_evhost_plugin_init(plugin *p);
+int mod_evhost_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("evhost");
+ p->init = mod_evhost_init;
+ p->set_defaults = mod_evhost_set_defaults;
+ p->handle_docroot = mod_evhost_uri_handler;
+ p->cleanup = mod_evhost_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
+/* eof */
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_expire.c b/data/lighttpd/lighttpd-1.4.53/src/mod_expire.c
new file mode 100644
index 000000000..d0f771bf8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_expire.c
@@ -0,0 +1,424 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/**
+ * this is a expire module for a lighttpd
+ *
+ * set 'Expires:' HTTP Headers on demand
+ */
+
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *expire_url;
+ array *expire_mimetypes;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *expire_tstmp;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_expire_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->expire_tstmp = buffer_init();
+
+ buffer_string_prepare_copy(p->expire_tstmp, 255);
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_expire_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ buffer_free(p->expire_tstmp);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->expire_url);
+ array_free(s->expire_mimetypes);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, time_t *offset) {
+ char *ts;
+ int type = -1;
+ time_t retts = 0;
+
+ UNUSED(p);
+
+ /*
+ * parse
+ *
+ * '(access|now|modification) [plus] {<num> <type>}*'
+ *
+ * e.g. 'access 1 years'
+ */
+
+ if (buffer_string_is_empty(expire)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "empty:");
+ return -1;
+ }
+
+ ts = expire->ptr;
+
+ if (0 == strncmp(ts, "access ", 7)) {
+ type = 0;
+ ts += 7;
+ } else if (0 == strncmp(ts, "now ", 4)) {
+ type = 0;
+ ts += 4;
+ } else if (0 == strncmp(ts, "modification ", 13)) {
+ type = 1;
+ ts += 13;
+ } else {
+ /* invalid type-prefix */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "invalid <base>:", ts);
+ return -1;
+ }
+
+ if (0 == strncmp(ts, "plus ", 5)) {
+ /* skip the optional plus */
+ ts += 5;
+ }
+
+ /* the rest is just <number> (years|months|weeks|days|hours|minutes|seconds) */
+ while (1) {
+ char *space, *err;
+ int num;
+
+ if (NULL == (space = strchr(ts, ' '))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "missing space after <num>:", ts);
+ return -1;
+ }
+
+ num = strtol(ts, &err, 10);
+ if (*err != ' ') {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "missing <type> after <num>:", ts);
+ return -1;
+ }
+
+ ts = space + 1;
+
+ if (NULL != (space = strchr(ts, ' '))) {
+ int slen;
+ /* */
+
+ slen = space - ts;
+
+ if (slen == 5 &&
+ 0 == strncmp(ts, "years", slen)) {
+ num *= 60 * 60 * 24 * 30 * 12;
+ } else if (slen == 6 &&
+ 0 == strncmp(ts, "months", slen)) {
+ num *= 60 * 60 * 24 * 30;
+ } else if (slen == 5 &&
+ 0 == strncmp(ts, "weeks", slen)) {
+ num *= 60 * 60 * 24 * 7;
+ } else if (slen == 4 &&
+ 0 == strncmp(ts, "days", slen)) {
+ num *= 60 * 60 * 24;
+ } else if (slen == 5 &&
+ 0 == strncmp(ts, "hours", slen)) {
+ num *= 60 * 60;
+ } else if (slen == 7 &&
+ 0 == strncmp(ts, "minutes", slen)) {
+ num *= 60;
+ } else if (slen == 7 &&
+ 0 == strncmp(ts, "seconds", slen)) {
+ num *= 1;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "unknown type:", ts);
+ return -1;
+ }
+
+ retts += num;
+
+ ts = space + 1;
+ } else {
+ if (0 == strcmp(ts, "years")) {
+ num *= 60 * 60 * 24 * 30 * 12;
+ } else if (0 == strcmp(ts, "months")) {
+ num *= 60 * 60 * 24 * 30;
+ } else if (0 == strcmp(ts, "weeks")) {
+ num *= 60 * 60 * 24 * 7;
+ } else if (0 == strcmp(ts, "days")) {
+ num *= 60 * 60 * 24;
+ } else if (0 == strcmp(ts, "hours")) {
+ num *= 60 * 60;
+ } else if (0 == strcmp(ts, "minutes")) {
+ num *= 60;
+ } else if (0 == strcmp(ts, "seconds")) {
+ num *= 1;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "unknown type:", ts);
+ return -1;
+ }
+
+ retts += num;
+
+ break;
+ }
+ }
+
+ if (offset != NULL) *offset = retts;
+
+ return type;
+}
+
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_expire_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0, k;
+
+ config_values_t cv[] = {
+ { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "expire.mimetypes", 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(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->expire_url = array_init();
+ s->expire_mimetypes = array_init();
+
+ cv[0].destination = s->expire_url;
+ cv[1].destination = s->expire_mimetypes;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->expire_url)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for expire.url; expected list of \"urlpath\" => \"expiration\"");
+ return HANDLER_ERROR;
+ }
+
+ for (k = 0; k < s->expire_url->used; k++) {
+ data_string *ds = (data_string *)s->expire_url->data[k];
+
+ /* parse lines */
+ if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing expire.url failed:", ds->value);
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (!array_is_kvstring(s->expire_mimetypes)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for expire.mimetypes; expected list of \"mimetype\" => \"expiration\"");
+ return HANDLER_ERROR;
+ }
+
+ for (k = 0; k < s->expire_mimetypes->used; k++) {
+ data_string *ds = (data_string *)s->expire_mimetypes->data[k];
+ size_t klen = buffer_string_length(ds->key);
+
+ /*(omit trailing '*', if present, from prefix match)*/
+ /*(not usually a good idea to modify array keys
+ * since doing so might break array_get_element_klen() search,
+ * but array use in this module only walks array)*/
+ if (klen && ds->key->ptr[klen-1] == '*') buffer_string_set_length(ds->key, klen-1);
+
+ /* parse lines */
+ if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing expire.mimetypes failed:", ds->value);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(expire_url);
+ PATCH(expire_mimetypes);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
+ PATCH(expire_url);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.mimetypes"))) {
+ PATCH(expire_mimetypes);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+CONNECTION_FUNC(mod_expire_handler) {
+ plugin_data *p = p_d;
+ buffer *vb;
+ data_string *ds;
+
+ /* Add caching headers only to http_status 200 OK or 206 Partial Content */
+ if (con->http_status != 200 && con->http_status != 206) return HANDLER_GO_ON;
+ /* Add caching headers only to GET or HEAD requests */
+ if ( con->request.http_method != HTTP_METHOD_GET
+ && con->request.http_method != HTTP_METHOD_HEAD) return HANDLER_GO_ON;
+ /* Add caching headers only if not already present */
+ vb = http_header_response_get(con, HTTP_HEADER_CACHE_CONTROL, CONST_STR_LEN("Cache-Control"));
+ if (NULL != vb) return HANDLER_GO_ON;
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_expire_patch_connection(srv, con, p);
+
+ /* check expire.url */
+ ds = (data_string *)array_match_key_prefix(p->conf.expire_url, con->uri.path);
+ if (NULL != ds) {
+ vb = ds->value;
+ }
+ else {
+ /* check expire.mimetypes (if no match with expire.url) */
+ vb = http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"));
+ ds = (NULL != vb)
+ ? (data_string *)array_match_key_prefix(p->conf.expire_mimetypes, vb)
+ : (data_string *)array_get_element_klen(p->conf.expire_mimetypes, CONST_STR_LEN(""));
+ if (NULL == ds) return HANDLER_GO_ON;
+ vb = ds->value;
+ }
+
+ if (NULL != vb) {
+ time_t ts, expires;
+ stat_cache_entry *sce = NULL;
+
+ /* if stat fails => sce == NULL, ignore return value */
+ (void) stat_cache_get_entry(srv, con, con->physical.path, &sce);
+
+ switch(mod_expire_get_offset(srv, p, vb, &ts)) {
+ case 0:
+ /* access */
+ expires = (ts + srv->cur_ts);
+ break;
+ case 1:
+ /* modification */
+
+ /* can't set modification based expire header if
+ * mtime is not available
+ */
+ if (NULL == sce) return HANDLER_GO_ON;
+
+ expires = (ts + sce->st.st_mtime);
+ break;
+ default:
+ /* -1 is handled at parse-time */
+ return HANDLER_ERROR;
+ }
+
+ /* expires should be at least srv->cur_ts */
+ if (expires < srv->cur_ts) expires = srv->cur_ts;
+
+ buffer_clear(p->expire_tstmp);
+ buffer_append_strftime(p->expire_tstmp, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires)));
+
+ /* HTTP/1.0 */
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
+
+ /* HTTP/1.1 */
+ buffer_copy_string_len(p->expire_tstmp, CONST_STR_LEN("max-age="));
+ buffer_append_int(p->expire_tstmp, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
+
+ http_header_response_set(con, HTTP_HEADER_CACHE_CONTROL, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
+
+ return HANDLER_GO_ON;
+ }
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_expire_plugin_init(plugin *p);
+int mod_expire_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("expire");
+
+ p->init = mod_expire_init;
+ p->handle_response_start = mod_expire_handler;
+ p->set_defaults = mod_expire_set_defaults;
+ p->cleanup = mod_expire_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_extforward.c b/data/lighttpd/lighttpd-1.4.53/src/mod_extforward.c
new file mode 100644
index 000000000..152353141
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_extforward.c
@@ -0,0 +1,1645 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+#include "request.h"
+#include "sock_addr.h"
+
+#include "plugin.h"
+
+#include "configfile.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sys-socket.h"
+
+/**
+ * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com
+ * extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu
+ * support chained proxies by glen@delfi.ee, #1528
+ *
+ * Config example:
+ *
+ * Trust proxy 10.0.0.232 and 10.0.0.232
+ * extforward.forwarder = ( "10.0.0.232" => "trust",
+ * "10.0.0.233" => "trust" )
+ *
+ * Trust all proxies (NOT RECOMMENDED!)
+ * extforward.forwarder = ( "all" => "trust")
+ *
+ * Note that "all" has precedence over specific entries,
+ * so "all except" setups will not work.
+ *
+ * In case you have chained proxies, you can add all their IP's to the
+ * config. However "all" has effect only on connecting IP, as the
+ * X-Forwarded-For header can not be trusted.
+ *
+ * Note: The effect of this module is variable on $HTTP["remotip"] directives and
+ * other module's remote ip dependent actions.
+ * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP.
+ * Things done in between these two moments will match on the real client's IP.
+ * The moment things are done by a module depends on in which hook it does things and within the same hook
+ * on whether they are before/after us in the module loading order
+ * (order in the server.modules directive in the config file).
+ *
+ * Tested behaviours:
+ *
+ * mod_access: Will match on the real client.
+ *
+ * mod_accesslog:
+ * In order to see the "real" ip address in access log ,
+ * you'll have to load mod_extforward after mod_accesslog.
+ * like this:
+ *
+ * server.modules = (
+ * .....
+ * mod_accesslog,
+ * mod_extforward
+ * )
+ */
+
+
+/* plugin config for all request/connections */
+
+typedef enum {
+ PROXY_FORWARDED_NONE = 0x00,
+ PROXY_FORWARDED_FOR = 0x01,
+ PROXY_FORWARDED_PROTO = 0x02,
+ PROXY_FORWARDED_HOST = 0x04,
+ PROXY_FORWARDED_BY = 0x08,
+ PROXY_FORWARDED_REMOTE_USER = 0x10
+} proxy_forwarded_t;
+
+struct sock_addr_mask {
+ sock_addr addr;
+ int bits;
+};
+
+struct sock_addr_masks {
+ struct sock_addr_mask *addrs;
+ size_t used;
+ size_t sz;
+};
+
+typedef struct {
+ array *forwarder;
+ struct sock_addr_masks *forward_masks;
+ array *headers;
+ array *opts_params;
+ unsigned int opts;
+ unsigned short int hap_PROXY;
+ unsigned short int hap_PROXY_ssl_client_verify;
+ short int forward_all;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+static plugin_data *mod_extforward_plugin_data_singleton;
+static int extforward_check_proxy;
+
+
+/* context , used for restore remote ip */
+
+typedef struct {
+ /* per-request state */
+ sock_addr saved_remote_addr;
+ buffer *saved_remote_addr_buf;
+
+ /* hap-PROXY protocol prior to receiving first request */
+ int(*saved_network_read)(server *, connection *, chunkqueue *, off_t);
+
+ /* connection-level state applied to requests in handle_request_env */
+ array *env;
+ int ssl_client_verify;
+} handler_ctx;
+
+
+static handler_ctx * handler_ctx_init(void) {
+ handler_ctx * hctx;
+ hctx = calloc(1, sizeof(*hctx));
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_extforward_init) {
+ plugin_data *p;
+ p = calloc(1, sizeof(*p));
+ mod_extforward_plugin_data_singleton = p;
+ return p;
+}
+
+/* destroy the plugin data */
+FREE_FUNC(mod_extforward_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->forwarder);
+ array_free(s->headers);
+ array_free(s->opts_params);
+
+ if (s->forward_masks) {
+ free(s->forward_masks->addrs);
+ free(s->forward_masks);
+ }
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_extforward_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "extforward.forwarder", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "extforward.headers", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "extforward.params", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "extforward.hap-PROXY", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "extforward.hap-PROXY-ssl-client-verify", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->forwarder = array_init();
+ s->headers = array_init();
+ s->opts_params = array_init();
+ s->opts = PROXY_FORWARDED_NONE;
+
+ cv[0].destination = s->forwarder;
+ cv[1].destination = s->headers;
+ cv[2].destination = s->opts_params;
+ cv[3].destination = &s->hap_PROXY;
+ cv[4].destination = &s->hap_PROXY_ssl_client_verify;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->forwarder)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for extforward.forwarder; expected list of \"IPaddr\" => \"trust\"");
+ return HANDLER_ERROR;
+ }
+
+ if (array_get_element(config->value, "extforward.forwarder")) {
+ const data_string * const allds = (data_string *)array_get_element(s->forwarder, "all");
+ s->forward_all = (NULL == allds) ? 0 : (0 == strcasecmp(allds->value->ptr, "trust")) ? 1 : -1;
+ for (size_t j = 0; j < s->forwarder->used; ++j) {
+ data_string * const ds = (data_string *)s->forwarder->data[j];
+ char * const nm_slash = strchr(ds->key->ptr, '/');
+ if (0 != strcasecmp(ds->value->ptr, "trust")) {
+ if (0 != strcasecmp(ds->value->ptr, "untrusted")) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs", "ERROR: expect \"trust\", not \"", ds->key, "\" => \"", ds->value, "\"; treating as untrusted");
+ }
+ if (NULL != nm_slash) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs", "ERROR: untrusted CIDR masks are ignored (\"", ds->key, "\" => \"", ds->value, "\")");
+ }
+ buffer_clear(ds->value); /* empty is untrusted */
+ continue;
+ }
+ if (NULL != nm_slash) {
+ struct sock_addr_mask *sm;
+ char *err;
+ const int nm_bits = strtol(nm_slash + 1, &err, 10);
+ int rc;
+ if (*err || nm_bits <= 0) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask:", ds->key, err);
+ return HANDLER_ERROR;
+ }
+ if (NULL == s->forward_masks) {
+ s->forward_masks = calloc(1, sizeof(struct sock_addr_masks));
+ force_assert(s->forward_masks);
+ }
+ if (s->forward_masks->used == s->forward_masks->sz) {
+ s->forward_masks->sz += 2;
+ s->forward_masks->addrs = realloc(s->forward_masks->addrs, s->forward_masks->sz * sizeof(struct sock_addr_mask));
+ force_assert(s->forward_masks->addrs);
+ }
+ sm = s->forward_masks->addrs + s->forward_masks->used++;
+ sm->bits = nm_bits;
+ *nm_slash = '\0';
+ rc = sock_addr_from_str_numeric(srv, &sm->addr, ds->key->ptr);
+ *nm_slash = '/';
+ if (1 != rc) return HANDLER_ERROR;
+ buffer_clear(ds->value); /* empty is untrusted, e.g. if subnet (incorrectly) appears in X-Forwarded-For */
+ }
+ }
+ }
+
+ if (!array_is_vlist(s->headers)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for extforward.headers; expected list of \"headername\"");
+ return HANDLER_ERROR;
+ }
+
+ /* default to "X-Forwarded-For" or "Forwarded-For" if extforward.headers not specified or empty */
+ if (!s->hap_PROXY && 0 == s->headers->used && (0 == i || NULL != array_get_element(config->value, "extforward.headers"))) {
+ array_insert_value(s->headers, CONST_STR_LEN("X-Forwarded-For"));
+ array_insert_value(s->headers, CONST_STR_LEN("Forwarded-For"));
+ }
+
+ if (!array_is_kvany(s->opts_params)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for extforward.params; expected ( \"param\" => \"value\" )");
+ return HANDLER_ERROR;
+ }
+ for (size_t j = 0, used = s->opts_params->used; j < used; ++j) {
+ proxy_forwarded_t param;
+ data_unset *du = s->opts_params->data[j];
+ #if 0 /*("for" and "proto" historical behavior: always enabled)*/
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("by"))) {
+ param = PROXY_FORWARDED_BY;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("for"))) {
+ param = PROXY_FORWARDED_FOR;
+ } else
+ #endif
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("host"))) {
+ param = PROXY_FORWARDED_HOST;
+ #if 0
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proto"))) {
+ param = PROXY_FORWARDED_PROTO;
+ #endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("remote_user"))) {
+ param = PROXY_FORWARDED_REMOTE_USER;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "extforward.params keys must be one of: host, remote_user, but not:", du->key);
+ return HANDLER_ERROR;
+ }
+ if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
+ s->opts |= param;
+ } else if (!buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "extforward.params values must be one of: 0, 1, enable, disable; error for key:", du->key);
+ return HANDLER_ERROR;
+ }
+ } else if (du->type == TYPE_INTEGER) {
+ data_integer *di = (data_integer *)du;
+ if (di->value) s->opts |= param;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "extforward.params values must be one of: 0, 1, enable, disable; error for key:", du->key);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ /* attempt to warn if mod_extforward is not last module loaded to hook
+ * handle_connection_accept. (Nice to have, but remove this check if
+ * it reaches too far into internals and prevents other code changes.)
+ * While it would be nice to check connection_handle_accept plugin slot
+ * to make sure mod_extforward is last, that info is private to plugin.c
+ * so merely warn if mod_openssl is loaded after mod_extforward, though
+ * future modules which hook connection_handle_accept might be missed.*/
+ for (i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ if (s->hap_PROXY) {
+ size_t j;
+ for (j = 0; j < srv->srvconf.modules->used; ++j) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[j];
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_extforward"))) {
+ break;
+ }
+ }
+ for (; j < srv->srvconf.modules->used; ++j) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[j];
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_openssl"))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "mod_extforward must be loaded after mod_openssl in server.modules when extforward.hap-PROXY = \"enable\"");
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[i];
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_proxy"))) {
+ extforward_check_proxy = 1;
+ break;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_extforward_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(forwarder);
+ PATCH(forward_masks);
+ PATCH(headers);
+ PATCH(opts);
+ PATCH(hap_PROXY);
+ PATCH(hap_PROXY_ssl_client_verify);
+ PATCH(forward_all);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.forwarder"))) {
+ PATCH(forwarder);
+ PATCH(forward_masks);
+ PATCH(forward_all);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.headers"))) {
+ PATCH(headers);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.params"))) {
+ PATCH(opts);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.hap-PROXY"))) {
+ PATCH(hap_PROXY);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.hap-PROXY-ssl-client-verify"))) {
+ PATCH(hap_PROXY_ssl_client_verify);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+/*
+ extract a forward array from the environment
+*/
+static array *extract_forward_array(buffer *pbuffer)
+{
+ array *result = array_init();
+ if (!buffer_string_is_empty(pbuffer)) {
+ char *base, *curr;
+ /* state variable, 0 means not in string, 1 means in string */
+ int in_str = 0;
+ for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) {
+ if (in_str) {
+ if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' && (*curr < 'a' || *curr > 'f') && (*curr < 'A' || *curr > 'F')) {
+ /* found an separator , insert value into result array */
+ array_insert_value(result, base, curr - base);
+ /* change state to not in string */
+ in_str = 0;
+ }
+ } else {
+ if ((*curr >= '0' && *curr <= '9') || *curr == ':' || (*curr >= 'a' && *curr <= 'f') || (*curr >= 'A' && *curr <= 'F')) {
+ /* found leading char of an IP address, move base pointer and change state */
+ base = curr;
+ in_str = 1;
+ }
+ }
+ }
+ /* if breaking out while in str, we got to the end of string, so add it */
+ if (in_str) {
+ array_insert_value(result, base, curr - base);
+ }
+ }
+ return result;
+}
+
+/*
+ * check whether ip is trusted, return 1 for trusted , 0 for untrusted
+ */
+static int is_proxy_trusted(plugin_data *p, const char * const ip, size_t iplen)
+{
+ data_string *ds =
+ (data_string *)array_get_element_klen(p->conf.forwarder, ip, iplen);
+ if (NULL != ds) return !buffer_string_is_empty(ds->value);
+
+ if (p->conf.forward_masks) {
+ const struct sock_addr_mask * const addrs =p->conf.forward_masks->addrs;
+ const size_t aused = p->conf.forward_masks->used;
+ sock_addr addr;
+ /* C funcs inet_aton(), inet_pton() require '\0'-terminated IP str */
+ char addrstr[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
+ if (iplen >= sizeof(addrstr)) return 0;
+ memcpy(addrstr, ip, iplen);
+ addrstr[iplen] = '\0';
+
+ if (1 != sock_addr_inet_pton(&addr, addrstr, AF_INET, 0)
+ && 1 != sock_addr_inet_pton(&addr, addrstr, AF_INET6, 0)) return 0;
+
+ for (size_t i = 0; i < aused; ++i) {
+ if (sock_addr_is_addr_eq_bits(&addr, &addrs[i].addr, addrs[i].bits))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int is_connection_trusted(connection * const con, plugin_data *p)
+{
+ if (p->conf.forward_all) return (1 == p->conf.forward_all);
+ return is_proxy_trusted(p, CONST_BUF_LEN(con->dst_addr_buf));
+}
+
+/*
+ * Return last address of proxy that is not trusted.
+ * Do not accept "all" keyword here.
+ */
+static const char *last_not_in_array(array *a, plugin_data *p)
+{
+ int i;
+
+ for (i = a->used - 1; i >= 0; i--) {
+ data_string *ds = (data_string *)a->data[i];
+ if (!is_proxy_trusted(p, CONST_BUF_LEN(ds->value))) {
+ return ds->value->ptr;
+ }
+ }
+ return NULL;
+}
+
+static int mod_extforward_set_addr(server *srv, connection *con, plugin_data *p, const char *addr) {
+ sock_addr sock;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", addr);
+ }
+
+ sock.plain.sa_family = AF_UNSPEC;
+ if (1 != sock_addr_from_str_numeric(srv, &sock, addr)) return 0;
+ if (sock.plain.sa_family == AF_UNSPEC) return 0;
+
+ /* we found the remote address, modify current connection and save the old address */
+ if (hctx) {
+ if (hctx->saved_remote_addr_buf) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_extforward_uri_handler already patched this connection, resetting state");
+ }
+ con->dst_addr = hctx->saved_remote_addr;
+ buffer_free(con->dst_addr_buf);
+ con->dst_addr_buf = hctx->saved_remote_addr_buf;
+ hctx->saved_remote_addr_buf = NULL;
+ }
+ } else {
+ con->plugin_ctx[p->id] = hctx = handler_ctx_init();
+ }
+ /* save old address */
+ if (extforward_check_proxy) {
+ http_header_env_set(con, CONST_STR_LEN("_L_EXTFORWARD_ACTUAL_FOR"), CONST_BUF_LEN(con->dst_addr_buf));
+ }
+ hctx->saved_remote_addr = con->dst_addr;
+ hctx->saved_remote_addr_buf = con->dst_addr_buf;
+ /* patch connection address */
+ con->dst_addr = sock;
+ con->dst_addr_buf = buffer_init_string(addr);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "patching con->dst_addr_buf for the accesslog:", addr);
+ }
+
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP);
+
+ return 1;
+}
+
+static void mod_extforward_set_proto(server *srv, connection *con, const char *proto, size_t protolen) {
+ if (0 != protolen && !buffer_is_equal_caseless_string(con->uri.scheme, proto, protolen)) {
+ /* update scheme if X-Forwarded-Proto is set
+ * Limitations:
+ * - Only "http" or "https" are currently accepted since the request to lighttpd currently has to
+ * be HTTP/1.0 or HTTP/1.1 using http or https. If this is changed, then the scheme from this
+ * untrusted header must be checked to contain only alphanumeric characters, and to be a
+ * reasonable length, e.g. < 256 chars.
+ * - con->uri.scheme is not reset in mod_extforward_restore() but is currently not an issues since
+ * con->uri.scheme will be reset by next request. If a new module uses con->uri.scheme in the
+ * handle_request_done hook, then should evaluate if that module should use the forwarded value
+ * (probably) or the original value.
+ */
+ if (extforward_check_proxy) {
+ http_header_env_set(con, CONST_STR_LEN("_L_EXTFORWARD_ACTUAL_PROTO"), CONST_BUF_LEN(con->uri.scheme));
+ }
+ if (0 == buffer_caseless_compare(proto, protolen, CONST_STR_LEN("https"))) {
+ buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_SCHEME);
+ } else if (0 == buffer_caseless_compare(proto, protolen, CONST_STR_LEN("http"))) {
+ buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_SCHEME);
+ }
+ }
+}
+
+static handler_t mod_extforward_X_Forwarded_For(server *srv, connection *con, plugin_data *p, buffer *x_forwarded_for) {
+ /* build forward_array from forwarded data_string */
+ array *forward_array = extract_forward_array(x_forwarded_for);
+ const char *real_remote_addr = last_not_in_array(forward_array, p);
+ if (real_remote_addr != NULL) { /* parsed */
+ /* get scheme if X-Forwarded-Proto is set
+ * Limitations:
+ * - X-Forwarded-Proto may or may not be set by proxies, even if X-Forwarded-For is set
+ * - X-Forwarded-Proto may be a comma-separated list if there are multiple proxies,
+ * but the historical behavior of the code below only honored it if there was exactly one value
+ * (not done: walking backwards in X-Forwarded-Proto the same num of steps
+ * as in X-Forwarded-For to find proto set by last trusted proxy)
+ */
+ buffer *x_forwarded_proto = http_header_request_get(con, HTTP_HEADER_X_FORWARDED_PROTO, CONST_STR_LEN("X-Forwarded-Proto"));
+ if (mod_extforward_set_addr(srv, con, p, real_remote_addr) && NULL != x_forwarded_proto) {
+ mod_extforward_set_proto(srv, con, CONST_BUF_LEN(x_forwarded_proto));
+ }
+ }
+ array_free(forward_array);
+ return HANDLER_GO_ON;
+}
+
+static int find_end_quoted_string (const char * const s, int i) {
+ do {
+ ++i;
+ } while (s[i] != '"' && s[i] != '\0' && (s[i] != '\\' || s[++i] != '\0'));
+ return i;
+}
+
+static int find_next_semicolon_or_comma_or_eq (const char * const s, int i) {
+ for (; s[i] != '=' && s[i] != ';' && s[i] != ',' && s[i] != '\0'; ++i) {
+ if (s[i] == '"') {
+ i = find_end_quoted_string(s, i);
+ if (s[i] == '\0') return -1;
+ }
+ }
+ return i;
+}
+
+static int find_next_semicolon_or_comma (const char * const s, int i) {
+ for (; s[i] != ';' && s[i] != ',' && s[i] != '\0'; ++i) {
+ if (s[i] == '"') {
+ i = find_end_quoted_string(s, i);
+ if (s[i] == '\0') return -1;
+ }
+ }
+ return i;
+}
+
+static int buffer_backslash_unescape (buffer * const b) {
+ /* (future: might move to buffer.c) */
+ size_t j = 0;
+ size_t len = buffer_string_length(b);
+ char *p = memchr(b->ptr, '\\', len);
+
+ if (NULL == p) return 1; /*(nothing to do)*/
+
+ len -= (size_t)(p - b->ptr);
+ for (size_t i = 0; i < len; ++i) {
+ if (p[i] == '\\') {
+ if (++i == len) return 0; /*(invalid trailing backslash)*/
+ }
+ p[j++] = p[i];
+ }
+ buffer_string_set_length(b, (size_t)(p+j - b->ptr));
+ return 1;
+}
+
+static handler_t mod_extforward_Forwarded (server *srv, connection *con, plugin_data *p, buffer *forwarded) {
+ /* HTTP list need not consist of param=value tokens,
+ * but this routine expect such for HTTP Forwarded header
+ * Since info in each set of params is only used if from
+ * admin-specified trusted proxy:
+ * - invalid param=value tokens are ignored and skipped
+ * - not checking "for" exists in each set of params
+ * - not checking for duplicated params in each set of params
+ * - not checking canonical form of addr (also might be obfuscated)
+ * - obfuscated tokens permitted in chain, though end of trust is expected
+ * to be non-obfuscated IP for mod_extforward to masquerade as remote IP
+ * future: since (potentially) trusted proxies begin at end of string,
+ * it might be better to parse from end of string rather than parsing from
+ * beginning. Doing so would also allow reducing arbitrary param limit
+ * to number of params permitted per proxy.
+ */
+ char * const s = forwarded->ptr;
+ int i = 0, j = -1, v, vlen, k, klen;
+ int used = (int)buffer_string_length(forwarded);
+ int ofor = -1, oproto, ohost, oby, oremote_user;
+ int offsets[256];/*(~50 params is more than reasonably expected to handle)*/
+ while (i < used) {
+ while (s[i] == ' ' || s[i] == '\t') ++i;
+ if (s[i] == ';') { ++i; continue; }
+ if (s[i] == ',') {
+ if (j >= (int)(sizeof(offsets)/sizeof(int))) break;
+ offsets[++j] = -1; /*("offset" separating params from next proxy)*/
+ ++i;
+ continue;
+ }
+ if (s[i] == '\0') break;
+
+ k = i;
+ i = find_next_semicolon_or_comma_or_eq(s, i);
+ if (i < 0) {
+ /*(reject IP spoofing if attacker sets improper quoted-string)*/
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "invalid quoted-string in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ if (s[i] != '=') continue;
+ klen = i - k;
+ v = ++i;
+ i = find_next_semicolon_or_comma(s, i);
+ if (i < 0) {
+ /*(reject IP spoofing if attacker sets improper quoted-string)*/
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "invalid quoted-string in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ vlen = i - v; /* might be 0 */
+
+ /* have k, klen, v, vlen
+ * (might contain quoted string) (contents not validated or decoded)
+ * (might be repeated k)
+ */
+ if (0 == klen) continue; /* invalid k */
+ if (j >= (int)(sizeof(offsets)/sizeof(int))-4) break;
+ offsets[j+1] = k;
+ offsets[j+2] = klen;
+ offsets[j+3] = v;
+ offsets[j+4] = vlen;
+ j += 4;
+ }
+
+ if (j >= (int)(sizeof(offsets)/sizeof(int))-4) {
+ /* error processing Forwarded; too many params; fail closed */
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Too many params in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ if (-1 == j) return HANDLER_GO_ON; /* make no changes */
+ used = j+1;
+ offsets[used] = -1; /* mark end of last set of params */
+
+ while (j >= 4) { /*(param=value pairs)*/
+ if (-1 == offsets[j]) { --j; continue; }
+ do {
+ j -= 3; /*(k, klen, v, vlen come in sets of 4)*/
+ } while ((3 != offsets[j+1] /* 3 == sizeof("for")-1 */
+ || 0 != buffer_caseless_compare(s+offsets[j], 3, "for", 3))
+ && 0 != j-- && -1 != offsets[j]);
+ if (j < 0) break;
+ if (-1 == offsets[j]) { --j; continue; }
+
+ /* remove trailing spaces/tabs and double-quotes from string
+ * (note: not unescaping backslash escapes in quoted string) */
+ v = offsets[j+2];
+ vlen = v + offsets[j+3];
+ while (vlen > v && (s[vlen-1] == ' ' || s[vlen-1] == '\t')) --vlen;
+ if (vlen > v+1 && s[v] == '"' && s[vlen-1] == '"') {
+ offsets[j+2] = ++v;
+ --vlen;
+ if (s[v] == '[') {
+ /* remove "[]" surrounding IPv6, as well as (optional) port
+ * (assumes properly formatted IPv6 addr from trusted proxy) */
+ ++v;
+ do { --vlen; } while (vlen > v && s[vlen] != ']');
+ if (v == vlen) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Invalid IPv6 addr in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ }
+ else if (s[v] != '_' && s[v] != '/' && s[v] != 'u') {
+ /* remove (optional) port from non-obfuscated IPv4 */
+ for (klen=vlen, vlen=v; vlen < klen && s[vlen] != ':'; ++vlen) ;
+ }
+ offsets[j+2] = v;
+ }
+ offsets[j+3] = vlen - v;
+
+ /* obfuscated ipstr and obfuscated port are also accepted here, as
+ * is path to unix domain socket, but note that backslash escapes
+ * in quoted-string were not unescaped above. Also, if obfuscated
+ * identifiers are rotated by proxies as recommended by RFC, then
+ * maintaining list of trusted identifiers is non-trivial and is not
+ * attempted by this module. */
+
+ if (v != vlen) {
+ int trusted = is_proxy_trusted(p, s+v, vlen-v);
+
+ if (s[v] != '_' && s[v] != '/'
+ && (7 != (vlen - v) || 0 != memcmp(s+v, "unknown", 7))) {
+ ofor = j; /* save most recent non-obfuscated ipstr */
+ }
+
+ if (!trusted) break;
+ }
+
+ do { --j; } while (j > 0 && -1 != offsets[j]);
+ if (j <= 0) break;
+ --j;
+ }
+
+ if (-1 != ofor) {
+ /* C funcs getaddrinfo(), inet_addr() require '\0'-terminated IP str */
+ char *ipend = s+offsets[ofor+2]+offsets[ofor+3];
+ char c = *ipend;
+ int rc;
+ *ipend = '\0';
+ rc = mod_extforward_set_addr(srv, con, p, s+offsets[ofor+2]);
+ *ipend = c;
+ if (!rc) return HANDLER_GO_ON; /* invalid addr; make no changes */
+ }
+ else {
+ return HANDLER_GO_ON; /* make no changes */
+ }
+
+ /* parse out params associated with for=<ip> addr set above */
+ oproto = ohost = oby = oremote_user = -1;
+ j = ofor;
+ if (j > 0) { do { --j; } while (j > 0 && -1 != offsets[j]); }
+ if (-1 == offsets[j]) ++j;
+ if (j == ofor) j += 4;
+ for (; -1 != offsets[j]; j+=4) { /*(k, klen, v, vlen come in sets of 4)*/
+ switch (offsets[j+1]) {
+ #if 0
+ case 2:
+ if (0 == buffer_caseless_compare(s+offsets[j],2,"by",2))
+ oby = j;
+ break;
+ #endif
+ #if 0
+ /*(already handled above to find IP prior to earliest trusted proxy)*/
+ case 3:
+ if (0 == buffer_caseless_compare(s+offsets[j],3,"for",3))
+ ofor = j;
+ break;
+ #endif
+ case 4:
+ if (0 == buffer_caseless_compare(s+offsets[j],4,"host",4))
+ ohost = j;
+ break;
+ case 5:
+ if (0 == buffer_caseless_compare(s+offsets[j],5,"proto",5))
+ oproto = j;
+ break;
+ case 11:
+ if (0 == buffer_caseless_compare(s+offsets[j],11,"remote_user",11))
+ oremote_user = j;
+ break;
+ default:
+ break;
+ }
+ }
+ i = ++j;
+
+ if (-1 != oproto) {
+ /* remove trailing spaces/tabs, and double-quotes from proto
+ * (note: not unescaping backslash escapes in quoted string) */
+ v = offsets[oproto+2];
+ vlen = v + offsets[oproto+3];
+ while (vlen > v && (s[vlen-1] == ' ' || s[vlen-1] == '\t')) --vlen;
+ if (vlen > v+1 && s[v] == '"' && s[vlen-1] == '"') { ++v; --vlen; }
+ mod_extforward_set_proto(srv, con, s+v, vlen-v);
+ }
+
+ if (p->conf.opts & PROXY_FORWARDED_HOST) {
+ /* Limitations:
+ * - con->request.http_host is not reset in mod_extforward_restore()
+ * but is currently not an issues since con->request.http_host will be
+ * reset by next request. If a new module uses con->request.http_host
+ * in the handle_request_done hook, then should evaluate if that
+ * module should use the forwarded value (probably) or original value.
+ * - due to need to decode and unescape host=..., some extra work is
+ * done in the case where host matches current Host header.
+ * future: might add code to check if Host has actually changed or not
+ *
+ * note: change host after mod_extforward_set_proto() since that may
+ * affect scheme port used in http_request_host_policy() host
+ * normalization
+ */
+
+ /* find host param set by earliest trusted proxy in proxy chain
+ * (host might be changed anywhere along the chain) */
+ for (j = i; j < used && -1 == ohost; ) {
+ if (-1 == offsets[j]) { ++j; continue; }
+ if (4 == offsets[j+1]
+ && 0 == buffer_caseless_compare(s+offsets[j], 4, "host", 4))
+ ohost = j;
+ j += 4; /*(k, klen, v, vlen come in sets of 4)*/
+ }
+ if (-1 != ohost) {
+ if (extforward_check_proxy
+ && !buffer_string_is_empty(con->request.http_host)) {
+ http_header_env_set(con,
+ CONST_STR_LEN("_L_EXTFORWARD_ACTUAL_HOST"),
+ CONST_BUF_LEN(con->request.http_host));
+ }
+ /* remove trailing spaces/tabs, and double-quotes from host */
+ v = offsets[ohost+2];
+ vlen = v + offsets[ohost+3];
+ while (vlen > v && (s[vlen-1] == ' ' || s[vlen-1] == '\t')) --vlen;
+ if (vlen > v+1 && s[v] == '"' && s[vlen-1] == '"') {
+ ++v; --vlen;
+ buffer_copy_string_len(con->request.http_host, s+v, vlen-v);
+ if (!buffer_backslash_unescape(con->request.http_host)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "invalid host= value in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ }
+ else {
+ buffer_copy_string_len(con->request.http_host, s+v, vlen-v);
+ }
+
+ if (0 != http_request_host_policy(con, con->request.http_host,
+ con->uri.scheme)) {
+ /*(reject invalid chars in Host)*/
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "invalid host= value in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_HOST);
+ }
+ }
+
+ if (p->conf.opts & PROXY_FORWARDED_REMOTE_USER) {
+ /* find remote_user param set by closest proxy
+ * (auth may have been handled by any trusted proxy in proxy chain) */
+ for (j = i; j < used; ) {
+ if (-1 == offsets[j]) { ++j; continue; }
+ if (11 == offsets[j+1]
+ && 0==buffer_caseless_compare(s+offsets[j],11,"remote_user",11))
+ oremote_user = j;
+ j += 4; /*(k, klen, v, vlen come in sets of 4)*/
+ }
+ if (-1 != oremote_user) {
+ /* ???: should we also support param for auth_type ??? */
+ /* remove trailing spaces/tabs, and double-quotes from remote_user*/
+ v = offsets[oremote_user+2];
+ vlen = v + offsets[oremote_user+3];
+ while (vlen > v && (s[vlen-1] == ' ' || s[vlen-1] == '\t')) --vlen;
+ if (vlen > v+1 && s[v] == '"' && s[vlen-1] == '"') {
+ buffer *euser;
+ ++v; --vlen;
+ http_header_env_set(con,
+ CONST_STR_LEN("REMOTE_USER"), s+v, vlen-v);
+ euser = http_header_env_get(con, CONST_STR_LEN("REMOTE_USER"));
+ force_assert(NULL != euser);
+ if (!buffer_backslash_unescape(euser)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "invalid remote_user= value in Forwarded header");
+ con->http_status = 400; /* Bad Request */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ }
+ else {
+ http_header_env_set(con,
+ CONST_STR_LEN("REMOTE_USER"), s+v, vlen-v);
+ }
+ }
+ }
+
+ #if 0
+ if ((p->conf.opts & PROXY_FORWARDED_CREATE_XFF)
+ && NULL == http_header_request_get(con, HTTP_HEADER_X_FORWARDED_FOR, CONST_STR_LEN("X-Forwarded-For"))) {
+ /* create X-Forwarded-For if not present
+ * (and at least original connecting IP is a trusted proxy) */
+ buffer *xff = srv->tmp_buf;
+ buffer_clear(xff);
+ for (j = 0; j < used; ) {
+ if (-1 == offsets[j]) { ++j; continue; }
+ if (3 == offsets[j+1]
+ && 0 == buffer_caseless_compare(s+offsets[j], 3, "for", 3)) {
+ if (!buffer_string_is_empty(xff))
+ buffer_append_string_len(xff, CONST_STR_LEN(", "));
+ /* quoted-string, IPv6 brackets, and :port already removed */
+ v = offsets[j+2];
+ vlen = offsets[j+3];
+ buffer_append_string_len(xff, s+v, vlen);
+ if (s[v-1] != '=') { /*(must have been quoted-string)*/
+ char *x =
+ memchr(xff->ptr+buffer_string_length(xff)-vlen,'\\',vlen);
+ if (NULL != x) { /* backslash unescape in-place */
+ for (v = 0; x[v]; ++x) {
+ if (x[v] == '\\' && x[++v] == '\0')
+ break; /*(invalid trailing backslash)*/
+ *x = x[v];
+ }
+ buffer_string_set_length(xff, x - xff->ptr);
+ }
+ }
+ /* skip to next group; take first "for=..." in group
+ * (should be 0 or 1 "for=..." per group, but not trusted) */
+ do { j += 4; } while (-1 != offsets[j]);
+ ++j;
+ continue;
+ }
+ j += 4; /*(k, klen, v, vlen come in sets of 4)*/
+ }
+ http_header_request_set(con, HTTP_HEADER_X_FORWARDED_FOR, CONST_STR_LEN("X-Forwarded-For"), CONST_BUF_LEN(xff));
+ }
+ #endif
+
+ return HANDLER_GO_ON;
+}
+
+URIHANDLER_FUNC(mod_extforward_uri_handler) {
+ plugin_data *p = p_d;
+ buffer *forwarded = NULL;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ int is_forwarded_header = 0;
+
+ mod_extforward_patch_connection(srv, con, p);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_extforward_uri_handler called");
+ }
+
+ if (p->conf.hap_PROXY_ssl_client_verify) {
+ data_string *ds;
+ if (NULL != hctx && hctx->ssl_client_verify && NULL != hctx->env
+ && NULL != (ds = (data_string *)array_get_element(hctx->env, "SSL_CLIENT_S_DN_CN"))) {
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_STR_LEN("SUCCESS"));
+ http_header_env_set(con,
+ CONST_STR_LEN("REMOTE_USER"),
+ CONST_BUF_LEN(ds->value));
+ http_header_env_set(con,
+ CONST_STR_LEN("AUTH_TYPE"),
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"));
+ } else {
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_STR_LEN("NONE"));
+ }
+ }
+
+ for (size_t k = 0; k < p->conf.headers->used && NULL == forwarded; ++k) {
+ buffer *hdr = ((data_string *)p->conf.headers->data[k])->value;
+ forwarded = http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(hdr));
+ if (forwarded) {
+ is_forwarded_header = buffer_is_equal_caseless_string(hdr, CONST_STR_LEN("Forwarded"));
+ break;
+ }
+ }
+ if (NULL == forwarded) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "no forward header found, skipping");
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+ /* if the remote ip itself is not trusted, then do nothing */
+ if (!is_connection_trusted(con, p)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "remote address", con->dst_addr_buf, "is NOT a trusted proxy, skipping");
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+ if (is_forwarded_header) {
+ return mod_extforward_Forwarded(srv, con, p, forwarded);
+ }
+
+ return mod_extforward_X_Forwarded_For(srv, con, p, forwarded);
+}
+
+
+CONNECTION_FUNC(mod_extforward_handle_request_env) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ UNUSED(srv);
+ if (NULL == hctx || NULL == hctx->env) return HANDLER_GO_ON;
+ for (size_t i=0; i < hctx->env->used; ++i) {
+ /* note: replaces values which may have been set by mod_openssl
+ * (when mod_extforward is listed after mod_openssl in server.modules)*/
+ data_string *ds = (data_string *)hctx->env->data[i];
+ http_header_env_set(con,
+ CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
+ }
+ return HANDLER_GO_ON;
+}
+
+
+CONNECTION_FUNC(mod_extforward_restore) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (!hctx) return HANDLER_GO_ON;
+
+ if (NULL != hctx->saved_network_read) {
+ con->network_read = hctx->saved_network_read;
+ hctx->saved_network_read = NULL;
+ }
+
+ if (NULL != hctx->saved_remote_addr_buf) {
+ con->dst_addr = hctx->saved_remote_addr;
+ buffer_free(con->dst_addr_buf);
+ con->dst_addr_buf = hctx->saved_remote_addr_buf;
+ hctx->saved_remote_addr_buf = NULL;
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP);
+ }
+
+ if (NULL == hctx->env) {
+ handler_ctx_free(hctx);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+CONNECTION_FUNC(mod_extforward_handle_con_close)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ UNUSED(srv);
+ if (NULL != hctx) {
+ if (NULL != hctx->saved_network_read) {
+ con->network_read = hctx->saved_network_read;
+ }
+ if (NULL != hctx->saved_remote_addr_buf) {
+ con->dst_addr = hctx->saved_remote_addr;
+ buffer_free(con->dst_addr_buf);
+ con->dst_addr_buf = hctx->saved_remote_addr_buf;
+ }
+ if (NULL != hctx->env) {
+ array_free(hctx->env);
+ }
+ handler_ctx_free(hctx);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static int mod_extforward_network_read (server *srv, connection *con, chunkqueue *cq, off_t max_bytes);
+
+CONNECTION_FUNC(mod_extforward_handle_con_accept)
+{
+ plugin_data *p = p_d;
+ mod_extforward_patch_connection(srv, con, p);
+ if (!p->conf.hap_PROXY) return HANDLER_GO_ON;
+ if (is_connection_trusted(con, p)) {
+ handler_ctx *hctx = handler_ctx_init();
+ con->plugin_ctx[p->id] = hctx;
+ hctx->saved_network_read = con->network_read;
+ con->network_read = mod_extforward_network_read;
+ }
+ else {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "remote address", con->dst_addr_buf,
+ "is NOT a trusted proxy, skipping");
+ }
+ }
+ return HANDLER_GO_ON;
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_extforward_plugin_init(plugin *p);
+int mod_extforward_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("extforward");
+
+ p->init = mod_extforward_init;
+ p->handle_connection_accept = mod_extforward_handle_con_accept;
+ p->handle_uri_raw = mod_extforward_uri_handler;
+ p->handle_request_env = mod_extforward_handle_request_env;
+ p->handle_request_done = mod_extforward_restore;
+ p->connection_reset = mod_extforward_restore;
+ p->handle_connection_close = mod_extforward_handle_con_close;
+ p->set_defaults = mod_extforward_set_defaults;
+ p->cleanup = mod_extforward_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
+
+
+
+/* Modified from:
+ * http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
+ *
+9. Sample code
+
+The code below is an example of how a receiver may deal with both versions of
+the protocol header for TCP over IPv4 or IPv6. The function is supposed to be
+called upon a read event. Addresses may be directly copied into their final
+memory location since they're transported in network byte order. The sending
+side is even simpler and can easily be deduced from this sample code.
+ *
+ */
+
+union hap_PROXY_hdr {
+ struct {
+ char line[108];
+ } v1;
+ struct {
+ uint8_t sig[12];
+ uint8_t ver_cmd;
+ uint8_t fam;
+ uint16_t len;
+ union {
+ struct { /* for TCP/UDP over IPv4, len = 12 */
+ uint32_t src_addr;
+ uint32_t dst_addr;
+ uint16_t src_port;
+ uint16_t dst_port;
+ } ip4;
+ struct { /* for TCP/UDP over IPv6, len = 36 */
+ uint8_t src_addr[16];
+ uint8_t dst_addr[16];
+ uint16_t src_port;
+ uint16_t dst_port;
+ } ip6;
+ struct { /* for AF_UNIX sockets, len = 216 */
+ uint8_t src_addr[108];
+ uint8_t dst_addr[108];
+ } unx;
+ } addr;
+ } v2;
+};
+
+/*
+If the length specified in the PROXY protocol header indicates that additional
+bytes are part of the header beyond the address information, a receiver may
+choose to skip over and ignore those bytes, or attempt to interpret those
+bytes.
+
+The information in those bytes will be arranged in Type-Length-Value (TLV
+vectors) in the following format. The first byte is the Type of the vector.
+The second two bytes represent the length in bytes of the value (not included
+the Type and Length bytes), and following the length field is the number of
+bytes specified by the length.
+ */
+struct pp2_tlv {
+ uint8_t type;
+ uint8_t length_hi;
+ uint8_t length_lo;
+ /*uint8_t value[0];*//* C99 zero-length array */
+};
+
+/*
+The following types have already been registered for the <type> field :
+ */
+
+#define PP2_TYPE_ALPN 0x01
+#define PP2_TYPE_AUTHORITY 0x02
+#define PP2_TYPE_CRC32C 0x03
+#define PP2_TYPE_NOOP 0x04
+#define PP2_TYPE_SSL 0x20
+#define PP2_SUBTYPE_SSL_VERSION 0x21
+#define PP2_SUBTYPE_SSL_CN 0x22
+#define PP2_SUBTYPE_SSL_CIPHER 0x23
+#define PP2_SUBTYPE_SSL_SIG_ALG 0x24
+#define PP2_SUBTYPE_SSL_KEY_ALG 0x25
+#define PP2_TYPE_NETNS 0x30
+
+/*
+For the type PP2_TYPE_SSL, the value is itselv a defined like this :
+ */
+
+struct pp2_tlv_ssl {
+ uint8_t client;
+ uint32_t verify;
+ /*struct pp2_tlv sub_tlv[0];*//* C99 zero-length array */
+};
+
+/*
+And the <client> field is made of a bit field from the following values,
+indicating which element is present :
+ */
+
+#define PP2_CLIENT_SSL 0x01
+#define PP2_CLIENT_CERT_CONN 0x02
+#define PP2_CLIENT_CERT_SESS 0x04
+
+
+
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+/* returns 0 if needs to poll, <0 upon error or >0 is protocol vers (success) */
+static int hap_PROXY_recv (const int fd, union hap_PROXY_hdr * const hdr, const int family, const int so_type)
+{
+ static const char v2sig[12] =
+ "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
+
+ ssize_t ret;
+ size_t sz;
+ int ver;
+
+ do {
+ ret = recv(fd, hdr, sizeof(*hdr), MSG_PEEK|MSG_DONTWAIT|MSG_NOSIGNAL);
+ } while (-1 == ret && errno == EINTR);
+
+ if (-1 == ret)
+ return (errno == EAGAIN
+ #ifdef EWOULDBLOCK
+ #if EAGAIN != EWOULDBLOCK
+ || errno == EWOULDBLOCK
+ #endif
+ #endif
+ ) ? 0 : -1;
+
+ if (ret >= 16 && 0 == memcmp(&hdr->v2, v2sig, 12)
+ && (hdr->v2.ver_cmd & 0xF0) == 0x20) {
+ ver = 2;
+ sz = 16 + (size_t)ntohs(hdr->v2.len);
+ if ((size_t)ret < sz)
+ return -2; /* truncated or too large header */
+
+ switch (hdr->v2.ver_cmd & 0xF) {
+ case 0x01: break; /* PROXY command */
+ case 0x00: break; /* LOCAL command */
+ default: return -2; /* not a supported command */
+ }
+ }
+ else if (ret >= 8 && 0 == memcmp(hdr->v1.line, "PROXY", 5)) {
+ const char *end = memchr(hdr->v1.line, '\r', ret - 1);
+ if (!end || end[1] != '\n')
+ return -2; /* partial or invalid header */
+ ver = 1;
+ sz = (size_t)(end + 2 - hdr->v1.line); /* skip header + CRLF */
+ }
+ else {
+ /* Wrong protocol */
+ return -2;
+ }
+
+ /* we need to consume the appropriate amount of data from the socket
+ * (overwrites existing contents of hdr with same data) */
+ UNUSED(family);
+ UNUSED(so_type);
+ do {
+ #if defined(MSG_TRUNC) && defined(__linux__)
+ if ((family==AF_INET || family==AF_INET6) && so_type == SOCK_STREAM) {
+ ret = recv(fd, hdr, sz, MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL);
+ if (ret >= 0 || errno != EINVAL) continue;
+ }
+ #endif
+ ret = recv(fd, hdr, sz, MSG_DONTWAIT|MSG_NOSIGNAL);
+ } while (-1 == ret && errno == EINTR);
+ if (ret < 0) return -1;
+ if (ret != (ssize_t)sz) {
+ errno = EIO; /*(partial read; valid but unexpected; not handled)*/
+ return -1;
+ }
+ if (1 == ver) hdr->v1.line[sz-2] = '\0'; /*terminate str to ease parsing*/
+ return ver;
+}
+
+
+static int mod_extforward_hap_PROXY_v1 (connection * const con,
+ union hap_PROXY_hdr * const hdr)
+{
+ #ifdef __COVERITY__
+ __coverity_tainted_data_sink__(hdr);
+ #endif
+
+ /* samples
+ * "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"
+ * "PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n"
+ * "PROXY UNKNOWN\r\n"
+ * "PROXY UNKNOWN ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n"
+ */
+ char *s = hdr->v1.line + sizeof("PROXY")-1; /*checked in hap_PROXY_recv()*/
+ char *src_addr, *dst_addr, *src_port, *dst_port, *e;
+ int family;
+ long src_lport, dst_lport;
+ if (*s != ' ') return -1;
+ ++s;
+ if (s[0] == 'T' && s[1] == 'C' && s[2] == 'P' && s[4] == ' ') {
+ if (s[3] == '4') {
+ family = AF_INET;
+ } else if (s[3] == '6') {
+ family = AF_INET6;
+ }
+ else {
+ return -1;
+ }
+ s += 5;
+ }
+ else if (0 == memcmp(s, "UNKNOWN", sizeof("UNKNOWN")-1)
+ && (s[7] == '\0' || s[7] == ' ')) {
+ return 0; /* keep local connection address */
+ }
+ else {
+ return -1;
+ }
+
+ /*(strsep() should be fairly portable, but is not standard)*/
+ src_addr = s;
+ dst_addr = strchr(src_addr, ' ');
+ if (NULL == dst_addr) return -1;
+ *dst_addr++ = '\0';
+ src_port = strchr(dst_addr, ' ');
+ if (NULL == src_port) return -1;
+ *src_port++ = '\0';
+ dst_port = strchr(src_port, ' ');
+ if (NULL == dst_port) return -1;
+ *dst_port++ = '\0';
+
+ src_lport = strtol(src_port, &e, 10);
+ if (src_lport <= 0 || src_lport > USHRT_MAX || *e != '\0') return -1;
+ dst_lport = strtol(dst_port, &e, 10);
+ if (dst_lport <= 0 || dst_lport > USHRT_MAX || *e != '\0') return -1;
+
+ if (1 != sock_addr_inet_pton(&con->dst_addr,
+ src_addr, family, (unsigned short)src_lport))
+ return -1;
+ /* Forwarded by=... could be saved here.
+ * (see additional comments in mod_extforward_hap_PROXY_v2()) */
+
+ /* re-parse addr to string to normalize
+ * (instead of trusting PROXY to provide canonicalized src_addr string)
+ * (should prefer PROXY v2 protocol if concerned about performance) */
+ sock_addr_inet_ntop_copy_buffer(con->dst_addr_buf, &con->dst_addr);
+
+ return 0;
+}
+
+
+static int mod_extforward_hap_PROXY_v2 (connection * const con,
+ union hap_PROXY_hdr * const hdr)
+{
+ #ifdef __COVERITY__
+ __coverity_tainted_data_sink__(hdr);
+ #endif
+
+ /* If HAProxy-PROXY protocol used, then lighttpd acts as transparent proxy,
+ * masquerading as servicing the client IP provided in by HAProxy-PROXY hdr.
+ * The connecting con->dst_addr and con->dst_addr_buf are not saved here,
+ * so that info is lost unless getsockname() and getpeername() are used.
+ * One result is that mod_proxy will use the masqueraded IP instead of the
+ * actual IP when updated Forwarded and X-Forwarded-For (but if actual
+ * connection IPs needed, better to save the info here rather than use
+ * syscalls to retrieve the info later).
+ * (Exception: con->dst_addr can be further changed if mod_extforward parses
+ * Forwaded or X-Forwarded-For request headers later, after request headers
+ * have been received.)
+ */
+
+ /* Forwarded by=... could be saved here. The by param is for backends to be
+ * able to construct URIs for that interface (interface on server which
+ * received request and made PROXY connection here), though that server
+ * should provide that information in updated Forwarded or X-Forwarded-For
+ * HTTP headers */
+ /*struct sockaddr_storage by;*/
+
+ /* Addresses provided by HAProxy-PROXY protocol are in network byte order.
+ * Note: addr info is not validated, so do not accept HAProxy-PROXY
+ * protocol from untrusted servers. For example, untrusted servers from
+ * which HAProxy-PROXY protocol is accepted (don't do that) could pretend
+ * to be from the internal network and might thereby bypass security policy.
+ */
+
+ /* (Clear con->dst_addr with memset() in case actual and proxies IPs
+ * are different domains, e.g. one is IPv4 and the other is IPv6) */
+
+ struct pp2_tlv *tlv;
+ uint32_t sz = ntohs(hdr->v2.len);
+ uint32_t len = 0;
+
+ switch (hdr->v2.ver_cmd & 0xF) {
+ case 0x01: break; /* PROXY command */
+ case 0x00: return 0;/* LOCAL command; keep local connection address */
+ default: return -1;/* should not happen; validated in hap_PROXY_recv()*/
+ }
+
+ /* PROXY command */
+
+ switch (hdr->v2.fam) {
+ case 0x11: /* TCPv4 */
+ sock_addr_assign(&con->dst_addr, AF_INET, hdr->v2.addr.ip4.src_port,
+ &hdr->v2.addr.ip4.src_addr);
+ sock_addr_inet_ntop_copy_buffer(con->dst_addr_buf, &con->dst_addr);
+ #if 0
+ ((struct sockaddr_in *)&by)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&by)->sin_addr.s_addr =
+ hdr->v2.addr.ip4.dst_addr;
+ ((struct sockaddr_in *)&by)->sin_port =
+ hdr->v2.addr.ip4.dst_port;
+ #endif
+ len = (uint32_t)sizeof(hdr->v2.addr.ip4);
+ break;
+ #ifdef HAVE_IPV6
+ case 0x21: /* TCPv6 */
+ sock_addr_assign(&con->dst_addr, AF_INET6, hdr->v2.addr.ip6.src_port,
+ &hdr->v2.addr.ip6.src_addr);
+ sock_addr_inet_ntop_copy_buffer(con->dst_addr_buf, &con->dst_addr);
+ #if 0
+ ((struct sockaddr_in6 *)&by)->sin6_family = AF_INET6;
+ memcpy(&((struct sockaddr_in6 *)&by)->sin6_addr,
+ hdr->v2.addr.ip6.dst_addr, 16);
+ ((struct sockaddr_in6 *)&by)->sin6_port =
+ hdr->v2.addr.ip6.dst_port;
+ #endif
+ len = (uint32_t)sizeof(hdr->v2.addr.ip6);
+ break;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case 0x31: /* UNIX domain socket */
+ {
+ char *src_addr = (char *)hdr->v2.addr.unx.src_addr;
+ char *z = memchr(src_addr, '\0', UNIX_PATH_MAX);
+ if (NULL == z) return -1; /* invalid addr; too long */
+ len = (uint32_t)(z - src_addr + 1); /*(+1 for '\0')*/
+ sock_addr_assign(&con->dst_addr, AF_UNIX, 0, src_addr);
+ buffer_copy_string_len(con->dst_addr_buf, src_addr, len);
+ }
+ #if 0 /*(dst_addr should be identical to src_addr for AF_UNIX)*/
+ ((struct sockaddr_un *)&by)->sun_family = AF_UNIX;
+ memcpy(&((struct sockaddr_un *)&by)->sun_path,
+ hdr->v2.addr.unx.dst_addr, 108);
+ #endif
+ len = (uint32_t)sizeof(hdr->v2.addr.unx);
+ break;
+ #endif
+ default: /* keep local connection address; unsupported protocol */
+ return 0;
+ }
+
+ /* (optional) Type-Length-Value (TLV vectors) follow addresses */
+
+ tlv = (struct pp2_tlv *)((char *)hdr + 16);
+ for (sz -= len, len -= 3; sz >= 3; sz -= 3 + len) {
+ tlv = (struct pp2_tlv *)((char *)tlv + 3 + len);
+ len = ((uint32_t)tlv->length_hi << 8) | tlv->length_lo;
+ if (3 + len > sz) break; /*(invalid TLV)*/
+ switch (tlv->type) {
+ #if 0 /*(not implemented here)*/
+ case PP2_TYPE_ALPN:
+ case PP2_TYPE_AUTHORITY:
+ case PP2_TYPE_CRC32C:
+ #endif
+ case PP2_TYPE_SSL: {
+ static const uint32_t zero = 0;
+ handler_ctx *hctx =
+ con->plugin_ctx[mod_extforward_plugin_data_singleton->id];
+ struct pp2_tlv_ssl *tlv_ssl =
+ (struct pp2_tlv_ssl *)(void *)((char *)tlv+3);
+ struct pp2_tlv *subtlv = tlv;
+ if (tlv_ssl->client & PP2_CLIENT_SSL) {
+ buffer_copy_string_len(con->proto, CONST_STR_LEN("https"));
+ }
+ if ((tlv_ssl->client & (PP2_CLIENT_CERT_CONN|PP2_CLIENT_CERT_SESS))
+ && 0 == memcmp(&tlv_ssl->verify, &zero, 4)) { /* misaligned */
+ hctx->ssl_client_verify = 1;
+ }
+ for (uint32_t subsz = len-5, n = 5; subsz >= 3; subsz -= 3 + n) {
+ subtlv = (struct pp2_tlv *)((char *)subtlv + 3 + n);
+ n = ((uint32_t)subtlv->length_hi << 8) | subtlv->length_lo;
+ if (3 + n > subsz) break; /*(invalid TLV)*/
+ if (NULL == hctx->env) hctx->env = array_init();
+ switch (subtlv->type) {
+ case PP2_SUBTYPE_SSL_VERSION:
+ array_set_key_value(hctx->env,
+ CONST_STR_LEN("SSL_PROTOCOL"),
+ (char *)subtlv+3, n);
+ break;
+ case PP2_SUBTYPE_SSL_CN:
+ /* (tlv_ssl->client & PP2_CLIENT_CERT_CONN)
+ * or
+ * (tlv_ssl->client & PP2_CLIENT_CERT_SESS) */
+ array_set_key_value(hctx->env,
+ CONST_STR_LEN("SSL_CLIENT_S_DN_CN"),
+ (char *)subtlv+3, n);
+ break;
+ case PP2_SUBTYPE_SSL_CIPHER:
+ array_set_key_value(hctx->env,
+ CONST_STR_LEN("SSL_CIPHER"),
+ (char *)subtlv+3, n);
+ break;
+ case PP2_SUBTYPE_SSL_SIG_ALG:
+ array_set_key_value(hctx->env,
+ CONST_STR_LEN("SSL_SERVER_A_SIG"),
+ (char *)subtlv+3, n);
+ break;
+ case PP2_SUBTYPE_SSL_KEY_ALG:
+ array_set_key_value(hctx->env,
+ CONST_STR_LEN("SSL_SERVER_A_KEY"),
+ (char *)subtlv+3, n);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ #if 0 /*(not implemented here)*/
+ case PP2_TYPE_NETNS:
+ #endif
+ /*case PP2_TYPE_NOOP:*//* no-op */
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static int mod_extforward_network_read (server *srv, connection *con,
+ chunkqueue *cq, off_t max_bytes)
+{
+ /* XXX: when using hap-PROXY protocol, currently avoid overhead of setting
+ * _L_ environment variables for mod_proxy to accurately set Forwarded hdr
+ * In the future, might add config switch to enable doing this extra work */
+
+ union hap_PROXY_hdr hdr;
+ int rc = hap_PROXY_recv(con->fd, &hdr,
+ con->dst_addr.plain.sa_family, SOCK_STREAM);
+ switch (rc) {
+ case 2: rc = mod_extforward_hap_PROXY_v2(con, &hdr); break;
+ case 1: rc = mod_extforward_hap_PROXY_v1(con, &hdr); break;
+ case 0: return 0; /*(errno == EAGAIN || errno == EWOULDBLOCK)*/
+ case -1: log_error_write(srv, __FILE__, __LINE__, "ss",
+ "hap-PROXY recv()", strerror(errno));
+ rc = -1; break;
+ case -2: log_error_write(srv, __FILE__, __LINE__, "s",
+ "hap-PROXY proto received "
+ "invalid/unsupported request");
+ /* fall through */
+ default: rc = -1; break;
+ }
+
+ mod_extforward_restore(srv, con, mod_extforward_plugin_data_singleton);
+ return (0 == rc) ? con->network_read(srv, con, cq, max_bytes) : rc;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_fastcgi.c b/data/lighttpd/lighttpd-1.4.53/src/mod_fastcgi.c
new file mode 100644
index 000000000..901b0b2c1
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_fastcgi.c
@@ -0,0 +1,542 @@
+#include "first.h"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gw_backend.h"
+typedef gw_plugin_config plugin_config;
+typedef gw_plugin_data plugin_data;
+typedef gw_handler_ctx handler_ctx;
+
+#include "base.h"
+#include "buffer.h"
+#include "fdevent.h"
+#include "http_chunk.h"
+#include "log.h"
+#include "status_counter.h"
+
+#ifdef HAVE_FASTCGI_FASTCGI_H
+# include <fastcgi/fastcgi.h>
+#else
+# ifdef HAVE_FASTCGI_H
+# include <fastcgi.h>
+# else
+# include "fastcgi.h"
+# endif
+#endif /* HAVE_FASTCGI_FASTCGI_H */
+
+#if GW_RESPONDER != FCGI_RESPONDER
+#error "mismatched defines: (GW_RESPONDER != FCGI_RESPONDER)"
+#endif
+#if GW_AUTHORIZER != FCGI_AUTHORIZER
+#error "mismatched defines: (GW_AUTHORIZER != FCGI_AUTHORIZER)"
+#endif
+#if GW_FILTER != FCGI_FILTER
+#error "mismatched defines: (GW_FILTER != FCGI_FILTER)"
+#endif
+
+SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ plugin_data *p = p_d;
+ data_unset *du;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "fastcgi.debug", NULL, T_CONFIG_INT , T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "fastcgi.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+ force_assert(p->config_storage);
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ force_assert(s);
+ s->exts = NULL;
+ s->exts_auth = NULL;
+ s->exts_resp = NULL;
+ s->debug = 0;
+ s->ext_mapping = array_init();
+
+ cv[0].destination = s->exts; /* not used; T_CONFIG_LOCAL */
+ cv[1].destination = &(s->debug);
+ cv[2].destination = s->ext_mapping;
+ cv[3].destination = NULL; /* not used; T_CONFIG_LOCAL */
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "fastcgi.server");
+ if (!gw_set_defaults_backend(srv, p, du, i, 0)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "fastcgi.balance");
+ if (!gw_set_defaults_balance(srv, s, du)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static int fcgi_env_add(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
+ buffer *env = venv;
+ size_t len;
+ char len_enc[8];
+ size_t len_enc_len = 0;
+ char *dst;
+
+ if (!key || !val) return -1;
+
+ len = key_len + val_len;
+
+ len += key_len > 127 ? 4 : 1;
+ len += val_len > 127 ? 4 : 1;
+
+ if (buffer_string_length(env) + len >= FCGI_MAX_LENGTH + sizeof(FCGI_BeginRequestRecord) + sizeof(FCGI_Header)) {
+ /**
+ * we can't append more headers, ignore it
+ */
+ return -1;
+ }
+
+ /**
+ * field length can be 31bit max
+ *
+ * HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit
+ */
+ force_assert(key_len < 0x7fffffffu);
+ force_assert(val_len < 0x7fffffffu);
+
+ if (buffer_string_space(env) < len) {
+ size_t extend = env->size * 2 - buffer_string_length(env);
+ extend = extend > len ? extend : len + 4095;
+ buffer_string_prepare_append(env, extend);
+ }
+
+ if (key_len > 127) {
+ len_enc[len_enc_len++] = ((key_len >> 24) & 0xff) | 0x80;
+ len_enc[len_enc_len++] = (key_len >> 16) & 0xff;
+ len_enc[len_enc_len++] = (key_len >> 8) & 0xff;
+ len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
+ } else {
+ len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
+ }
+
+ if (val_len > 127) {
+ len_enc[len_enc_len++] = ((val_len >> 24) & 0xff) | 0x80;
+ len_enc[len_enc_len++] = (val_len >> 16) & 0xff;
+ len_enc[len_enc_len++] = (val_len >> 8) & 0xff;
+ len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
+ } else {
+ len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
+ }
+
+ dst = buffer_string_prepare_append(env, len);
+ memcpy(dst, len_enc, len_enc_len);
+ memcpy(dst + len_enc_len, key, key_len);
+ memcpy(dst + len_enc_len + key_len, val, val_len);
+ buffer_commit(env, len);
+
+ return 0;
+}
+
+static void fcgi_header(FCGI_Header * header, unsigned char type, int request_id, int contentLength, unsigned char paddingLength) {
+ force_assert(contentLength <= FCGI_MAX_LENGTH);
+
+ header->version = FCGI_VERSION_1;
+ header->type = type;
+ header->requestIdB0 = request_id & 0xff;
+ header->requestIdB1 = (request_id >> 8) & 0xff;
+ header->contentLengthB0 = contentLength & 0xff;
+ header->contentLengthB1 = (contentLength >> 8) & 0xff;
+ header->paddingLength = paddingLength;
+ header->reserved = 0;
+}
+
+static handler_t fcgi_stdin_append(server *srv, handler_ctx *hctx) {
+ FCGI_Header header;
+ connection *con = hctx->remote_conn;
+ chunkqueue *req_cq = con->request_content_queue;
+ off_t offset, weWant;
+ const off_t req_cqlen = req_cq->bytes_in - req_cq->bytes_out;
+ int request_id = hctx->request_id;
+ UNUSED(srv);
+
+ /* something to send ? */
+ for (offset = 0; offset != req_cqlen; offset += weWant) {
+ weWant = req_cqlen - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cqlen - offset;
+
+ if (-1 != hctx->wb_reqlen) {
+ if (hctx->wb_reqlen >= 0) {
+ hctx->wb_reqlen += sizeof(header);
+ } else {
+ hctx->wb_reqlen -= sizeof(header);
+ }
+ }
+
+ fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
+ (chunkqueue_is_empty(hctx->wb) || hctx->wb->first->type == MEM_CHUNK) /* else FILE_CHUNK for temp file */
+ ? chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header))
+ : chunkqueue_append_mem_min(hctx->wb, (const char *)&header, sizeof(header));
+ chunkqueue_steal(hctx->wb, req_cq, weWant);
+ /*(hctx->wb_reqlen already includes content_length)*/
+ }
+
+ if (hctx->wb->bytes_in == hctx->wb_reqlen) {
+ /* terminate STDIN */
+ /* (future: must defer ending FCGI_STDIN
+ * if might later upgrade protocols
+ * and then have more data to send) */
+ fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
+ chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header));
+ hctx->wb_reqlen += (int)sizeof(header);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t fcgi_create_env(server *srv, handler_ctx *hctx) {
+ FCGI_BeginRequestRecord beginRecord;
+ FCGI_Header header;
+ int request_id;
+
+ gw_host *host = hctx->host;
+ connection *con = hctx->remote_conn;
+
+ http_cgi_opts opts = {
+ (hctx->gw_mode == FCGI_AUTHORIZER),
+ host->break_scriptfilename_for_php,
+ host->docroot,
+ host->strip_request_uri
+ };
+
+ size_t rsz = (size_t)(con->read_queue->bytes_out - hctx->wb->bytes_in);
+ buffer * const b = chunkqueue_prepend_buffer_open_sz(hctx->wb, rsz < 65536 ? rsz : con->header_len);
+
+ /* send FCGI_BEGIN_REQUEST */
+
+ if (hctx->request_id == 0) {
+ hctx->request_id = 1; /* always use id 1 as we don't use multiplexing */
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "fcgi-request is already in use:", hctx->request_id);
+ }
+ request_id = hctx->request_id;
+
+ fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
+ beginRecord.body.roleB0 = hctx->gw_mode;
+ beginRecord.body.roleB1 = 0;
+ beginRecord.body.flags = 0;
+ memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
+
+ buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
+ fcgi_header(&header, FCGI_PARAMS, request_id, 0, 0); /*(set aside space to fill in later)*/
+ buffer_append_string_len(b, (const char *)&header, sizeof(header));
+
+ /* send FCGI_PARAMS */
+
+ if (0 != http_cgi_headers(srv, con, &opts, fcgi_env_add, b)) {
+ con->http_status = 400;
+ con->mode = DIRECT;
+ buffer_clear(b);
+ chunkqueue_remove_finished_chunks(hctx->wb);
+ return HANDLER_FINISHED;
+ } else {
+ fcgi_header(&(header), FCGI_PARAMS, request_id,
+ buffer_string_length(b) - sizeof(FCGI_BeginRequestRecord) - sizeof(FCGI_Header), 0);
+ memcpy(b->ptr+sizeof(FCGI_BeginRequestRecord), (const char *)&header, sizeof(header));
+
+ fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
+ buffer_append_string_len(b, (const char *)&header, sizeof(header));
+
+ hctx->wb_reqlen = buffer_string_length(b);
+ chunkqueue_prepend_buffer_commit(hctx->wb);
+ }
+
+ if (con->request.content_length) {
+ /*chunkqueue_append_chunkqueue(hctx->wb, con->request_content_queue);*/
+ if (con->request.content_length > 0)
+ hctx->wb_reqlen += con->request.content_length;/* (eventual) (minimal) total request size, not necessarily including all fcgi_headers around content length yet */
+ else /* as-yet-unknown total request size (Transfer-Encoding: chunked)*/
+ hctx->wb_reqlen = -hctx->wb_reqlen;
+ }
+ fcgi_stdin_append(srv, hctx);
+
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
+ return HANDLER_GO_ON;
+}
+
+typedef struct {
+ unsigned int len;
+ int type;
+ int padding;
+ int request_id;
+} fastcgi_response_packet;
+
+static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {
+ FCGI_Header header;
+ size_t toread = sizeof(FCGI_Header), flen = 0;
+ off_t rblen = chunkqueue_length(hctx->rb);
+ if (rblen < (off_t)sizeof(FCGI_Header)) {
+ /* no header */
+ if (hctx->conf.debug && 0 != rblen) {
+ log_error_write(srv, __FILE__, __LINE__, "sosds", "FastCGI: header too small:", rblen, "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");
+ }
+ return -1;
+ }
+
+ /* get at least the FastCGI header */
+ for (chunk *c = hctx->rb->first; c; c = c->next) {
+ size_t weHave = buffer_string_length(c->mem) - c->offset;
+ if (weHave >= toread) {
+ memcpy((char *)&header + flen, c->mem->ptr + c->offset, toread);
+ break;
+ }
+
+ memcpy((char *)&header + flen, c->mem->ptr + c->offset, weHave);
+ flen += weHave;
+ toread -= weHave;
+ }
+
+ /* we have at least a header, now check how much we have to fetch */
+ packet->len = (header.contentLengthB0 | (header.contentLengthB1 << 8)) + header.paddingLength;
+ packet->request_id = (header.requestIdB0 | (header.requestIdB1 << 8));
+ packet->type = header.type;
+ packet->padding = header.paddingLength;
+
+ if (packet->len > (unsigned int)rblen-sizeof(FCGI_Header)) {
+ return -1; /* we didn't get the full packet */
+ }
+
+ chunkqueue_mark_written(hctx->rb, sizeof(FCGI_Header));
+ return 0;
+}
+
+static void fastcgi_get_packet_body(buffer *b, handler_ctx *hctx, fastcgi_response_packet *packet) {
+ /* copy content; hctx->rb must contain at least packet->len content */
+ size_t toread = packet->len - packet->padding;
+ buffer_string_prepare_append(b, toread);
+ for (chunk *c = hctx->rb->first; c; c = c->next) {
+ size_t weHave = buffer_string_length(c->mem) - c->offset;
+ if (weHave >= toread) {
+ buffer_append_string_len(b, c->mem->ptr + c->offset, toread);
+ break;
+ }
+
+ buffer_append_string_len(b, c->mem->ptr + c->offset, weHave);
+ toread -= weHave;
+ }
+ chunkqueue_mark_written(hctx->rb, packet->len);
+}
+
+static handler_t fcgi_recv_parse(server *srv, connection *con, struct http_response_opts_t *opts, buffer *b, size_t n) {
+ handler_ctx *hctx = (handler_ctx *)opts->pdata;
+ int fin = 0;
+
+ if (0 == n) {
+ if (-1 == hctx->request_id) return HANDLER_FINISHED; /*(flag request ended)*/
+ if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)
+ && !(con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_POLLRDHUP))
+ return HANDLER_GO_ON;
+ log_error_write(srv, __FILE__, __LINE__, "ssdsb",
+ "unexpected end-of-file (perhaps the fastcgi process died):",
+ "pid:", hctx->proc->pid,
+ "socket:", hctx->proc->connection_name);
+
+ return HANDLER_ERROR;
+ }
+
+ chunkqueue_append_buffer(hctx->rb, b);
+
+ /*
+ * parse the fastcgi packets and forward the content to the write-queue
+ *
+ */
+ while (fin == 0) {
+ fastcgi_response_packet packet;
+
+ /* check if we have at least one packet */
+ if (0 != fastcgi_get_packet(srv, hctx, &packet)) {
+ /* no full packet */
+ break;
+ }
+
+ switch(packet.type) {
+ case FCGI_STDOUT:
+ if (packet.len == 0) break;
+
+ /* is the header already finished */
+ if (0 == con->file_started) {
+ /* split header from body */
+ buffer *hdrs = hctx->response;
+ if (NULL == hdrs) {
+ hdrs = srv->tmp_buf;
+ buffer_clear(srv->tmp_buf);
+ }
+ fastcgi_get_packet_body(hdrs, hctx, &packet);
+ if (HANDLER_GO_ON != http_response_parse_headers(srv, con, &hctx->opts, hdrs)) {
+ hctx->send_content_body = 0;
+ fin = 1;
+ break;
+ }
+ if (0 == con->file_started) {
+ if (!hctx->response) {
+ hctx->response = chunk_buffer_acquire();
+ buffer_copy_buffer(hctx->response, hdrs);
+ }
+ }
+ else if (hctx->gw_mode == GW_AUTHORIZER &&
+ (con->http_status == 0 || con->http_status == 200)) {
+ /* authorizer approved request; ignore the content here */
+ hctx->send_content_body = 0;
+ }
+ } else if (hctx->send_content_body) {
+ if (0 != http_chunk_transfer_cqlen(srv, con, hctx->rb, packet.len - packet.padding)) {
+ /* error writing to tempfile;
+ * truncate response or send 500 if nothing sent yet */
+ fin = 1;
+ }
+ if (packet.padding) chunkqueue_mark_written(hctx->rb, packet.padding);
+ } else {
+ chunkqueue_mark_written(hctx->rb, packet.len);
+ }
+ break;
+ case FCGI_STDERR:
+ if (packet.len == 0) break;
+
+ buffer_clear(srv->tmp_buf);
+ fastcgi_get_packet_body(srv->tmp_buf, hctx, &packet);
+ log_error_write_multiline_buffer(srv, __FILE__, __LINE__, srv->tmp_buf, "s",
+ "FastCGI-stderr:");
+
+ break;
+ case FCGI_END_REQUEST:
+ hctx->request_id = -1; /*(flag request ended)*/
+ fin = 1;
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "FastCGI: header.type not handled: ", packet.type);
+ chunkqueue_mark_written(hctx->rb, packet.len);
+ break;
+ }
+ }
+
+ return 0 == fin ? HANDLER_GO_ON : HANDLER_FINISHED;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(exts);
+ PATCH(exts_auth);
+ PATCH(exts_resp);
+ PATCH(debug);
+ PATCH(balance);
+ PATCH(ext_mapping);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
+ PATCH(exts);
+ PATCH(exts_auth);
+ PATCH(exts_resp);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
+ PATCH(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.balance"))) {
+ PATCH(balance);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
+ PATCH(ext_mapping);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
+ plugin_data *p = p_d;
+ handler_t rc;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ fcgi_patch_connection(srv, con, p);
+ if (NULL == p->conf.exts) return HANDLER_GO_ON;
+
+ rc = gw_check_extension(srv, con, p, uri_path_handler, 0);
+ if (HANDLER_GO_ON != rc) return rc;
+
+ if (con->mode == p->id) {
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ hctx->opts.backend = BACKEND_FASTCGI;
+ hctx->opts.parse = fcgi_recv_parse;
+ hctx->opts.pdata = hctx;
+ hctx->stdin_append = fcgi_stdin_append;
+ hctx->create_env = fcgi_create_env;
+ if (!hctx->rb) {
+ hctx->rb = chunkqueue_init();
+ }
+ else {
+ chunkqueue_reset(hctx->rb);
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/* uri-path handler */
+static handler_t fcgi_check_extension_1(server *srv, connection *con, void *p_d) {
+ return fcgi_check_extension(srv, con, p_d, 1);
+}
+
+/* start request handler */
+static handler_t fcgi_check_extension_2(server *srv, connection *con, void *p_d) {
+ return fcgi_check_extension(srv, con, p_d, 0);
+}
+
+
+int mod_fastcgi_plugin_init(plugin *p);
+int mod_fastcgi_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("fastcgi");
+
+ p->init = gw_init;
+ p->cleanup = gw_free;
+ p->set_defaults = mod_fastcgi_set_defaults;
+ p->connection_reset = gw_connection_reset;
+ p->handle_uri_clean = fcgi_check_extension_1;
+ p->handle_subrequest_start = fcgi_check_extension_2;
+ p->handle_subrequest = gw_handle_subrequest;
+ p->handle_trigger = gw_handle_trigger;
+ p->handle_waitpid = gw_handle_waitpid_cb;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_flv_streaming.c b/data/lighttpd/lighttpd-1.4.53/src/mod_flv_streaming.c
new file mode 100644
index 000000000..cb6186f63
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_flv_streaming.c
@@ -0,0 +1,224 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_chunk.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *extensions;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_flv_streaming_init) {
+ return calloc(1, sizeof(plugin_data));
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_flv_streaming_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ array_free(s->extensions);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->extensions = array_init();
+
+ cv[0].destination = s->extensions;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->extensions)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for flv-streaming.extensions; expected list of \"ext\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(extensions);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
+ PATCH(extensions);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int split_get_params(array *get_params, buffer *qrystr) {
+ size_t is_key = 1, klen = 0;
+ char *key = qrystr->ptr, *val = NULL;
+
+ if (buffer_string_is_empty(qrystr)) return 0;
+ for (size_t i = 0, len = buffer_string_length(qrystr); i <= len; ++i) {
+ switch(qrystr->ptr[i]) {
+ case '=':
+ if (is_key) {
+ val = qrystr->ptr + i + 1;
+ klen = (size_t)(qrystr->ptr + i - key);
+ is_key = 0;
+ }
+
+ break;
+ case '&':
+ case '\0': /* fin symbol */
+ if (!is_key) {
+ /* we need at least a = since the last & */
+ array_insert_key_value(get_params, key, klen, val, qrystr->ptr + i - val);
+ }
+
+ key = qrystr->ptr + i + 1;
+ val = NULL;
+ is_key = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+ plugin_data *p = p_d;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+ if (buffer_string_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_flv_streaming_patch_connection(srv, con, p);
+
+ if (!array_match_value_suffix(p->conf.extensions, con->physical.path)) {
+ /* not found */
+ return HANDLER_GO_ON;
+ }
+
+ {
+ data_string *get_param;
+ off_t start = 0, len = -1;
+ char *err = NULL;
+ /* if there is a start=[0-9]+ in the header use it as start,
+ * otherwise set start to beginning of file */
+ /* if there is a end=[0-9]+ in the header use it as end pos,
+ * otherwise send rest of file, starting from start */
+
+ array_reset_data_strings(srv->split_vals);
+ split_get_params(srv->split_vals, con->uri.query);
+
+ if (NULL != (get_param = (data_string *)array_get_element_klen(srv->split_vals, CONST_STR_LEN("start")))) {
+ if (buffer_string_is_empty(get_param->value)) return HANDLER_GO_ON;
+ start = strtoll(get_param->value->ptr, &err, 10);
+ if (*err != '\0') return HANDLER_GO_ON;
+ if (start < 0) return HANDLER_GO_ON;
+ }
+
+ if (NULL != (get_param = (data_string *)array_get_element_klen(srv->split_vals, CONST_STR_LEN("end")))) {
+ off_t end;
+ if (buffer_string_is_empty(get_param->value)) return HANDLER_GO_ON;
+ end = strtoll(get_param->value->ptr, &err, 10);
+ if (*err != '\0') return HANDLER_GO_ON;
+ if (end < 0) return HANDLER_GO_ON;
+ len = (start < end ? end - start : start - end) + 1;
+ }
+ else if (0 == start) {
+ return HANDLER_GO_ON;
+ }
+
+ /* let's build a flv header */
+ http_chunk_append_mem(srv, con, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
+ if (0 != http_chunk_append_file_range(srv, con, con->physical.path, start, len)) {
+ chunkqueue_reset(con->write_queue);
+ return HANDLER_GO_ON;
+ }
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ }
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_flv_streaming_plugin_init(plugin *p);
+int mod_flv_streaming_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("flv_streaming");
+
+ p->init = mod_flv_streaming_init;
+ p->handle_physical = mod_flv_streaming_path_handler;
+ p->set_defaults = mod_flv_streaming_set_defaults;
+ p->cleanup = mod_flv_streaming_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_geoip.c b/data/lighttpd/lighttpd-1.4.53/src/mod_geoip.c
new file mode 100644
index 000000000..12c855d04
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_geoip.c
@@ -0,0 +1,305 @@
+#include "first.h"
+
+#include <GeoIP.h>
+#include <GeoIPCity.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ *
+ * $mod_geoip.c (v2.0) (13.09.2006 00:29:11)
+ *
+ * Name:
+ * mod_geoip.c
+ *
+ * Description:
+ * GeoIP module (plugin) for lighttpd.
+ * the module loads a geoip database of type "country" or "city" and
+ * sets new ENV vars based on ip record lookups.
+ *
+ * country db env's:
+ * GEOIP_COUNTRY_CODE
+ * GEOIP_COUNTRY_CODE3
+ * GEOIP_COUNTRY_NAME
+ *
+ * city db env's:
+ * GEOIP_COUNTRY_CODE
+ * GEOIP_COUNTRY_CODE3
+ * GEOIP_COUNTRY_NAME
+ * GEOIP_CITY_NAME
+ * GEOIP_CITY_POSTAL_CODE
+ * GEOIP_CITY_LATITUDE
+ * GEOIP_CITY_LONG_LATITUDE
+ * GEOIP_CITY_DMA_CODE
+ * GEOIP_CITY_AREA_CODE
+ *
+ * Usage (configuration options):
+ * geoip.db-filename = <path to the geoip or geocity database>
+ * geoip.memory-cache = <enable|disable> : default disabled
+ * if enabled, mod_geoip will load the database binary file to
+ * memory for very fast lookups. the only penalty is memory usage.
+ *
+ * Author:
+ * Ami E. Bizamcher (amix)
+ * duke.amix@gmail.com
+ *
+ * Note:
+ * GeoIP Library and API must be installed!
+ */
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ unsigned short mem_cache;
+ buffer *db_name;
+ GeoIP *gi;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_geoip_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+/* destroy the plugin data */
+FREE_FUNC(mod_geoip_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!s) continue;
+
+ buffer_free(s->db_name);
+
+ /* clean up */
+ if (s->gi) GeoIP_delete(s->gi);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_geoip_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "geoip.db-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "geoip.memory-cache", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+ int mode;
+
+ s = calloc(1, sizeof(plugin_config));
+
+ s->db_name = buffer_init();
+ s->mem_cache = 0; /* default: do not load db to cache */
+ s->gi = NULL;
+
+ cv[0].destination = s->db_name;
+ cv[1].destination = &(s->mem_cache);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ mode = GEOIP_STANDARD | GEOIP_CHECK_CACHE;
+
+ /* country db filename is requeried! */
+ if (!buffer_is_empty(s->db_name)) {
+
+ /* let's start cooking */
+ if (s->mem_cache != 0)
+ mode = GEOIP_MEMORY_CACHE | GEOIP_CHECK_CACHE;
+
+ if (NULL == (s->gi = GeoIP_open(s->db_name->ptr, mode))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "failed to open GeoIP database!!!");
+
+ return HANDLER_ERROR;
+ }
+
+ /* is the db supported ? */
+ if (s->gi->databaseType != GEOIP_COUNTRY_EDITION &&
+ s->gi->databaseType != GEOIP_CITY_EDITION_REV0 &&
+ s->gi->databaseType != GEOIP_CITY_EDITION_REV1) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "GeoIP database is of unsupported type!!!");
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_geoip_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(db_name);
+ PATCH(mem_cache);
+ PATCH(gi);
+
+ /* 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("geoip.db-filename"))) {
+ PATCH(db_name);
+ }
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("geoip.memory-cache"))) {
+ PATCH(mem_cache);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static handler_t mod_geoip_query (connection *con, plugin_data *p) {
+ GeoIPRecord *gir;
+ const char *remote_ip = con->dst_addr_buf->ptr;
+
+ if (NULL != http_header_env_get(con, CONST_STR_LEN("GEOIP_COUNTRY_CODE"))) {
+ return HANDLER_GO_ON;
+ }
+
+ if (p->conf.gi->databaseType == GEOIP_COUNTRY_EDITION) {
+ const char *returnedCountry;
+
+ if (NULL != (returnedCountry = GeoIP_country_code_by_addr(p->conf.gi, remote_ip))) {
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_COUNTRY_CODE"), returnedCountry, strlen(returnedCountry));
+ }
+
+ if (NULL != (returnedCountry = GeoIP_country_code3_by_addr(p->conf.gi, remote_ip))) {
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_COUNTRY_CODE3"), returnedCountry, strlen(returnedCountry));
+ }
+
+ if (NULL != (returnedCountry = GeoIP_country_name_by_addr(p->conf.gi, remote_ip))) {
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_COUNTRY_NAME"), returnedCountry, strlen(returnedCountry));
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+ /* if we are here, geo city is in use */
+
+ if (NULL != (gir = GeoIP_record_by_addr(p->conf.gi, remote_ip))) {
+
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_COUNTRY_CODE"), gir->country_code, strlen(gir->country_code));
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_COUNTRY_CODE3"), gir->country_code3, strlen(gir->country_code3));
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_COUNTRY_NAME"), gir->country_name, strlen(gir->country_name));
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_REGION"), gir->region, strlen(gir->region));
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_NAME"), gir->city, strlen(gir->city));
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_POSTAL_CODE"), gir->postal_code, strlen(gir->postal_code));
+
+ {
+ char latitude[32];
+ snprintf(latitude, sizeof(latitude), "%f", gir->latitude);
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_LATITUDE"), latitude, strlen(latitude));
+ }
+
+ {
+ char long_latitude[32];
+ snprintf(long_latitude, sizeof(long_latitude), "%f", gir->longitude);
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_LONG_LATITUDE"), long_latitude, strlen(long_latitude));
+ }
+
+ {
+ char dc[LI_ITOSTRING_LENGTH];
+ li_utostrn(dc, sizeof(dc), gir->dma_code);
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_DMA_CODE"), dc, strlen(dc));
+ }
+
+ {
+ char ac[LI_ITOSTRING_LENGTH];
+ li_utostrn(ac, sizeof(ac), gir->area_code);
+ http_header_env_set(con, CONST_STR_LEN("GEOIP_CITY_AREA_CODE"), ac, strlen(ac));
+ }
+
+ GeoIPRecord_delete(gir);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_geoip_handle_request_env) {
+ plugin_data *p = p_d;
+ mod_geoip_patch_connection(srv, con, p);
+ if (buffer_is_empty(p->conf.db_name)) return HANDLER_GO_ON;
+
+ return mod_geoip_query(con, p);
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_geoip_plugin_init(plugin *p);
+int mod_geoip_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("geoip");
+
+ p->init = mod_geoip_init;
+ p->handle_request_env = mod_geoip_handle_request_env;
+ p->set_defaults = mod_geoip_set_defaults;
+ p->cleanup = mod_geoip_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_indexfile.c b/data/lighttpd/lighttpd-1.4.53/src/mod_indexfile.c
new file mode 100644
index 000000000..a48681b17
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_indexfile.c
@@ -0,0 +1,235 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *indexfiles;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_indexfile_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_indexfile_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->indexfiles);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->indexfiles = array_init();
+
+ cv[0].destination = s->indexfiles;
+ cv[1].destination = s->indexfiles; /* old name for [0] */
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->indexfiles)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for index-file.names; expected list of \"file\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(indexfiles);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
+ PATCH(indexfiles);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
+ PATCH(indexfiles);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_indexfile_subrequest) {
+ plugin_data *p = p_d;
+ size_t k;
+ stat_cache_entry *sce = NULL;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+ if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON;
+
+ mod_indexfile_patch_connection(srv, con, p);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
+ }
+
+ /* indexfile */
+ for (k = 0; k < p->conf.indexfiles->used; k++) {
+ data_string *ds = (data_string *)p->conf.indexfiles->data[k];
+
+ if (ds->value && ds->value->ptr[0] == '/') {
+ /* if the index-file starts with a prefix as use this file as
+ * index-generator */
+ buffer_copy_buffer(p->tmp_buf, con->physical.doc_root);
+ } else {
+ buffer_copy_buffer(p->tmp_buf, con->physical.path);
+ }
+ buffer_append_string_buffer(p->tmp_buf, ds->value);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+ if (errno == EACCES) {
+ con->http_status = 403;
+ buffer_reset(con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ if (errno != ENOENT &&
+ errno != ENOTDIR) {
+ /* we have no idea what happend. let's tell the user so. */
+
+ con->http_status = 500;
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsb",
+ "file not found ... or so: ", strerror(errno),
+ con->uri.path,
+ "->", con->physical.path);
+
+ buffer_reset(con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+ continue;
+ }
+
+ if (ds->value && ds->value->ptr[0] == '/') {
+ /* replace uri.path */
+ buffer_copy_buffer(con->uri.path, ds->value);
+ http_header_env_set(con, CONST_STR_LEN("PATH_TRANSLATED_DIRINDEX"), CONST_BUF_LEN(con->physical.path));
+ } else {
+ /* append to uri.path the relative path to index file (/ -> /index.php) */
+ buffer_append_string_buffer(con->uri.path, ds->value);
+ }
+
+ buffer_copy_buffer(con->physical.path, p->tmp_buf);
+
+ return HANDLER_GO_ON;
+ }
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_indexfile_plugin_init(plugin *p);
+int mod_indexfile_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("indexfile");
+
+ p->init = mod_indexfile_init;
+ p->handle_subrequest_start = mod_indexfile_subrequest;
+ p->set_defaults = mod_indexfile_set_defaults;
+ p->cleanup = mod_indexfile_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_magnet.c b/data/lighttpd/lighttpd-1.4.53/src/mod_magnet.c
new file mode 100644
index 000000000..dcb1fd8cb
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_magnet.c
@@ -0,0 +1,1071 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_chunk.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include "mod_magnet_cache.h"
+#include "stat_cache.h"
+#include "status_counter.h"
+#include "etag.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#define LUA_RIDX_LIGHTTPD_SERVER "lighty.srv"
+#define LUA_RIDX_LIGHTTPD_CONNECTION "lighty.con"
+
+#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;
+
+ 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();
+
+ 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 (NULL == s) continue;
+
+ array_free(s->url_raw);
+ array_free(s->physical_path);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ script_cache_free(p->cache);
+
+ 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(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[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, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->url_raw)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for magnet.attract-raw-url-to; expected list of \"scriptpath\"");
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->physical_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for magnet.attract-physical-path-to; expected list \"scriptpath\"");
+ 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
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
+/* lua5.1 backward compat definition */
+static void lua_pushglobaltable(lua_State *L) { /* (-0, +1, -) */
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+}
+#endif
+
+static void magnet_setfenv_mainfn(lua_State *L, int funcIndex) { /* (-1, 0, -) */
+#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502
+ /* set "_ENV" upvalue, which should be the first upvalue of a "main" lua
+ * function if it uses any global names
+ */
+
+ const char* first_upvalue_name = lua_getupvalue(L, funcIndex, 1);
+ if (NULL == first_upvalue_name) return; /* doesn't have any upvalues */
+ lua_pop(L, 1); /* only need the name of the upvalue, not the value */
+
+ if (0 != strcmp(first_upvalue_name, "_ENV")) return;
+
+ if (NULL == lua_setupvalue(L, funcIndex, 1)) {
+ /* pop value if lua_setupvalue didn't set the (not existing) upvalue */
+ lua_pop(L, 1);
+ }
+#else
+ lua_setfenv(L, funcIndex);
+#endif
+}
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
+/* lua 5.2 already supports __pairs */
+
+/* See http://lua-users.org/wiki/GeneralizedPairsAndIpairs for implementation details.
+ * Override the default pairs() function to allow us to use a __pairs metakey
+ */
+static int magnet_pairs(lua_State *L) {
+ luaL_checkany(L, 1); /* "self" */
+
+ if (luaL_getmetafield(L, 1, "__pairs")) {
+ /* call __pairs(self) */
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 3);
+ } else {
+ /* call <original-pairs-method>(self) */
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 3);
+ }
+ return 3;
+}
+#endif
+
+static void magnet_push_buffer(lua_State *L, const buffer *b) {
+ if (!buffer_is_empty(b))
+ lua_pushlstring(L, CONST_BUF_LEN(b));
+ else
+ lua_pushnil(L);
+}
+
+#if 0
+static int magnet_array_get_element(lua_State *L, const array *a) {
+ /* __index: param 1 is the (empty) table the value was not found in */
+ size_t klen;
+ const char * const k = luaL_checklstring(L, 2, &klen);
+ data_string * const ds = (data_string *)array_get_element_klen(a, k, klen);
+ magnet_push_buffer(L, NULL != ds ? ds->value : NULL);
+ return 1;
+}
+#endif
+
+/* Define a function that will iterate over an array* (in upval 1) using current position (upval 2) */
+static int magnet_array_next(lua_State *L) {
+ data_unset *du;
+ data_string *ds;
+ data_integer *di;
+
+ size_t pos = lua_tointeger(L, lua_upvalueindex(1));
+ array *a = lua_touserdata(L, lua_upvalueindex(2));
+
+ lua_settop(L, 0);
+
+ if (pos >= a->used) return 0;
+ if (NULL != (du = a->data[pos])) {
+ lua_pushlstring(L, CONST_BUF_LEN(du->key));
+ switch (du->type) {
+ case TYPE_STRING:
+ ds = (data_string *)du;
+ magnet_push_buffer(L, ds->value);
+ break;
+ case TYPE_INTEGER:
+ di = (data_integer *)du;
+ lua_pushinteger(L, di->value);
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+
+ /* Update our positional upval to reflect our new current position */
+ pos++;
+ lua_pushinteger(L, pos);
+ lua_replace(L, lua_upvalueindex(1));
+
+ /* Returning 2 items on the stack (key, value) */
+ return 2;
+ }
+ return 0;
+}
+
+/* Create the closure necessary to iterate over the array *a with the above function */
+static int magnet_array_pairs(lua_State *L, array *a) {
+ lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
+ lua_pushlightuserdata(L, a); /* Push our array *a into upval 2 */
+ lua_pushcclosure(L, magnet_array_next, 2); /* Push our new closure with 2 upvals */
+ return 1;
+}
+
+static server* magnet_get_server(lua_State *L) {
+ server *srv;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_SERVER);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ return srv;
+}
+
+static connection* magnet_get_connection(lua_State *L) {
+ connection *con;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_CONNECTION);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ return con;
+}
+
+typedef struct {
+ const char *ptr;
+ size_t len;
+} const_buffer;
+
+static const_buffer magnet_checkconstbuffer(lua_State *L, int index) {
+ const_buffer cb;
+ cb.ptr = luaL_checklstring(L, index, &cb.len);
+ return cb;
+}
+
+static buffer* magnet_checkbuffer(lua_State *L, int index) {
+ const_buffer cb = magnet_checkconstbuffer(L, index);
+ buffer *b = buffer_init();
+ buffer_copy_string_len(b, cb.ptr, cb.len);
+ return b;
+}
+
+static int magnet_print(lua_State *L) {
+ const_buffer cb = magnet_checkconstbuffer(L, 1);
+ log_error_write(magnet_get_server(L), __FILE__, __LINE__, "ss",
+ "(lua-print)", cb.ptr);
+ return 0;
+}
+
+static int magnet_stat(lua_State *L) {
+ server *srv = magnet_get_server(L);
+ connection *con = magnet_get_connection(L);
+ stat_cache_entry *sce = NULL;
+ {
+ buffer *sb = magnet_checkbuffer(L, 1);
+ handler_t res;
+
+ res = stat_cache_get_entry(srv, con, sb, &sce);
+
+ if (HANDLER_GO_ON != res) {
+ buffer_free(sb);
+ lua_pushnil(L);
+ return 1;
+ }
+
+ stat_cache_content_type_get(srv, con, sb, sce);
+ buffer_free(sb);
+ }
+
+ lua_newtable(L); // return value
+
+ lua_pushboolean(L, S_ISREG(sce->st.st_mode));
+ lua_setfield(L, -2, "is_file");
+
+ lua_pushboolean(L, S_ISDIR(sce->st.st_mode));
+ lua_setfield(L, -2, "is_dir");
+
+ lua_pushboolean(L, S_ISCHR(sce->st.st_mode));
+ lua_setfield(L, -2, "is_char");
+
+ lua_pushboolean(L, S_ISBLK(sce->st.st_mode));
+ lua_setfield(L, -2, "is_block");
+
+ lua_pushboolean(L, S_ISSOCK(sce->st.st_mode));
+ lua_setfield(L, -2, "is_socket");
+
+ lua_pushboolean(L, S_ISLNK(sce->st.st_mode));
+ lua_setfield(L, -2, "is_link");
+
+ lua_pushboolean(L, S_ISFIFO(sce->st.st_mode));
+ lua_setfield(L, -2, "is_fifo");
+
+ lua_pushinteger(L, sce->st.st_mtime);
+ lua_setfield(L, -2, "st_mtime");
+
+ lua_pushinteger(L, sce->st.st_ctime);
+ lua_setfield(L, -2, "st_ctime");
+
+ lua_pushinteger(L, sce->st.st_atime);
+ lua_setfield(L, -2, "st_atime");
+
+ lua_pushinteger(L, sce->st.st_uid);
+ lua_setfield(L, -2, "st_uid");
+
+ lua_pushinteger(L, sce->st.st_gid);
+ lua_setfield(L, -2, "st_gid");
+
+ lua_pushinteger(L, sce->st.st_size);
+ lua_setfield(L, -2, "st_size");
+
+ lua_pushinteger(L, sce->st.st_ino);
+ lua_setfield(L, -2, "st_ino");
+
+ if (!buffer_string_is_empty(stat_cache_etag_get(sce, con->etag_flags))) {
+ /* we have to mutate the etag */
+ etag_mutate(srv->tmp_buf, sce->etag);
+ lua_pushlstring(L, CONST_BUF_LEN(srv->tmp_buf));
+ } else {
+ lua_pushnil(L);
+ }
+ lua_setfield(L, -2, "etag");
+
+ if (!buffer_string_is_empty(sce->content_type)) {
+ lua_pushlstring(L, CONST_BUF_LEN(sce->content_type));
+ } else {
+ lua_pushnil(L);
+ }
+ lua_setfield(L, -2, "content-type");
+
+ return 1;
+}
+
+
+static int magnet_atpanic(lua_State *L) {
+ const_buffer cb = magnet_checkconstbuffer(L, 1);
+ log_error_write(magnet_get_server(L), __FILE__, __LINE__, "ss",
+ "(lua-atpanic)", cb.ptr);
+ longjmp(exceptionjmp, 1);
+}
+
+static int magnet_reqhdr_get(lua_State *L) {
+ /* __index: param 1 is the (empty) table the value was not found in */
+ connection *con = magnet_get_connection(L);
+ size_t klen;
+ const char * const k = luaL_checklstring(L, 2, &klen);
+ buffer * const vb =
+ http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, k, klen);
+ magnet_push_buffer(L, NULL != vb ? vb : NULL);
+ return 1;
+}
+
+static int magnet_reqhdr_pairs(lua_State *L) {
+ connection *con = magnet_get_connection(L);
+ return magnet_array_pairs(L, con->request.headers);
+}
+
+static int magnet_status_get(lua_State *L) {
+ int *i;
+ server *srv = magnet_get_server(L);
+
+ /* __index: param 1 is the (empty) table the value was not found in */
+ const_buffer key = magnet_checkconstbuffer(L, 2);
+ i = status_counter_get_counter(srv, key.ptr, key.len);
+ lua_pushinteger(L, (lua_Integer)*i);
+
+ return 1;
+}
+
+static int magnet_status_set(lua_State *L) {
+ server *srv = magnet_get_server(L);
+
+ /* __newindex: param 1 is the (empty) table the value is supposed to be set in */
+ const_buffer key = magnet_checkconstbuffer(L, 2);
+ int counter = (int) luaL_checkinteger(L, 3);
+
+ status_counter_set(srv, key.ptr, key.len, counter);
+
+ return 0;
+}
+
+static int magnet_status_pairs(lua_State *L) {
+ server *srv = magnet_get_server(L);
+
+ return magnet_array_pairs(L, srv->status);
+}
+
+typedef struct {
+ const char *name;
+ enum {
+ MAGNET_ENV_UNSET,
+
+ MAGNET_ENV_PHYICAL_PATH,
+ MAGNET_ENV_PHYICAL_REL_PATH,
+ MAGNET_ENV_PHYICAL_DOC_ROOT,
+ MAGNET_ENV_PHYICAL_BASEDIR,
+
+ MAGNET_ENV_URI_PATH,
+ MAGNET_ENV_URI_PATH_RAW,
+ MAGNET_ENV_URI_SCHEME,
+ MAGNET_ENV_URI_AUTHORITY,
+ MAGNET_ENV_URI_QUERY,
+
+ MAGNET_ENV_REQUEST_METHOD,
+ MAGNET_ENV_REQUEST_URI,
+ MAGNET_ENV_REQUEST_ORIG_URI,
+ MAGNET_ENV_REQUEST_PATH_INFO,
+ MAGNET_ENV_REQUEST_REMOTE_IP,
+ MAGNET_ENV_REQUEST_PROTOCOL
+ } type;
+} magnet_env_t;
+
+static const magnet_env_t magnet_env[] = {
+ { "physical.path", MAGNET_ENV_PHYICAL_PATH },
+ { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
+ { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
+ { "physical.basedir", MAGNET_ENV_PHYICAL_BASEDIR },
+
+ { "uri.path", MAGNET_ENV_URI_PATH },
+ { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
+ { "uri.scheme", MAGNET_ENV_URI_SCHEME },
+ { "uri.authority", MAGNET_ENV_URI_AUTHORITY },
+ { "uri.query", MAGNET_ENV_URI_QUERY },
+
+ { "request.method", MAGNET_ENV_REQUEST_METHOD },
+ { "request.uri", MAGNET_ENV_REQUEST_URI },
+ { "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI },
+ { "request.path-info", MAGNET_ENV_REQUEST_PATH_INFO },
+ { "request.remote-ip", MAGNET_ENV_REQUEST_REMOTE_IP },
+ { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
+
+ { NULL, MAGNET_ENV_UNSET }
+};
+
+static buffer *magnet_env_get_buffer_by_id(server *srv, connection *con, int id) {
+ buffer *dest = NULL;
+
+ UNUSED(srv);
+
+ /**
+ * map all internal variables to lua
+ *
+ */
+
+ switch (id) {
+ case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
+ case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
+ case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
+ case MAGNET_ENV_PHYICAL_BASEDIR: dest = con->physical.basedir; break;
+
+ case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
+ case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
+ case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
+ case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
+ case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
+
+ case MAGNET_ENV_REQUEST_METHOD:
+ buffer_clear(srv->tmp_buf);
+ http_method_append(srv->tmp_buf, con->request.http_method);
+ dest = srv->tmp_buf;
+ break;
+ case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break;
+ case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break;
+ case MAGNET_ENV_REQUEST_PATH_INFO: dest = con->request.pathinfo; break;
+ case MAGNET_ENV_REQUEST_REMOTE_IP: dest = con->dst_addr_buf; break;
+ case MAGNET_ENV_REQUEST_PROTOCOL:
+ buffer_copy_string(srv->tmp_buf, get_http_version_name(con->request.http_version));
+ dest = srv->tmp_buf;
+ break;
+
+ case MAGNET_ENV_UNSET: break;
+ }
+
+ return dest;
+}
+
+static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
+ size_t i;
+
+ for (i = 0; magnet_env[i].name; i++) {
+ if (0 == strcmp(key, magnet_env[i].name)) break;
+ }
+
+ return magnet_env_get_buffer_by_id(srv, con, magnet_env[i].type);
+}
+
+static int magnet_env_get(lua_State *L) {
+ server *srv = magnet_get_server(L);
+ connection *con = magnet_get_connection(L);
+
+ /* __index: param 1 is the (empty) table the value was not found in */
+ const char *key = luaL_checkstring(L, 2);
+ magnet_push_buffer(L, magnet_env_get_buffer(srv, con, key));
+ return 1;
+}
+
+static int magnet_env_set(lua_State *L) {
+ server *srv = magnet_get_server(L);
+ connection *con = magnet_get_connection(L);
+
+ /* __newindex: param 1 is the (empty) table the value is supposed to be set in */
+ const char *key = luaL_checkstring(L, 2);
+ buffer *dest = NULL;
+
+ luaL_checkany(L, 3); /* nil or a string */
+
+ if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
+ if (lua_isnil(L, 3)) {
+ buffer_reset(dest);
+ } else {
+ const_buffer val = magnet_checkconstbuffer(L, 3);
+ buffer_copy_string_len(dest, val.ptr, val.len);
+ }
+ } else {
+ /* couldn't save */
+
+ return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
+ }
+
+ return 0;
+}
+
+static int magnet_env_next(lua_State *L) {
+ server *srv = magnet_get_server(L);
+ connection *con = magnet_get_connection(L);
+ const int pos = lua_tointeger(L, lua_upvalueindex(1));
+
+ /* ignore previous key: use upvalue for current pos */
+ lua_settop(L, 0);
+
+ if (NULL == magnet_env[pos].name) return 0; /* end of list */
+ /* Update our positional upval to reflect our new current position */
+ lua_pushinteger(L, pos + 1);
+ lua_replace(L, lua_upvalueindex(1));
+
+ /* key to return */
+ lua_pushstring(L, magnet_env[pos].name);
+
+ /* get value */
+ magnet_push_buffer(L, magnet_env_get_buffer_by_id(srv, con, magnet_env[pos].type));
+
+ /* return 2 items on the stack (key, value) */
+ return 2;
+}
+
+static int magnet_env_pairs(lua_State *L) {
+ lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
+ lua_pushcclosure(L, magnet_env_next, 1); /* Push our new closure with 1 upvals */
+ return 1;
+}
+
+static int magnet_cgi_get(lua_State *L) {
+ /* __index: param 1 is the (empty) table the value was not found in */
+ connection *con = magnet_get_connection(L);
+ size_t klen;
+ const char * const k = luaL_checklstring(L, 2, &klen);
+ buffer * const vb = http_header_env_get(con, k, klen);
+ magnet_push_buffer(L, NULL != vb ? vb : NULL);
+ return 1;
+}
+
+static int magnet_cgi_set(lua_State *L) {
+ /* __newindex: param 1 is the (empty) table the value is supposed to be set in */
+ connection *con = magnet_get_connection(L);
+ const_buffer key = magnet_checkconstbuffer(L, 2);
+ const_buffer val = magnet_checkconstbuffer(L, 3);
+ http_header_env_set(con, key.ptr, key.len, val.ptr, val.len);
+ return 0;
+}
+
+static int magnet_cgi_pairs(lua_State *L) {
+ connection *con = magnet_get_connection(L);
+
+ return magnet_array_pairs(L, con->environment);
+}
+
+
+static int magnet_copy_response_header(connection *con, lua_State *L, int lighty_table_ndx) {
+ force_assert(lua_istable(L, lighty_table_ndx));
+
+ lua_getfield(L, lighty_table_ndx, "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_buffer key = magnet_checkconstbuffer(L, -2);
+ const_buffer val = magnet_checkconstbuffer(L, -1);
+ enum http_header_e id = http_header_hkey_get(key.ptr, key.len);
+
+ val.len
+ ? http_header_response_set(con, id, key.ptr, key.len, val.ptr, val.len)
+ : http_header_response_unset(con, id, key.ptr, key.len);
+ }
+
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1); /* pop lighty.header */
+
+ 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, lua_State *L, int lighty_table_ndx) {
+ force_assert(lua_istable(L, lighty_table_ndx));
+
+ lua_getfield(L, lighty_table_ndx, "content"); /* lighty.content */
+ if (lua_istable(L, -1)) {
+ int i;
+ /* content 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)) {
+ const_buffer data = magnet_checkconstbuffer(L, -1);
+
+ chunkqueue_append_mem(con->write_queue, data.ptr, data.len);
+ } else if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "filename");
+ lua_getfield(L, -2, "length"); /* (0-based) end of range (not actually "length") */
+ lua_getfield(L, -3, "offset"); /* (0-based) start of range */
+
+ if (lua_isstring(L, -3)) { /* filename has to be a string */
+ off_t off = (off_t) luaL_optinteger(L, -1, 0);
+ off_t len = (off_t) luaL_optinteger(L, -2, -1); /*(-1 to http_chunk_append_file_range() uses file size minus offset)*/
+ if (off < 0) {
+ return luaL_error(L, "offset for '%s' is negative", lua_tostring(L, -3));
+ }
+
+ if (len >= off) {
+ len -= off;
+ } else if (-1 != len) {
+ return luaL_error(L, "offset > length for '%s'", lua_tostring(L, -3));
+ }
+
+ if (0 != len) {
+ buffer *fn = magnet_checkbuffer(L, -3);
+ int rc = http_chunk_append_file_range(srv, con, fn, off, len);
+ buffer_free(fn);
+ if (0 != rc) {
+ return luaL_error(L, "error opening file content '%s' at offset %lld", lua_tostring(L, -3), (long long)off);
+ }
+ }
+ } else {
+ 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)) {
+ /* end of list */
+
+ lua_pop(L, 1);
+
+ break;
+ } else {
+ return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
+ }
+
+ lua_pop(L, 1); /* pop the content[...] entry value */
+ }
+ } else {
+ return luaL_error(L, "lighty.content has to be a table");
+ }
+ lua_pop(L, 1); /* pop lighty.content */
+
+ return 0;
+}
+
+static int traceback(lua_State *L) {
+ if (!lua_isstring(L, 1)) /* 'message' not a string? */
+ return 1; /* keep it intact */
+ lua_getglobal(L, "debug");
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ lua_getfield(L, -1, "traceback");
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 2);
+ return 1;
+ }
+ lua_pushvalue(L, 1); /* pass error message */
+ lua_pushinteger(L, 2); /* skip this function and traceback */
+ lua_call(L, 2, 1); /* call debug.traceback */
+ return 1;
+}
+
+/* push traceback function before calling lua_pcall after narg arguments
+ * have been pushed (inserts it before the arguments). returns index for
+ * traceback function ("msgh" in lua_pcall)
+ */
+static int push_traceback(lua_State *L, int narg) {
+ int base = lua_gettop(L) - narg; /* function index */
+ lua_pushcfunction(L, traceback);
+ lua_insert(L, base);
+ return base;
+}
+
+static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
+ lua_State *L;
+ int lua_return_value;
+ const int func_ndx = 1;
+ const int lighty_table_ndx = 2;
+
+ /* 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);
+
+ force_assert(lua_gettop(L) == 0); /* only the error should have been on the stack */
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+
+ force_assert(lua_gettop(L) == 1);
+ force_assert(lua_isfunction(L, func_ndx));
+
+ lua_pushlightuserdata(L, srv);
+ lua_setfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_SERVER);
+
+ lua_pushlightuserdata(L, con);
+ lua_setfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_CONNECTION);
+
+ 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[] (ro) has the HTTP-request headers
+ * lighty.env[] (rw) has various url/physical file paths and
+ * request meta data; might contain nil values
+ * lighty.req_env[] (ro) has the cgi environment
+ * lighty.status[] (ro) has the status counters
+ * lighty.content[] (rw) is a table of string/file
+ * lighty.header[] (rw) is a array to set response headers
+ */
+
+ lua_newtable(L); /* lighty.* (sp += 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_reqhdr_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the env-table (sp += 1) */
+ lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_env_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to env (sp -= 1) */
+ lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the req_env-table (sp += 1) */
+ lua_pushcfunction(L, magnet_cgi_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_cgi_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_cgi_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to req_env (sp -= 1) */
+ lua_setfield(L, -2, "req_env"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the status-table (sp += 1) */
+ lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_status_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to statzs (sp -= 1) */
+ lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */
+
+ /* add empty 'content' and 'header' tables */
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */
+
+ lua_pushinteger(L, MAGNET_RESTART_REQUEST);
+ lua_setfield(L, -2, "RESTART_REQUEST");
+
+ lua_pushcfunction(L, magnet_stat); /* (sp += 1) */
+ lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */
+
+ /* insert lighty table at index 2 */
+ lua_pushvalue(L, -1);
+ lua_insert(L, lighty_table_ndx);
+
+ lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
+ /* override the default pairs() function to our __pairs capable version;
+ * not needed for lua 5.2+
+ */
+ lua_getglobal(L, "pairs"); /* push original pairs() (sp += 1) */
+ lua_pushcclosure(L, magnet_pairs, 1);
+ lua_setfield(L, -2, "pairs"); /* (sp -= 1) */
+#endif
+
+ lua_newtable(L); /* the meta-table for the new env (sp += 1) */
+ lua_pushglobaltable(L); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */
+ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
+
+ magnet_setfenv_mainfn(L, 1); /* (sp -= 1) */
+
+ /* pcall will destroy the func value, duplicate it */ /* (sp += 1) */
+ lua_pushvalue(L, func_ndx);
+ {
+ int errfunc = push_traceback(L, 0);
+ int ret = lua_pcall(L, 0, 1, errfunc);
+ lua_remove(L, errfunc);
+
+ /* reset environment */
+ lua_pushglobaltable(L); /* (sp += 1) */
+ magnet_setfenv_mainfn(L, 1); /* (sp -= 1) */
+
+ if (0 != ret) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "ss",
+ "lua_pcall():",
+ lua_tostring(L, -1));
+ lua_pop(L, 2); /* remove the error-msg and the lighty table at index 2 */
+
+ force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+ }
+
+ /* we should have the function, the lighty table and the return value on the stack */
+ force_assert(lua_gettop(L) == 3);
+
+ lua_return_value = (int) luaL_optinteger(L, -1, -1);
+ lua_pop(L, 1); /* pop return value */
+
+ magnet_copy_response_header(con, L, lighty_table_ndx);
+
+ {
+ handler_t result = HANDLER_GO_ON;
+
+ 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, L, lighty_table_ndx);
+ if (!chunkqueue_is_empty(con->write_queue)) {
+ con->mode = p->id;
+ }
+ } else {
+ lua_settop(L, 2); /* remove all but function and lighty table */
+ /* } catch () { */
+ con->http_status = 500;
+ con->mode = DIRECT;
+ }
+
+ result = HANDLER_FINISHED;
+ } else if (MAGNET_RESTART_REQUEST == lua_return_value) {
+ result = HANDLER_COMEBACK;
+ }
+
+ lua_pop(L, 1); /* pop the lighty table */
+ force_assert(lua_gettop(L) == 1); /* only the function should remain on the stack */
+
+ return result;
+ }
+}
+
+static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
+ size_t i;
+ handler_t ret = HANDLER_GO_ON;
+
+ /* no filename set */
+ if (files->used == 0) return HANDLER_GO_ON;
+
+ srv->request_env(srv, con);
+
+ /**
+ * execute all files and jump out on the first !HANDLER_GO_ON
+ */
+ for (i = 0; i < files->used && ret == HANDLER_GO_ON; i++) {
+ data_string *ds = (data_string *)files->data[i];
+
+ if (buffer_string_is_empty(ds->value)) continue;
+
+ ret = magnet_attract(srv, con, p, ds->value);
+ }
+
+ if (con->error_handler_saved_status) {
+ /* retrieve (possibly modified) REDIRECT_STATUS and store as number */
+ unsigned long x;
+ buffer * const vb = http_header_env_get(con, CONST_STR_LEN("REDIRECT_STATUS"));
+ if (vb && (x = strtoul(vb->ptr, NULL, 10)) < 1000)
+ /*(simplified validity check x < 1000)*/
+ con->error_handler_saved_status =
+ con->error_handler_saved_status > 0 ? (int)x : -(int)x;
+ }
+
+ return ret;
+}
+
+URIHANDLER_FUNC(mod_magnet_uri_handler) {
+ plugin_data *p = p_d;
+
+ mod_magnet_patch_connection(srv, con, p);
+
+ return magnet_attract_array(srv, con, p, p->conf.url_raw);
+}
+
+URIHANDLER_FUNC(mod_magnet_physical) {
+ plugin_data *p = p_d;
+
+ mod_magnet_patch_connection(srv, con, p);
+
+ return magnet_attract_array(srv, con, p, p->conf.physical_path);
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_magnet_plugin_init(plugin *p);
+int mod_magnet_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("magnet");
+
+ p->init = mod_magnet_init;
+ p->handle_uri_clean = mod_magnet_uri_handler;
+ p->handle_physical = mod_magnet_physical;
+ p->set_defaults = mod_magnet_set_defaults;
+ p->cleanup = mod_magnet_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.c b/data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.c
new file mode 100644
index 000000000..204bb8e16
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.c
@@ -0,0 +1,129 @@
+#include "first.h"
+
+#include "mod_magnet_cache.h"
+#include "base.h"
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <lualib.h>
+#include <lauxlib.h>
+
+static script *script_init() {
+ script *sc;
+
+ sc = calloc(1, sizeof(*sc));
+ sc->name = buffer_init();
+ sc->etag = buffer_init();
+
+ return sc;
+}
+
+static void script_free(script *sc) {
+ if (!sc) return;
+
+ lua_pop(sc->L, 1); /* the function copy */
+
+ buffer_free(sc->name);
+ buffer_free(sc->etag);
+
+ lua_close(sc->L);
+
+ free(sc);
+}
+
+script_cache *script_cache_init() {
+ script_cache *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+void script_cache_free(script_cache *p) {
+ size_t i;
+
+ if (!p) return;
+
+ for (i = 0; i < p->used; i++) {
+ script_free(p->ptr[i]);
+ }
+
+ free(p->ptr);
+
+ free(p);
+}
+
+lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
+ size_t i;
+ script *sc = NULL;
+ stat_cache_entry *sce;
+
+ for (i = 0; i < cache->used; i++) {
+ sc = cache->ptr[i];
+
+ if (buffer_is_equal(name, sc->name)) {
+ sc->last_used = time(NULL);
+
+ /* oops, the script failed last time */
+
+ if (lua_gettop(sc->L) == 0) break;
+ force_assert(lua_gettop(sc->L) == 1);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+ lua_pop(sc->L, 1); /* pop the old function */
+ break;
+ }
+
+ stat_cache_etag_get(sce, con->etag_flags);
+ if (!buffer_is_equal(sce->etag, sc->etag)) {
+ /* the etag is outdated, reload the function */
+ lua_pop(sc->L, 1);
+ break;
+ }
+
+ force_assert(lua_isfunction(sc->L, -1));
+
+ 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_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_buffer(sc->etag, stat_cache_etag_get(sce, con->etag_flags));
+ }
+
+ force_assert(lua_isfunction(sc->L, -1));
+
+ return sc->L;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.h b/data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.h
new file mode 100644
index 000000000..04eb1ab18
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_magnet_cache.h
@@ -0,0 +1,32 @@
+#ifndef _MOD_MAGNET_CACHE_H_
+#define _MOD_MAGNET_CACHE_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.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
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_mysql_vhost.c b/data/lighttpd/lighttpd-1.4.53/src/mod_mysql_vhost.c
new file mode 100644
index 000000000..2af5cc2ba
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_mysql_vhost.c
@@ -0,0 +1,380 @@
+#include "first.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mysql.h>
+
+#include "base.h"
+#include "plugin.h"
+#include "fdevent.h"
+#include "log.h"
+
+#include "stat_cache.h"
+
+/*
+ * Plugin for lighttpd to use MySQL
+ * for domain to directory lookups,
+ * i.e virtual hosts (vhosts).
+ *
+ * /ada@riksnet.se 2004-12-06
+ */
+
+typedef struct {
+ MYSQL *mysql;
+ buffer *mysql_query;
+
+ buffer *mydb;
+ buffer *myuser;
+ buffer *mypass;
+ buffer *mysock;
+
+ buffer *hostname;
+ unsigned short port;
+} plugin_config;
+
+/* global plugin data */
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* per connection plugin data */
+typedef struct {
+ buffer *server_name;
+ buffer *document_root;
+} plugin_connection_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_mysql_vhost_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+/* cleanup the plugin data */
+SERVER_FUNC(mod_mysql_vhost_cleanup) {
+ 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;
+
+ mysql_close(s->mysql);
+
+ buffer_free(s->mysql_query);
+ buffer_free(s->mydb);
+ buffer_free(s->myuser);
+ buffer_free(s->mypass);
+ buffer_free(s->mysock);
+ buffer_free(s->hostname);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle the plugin per connection data */
+static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
+{
+ plugin_data *p = p_d;
+ plugin_connection_data *c = con->plugin_ctx[p->id];
+
+ UNUSED(srv);
+
+ if (c) return c;
+ c = calloc(1, sizeof(*c));
+
+ c->server_name = buffer_init();
+ c->document_root = buffer_init();
+
+ return con->plugin_ctx[p->id] = c;
+}
+
+/* destroy the plugin per connection data */
+CONNECTION_FUNC(mod_mysql_vhost_handle_connection_reset) {
+ plugin_data *p = p_d;
+ plugin_connection_data *c = con->plugin_ctx[p->id];
+
+ UNUSED(srv);
+
+ if (!c) return HANDLER_GO_ON;
+
+ buffer_free(c->server_name);
+ buffer_free(c->document_root);
+
+ free(c);
+
+ con->plugin_ctx[p->id] = NULL;
+ return HANDLER_GO_ON;
+}
+
+/* set configuration values */
+SERVER_FUNC(mod_mysql_vhost_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "mysql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->mysql_query = buffer_init();
+ s->mydb = buffer_init();
+ s->myuser = buffer_init();
+ s->mypass = buffer_init();
+ s->mysock = buffer_init();
+ s->hostname = buffer_init();
+ s->port = 0; /* default port for mysql */
+ s->mysql = NULL;
+
+ cv[0].destination = s->mydb;
+ cv[1].destination = s->myuser;
+ cv[2].destination = s->mypass;
+ cv[3].destination = s->mysock;
+ cv[4].destination = s->mysql_query;
+ cv[5].destination = s->hostname;
+ cv[6].destination = &(s->port);
+
+ p->config_storage[i] = s;
+
+ if (config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ /* required:
+ * - username
+ * - database
+ *
+ * optional:
+ * - password, default: empty
+ * - socket, default: mysql default
+ * - hostname, if set overrides socket
+ * - port, default: 3306
+ */
+
+ /* all have to be set */
+ if (!(buffer_string_is_empty(s->myuser) ||
+ buffer_string_is_empty(s->mydb))) {
+
+ if (NULL == (s->mysql = mysql_init(NULL))) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
+ return HANDLER_ERROR;
+ }
+
+#if MYSQL_VERSION_ID >= 50013
+ /* in mysql versions above 5.0.3 the reconnect flag is off by default */
+ {
+ char reconnect = 1;
+ mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
+ }
+#endif
+
+#define FOO(x) (buffer_string_is_empty(s->x) ? NULL : s->x->ptr)
+
+#if MYSQL_VERSION_ID >= 40100
+ /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
+ if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
+ FOO(mydb), s->port, FOO(mysock), CLIENT_MULTI_STATEMENTS)) {
+#else
+ if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
+ FOO(mydb), s->port, FOO(mysock), 0)) {
+#endif
+ log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
+ return HANDLER_ERROR;
+ }
+#undef FOO
+
+ fdevent_setfd_cloexec(s->mysql->net.fd);
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(mysql_query);
+ PATCH(mysql);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
+ PATCH(mysql_query);
+ }
+ }
+
+ if (s->mysql) {
+ PATCH(mysql);
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+/* handle document root request */
+CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+ plugin_data *p = p_d;
+ plugin_connection_data *c;
+ stat_cache_entry *sce;
+
+ unsigned cols;
+ MYSQL_ROW row;
+ MYSQL_RES *result = NULL;
+
+ /* no host specified? */
+ if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
+
+ mod_mysql_vhost_patch_connection(srv, con, p);
+
+ if (!p->conf.mysql) return HANDLER_GO_ON;
+ if (buffer_string_is_empty(p->conf.mysql_query)) return HANDLER_GO_ON;
+
+ /* sets up connection data if not done yet */
+ c = mod_mysql_vhost_connection_data(srv, con, p_d);
+
+ /* check if cached this connection */
+ if (buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
+
+ /* build and run SQL query */
+ buffer_clear(p->tmp_buf);
+ for (char *b = p->conf.mysql_query->ptr, *d; *b; b = d+1) {
+ if (NULL != (d = strchr(b, '?'))) {
+ /* escape the uri.authority */
+ unsigned long to_len;
+ buffer_append_string_len(p->tmp_buf, b, (size_t)(d - b));
+ buffer_string_prepare_append(p->tmp_buf, buffer_string_length(con->uri.authority) * 2);
+ to_len = mysql_real_escape_string(p->conf.mysql,
+ p->tmp_buf->ptr + buffer_string_length(p->tmp_buf),
+ CONST_BUF_LEN(con->uri.authority));
+ if ((unsigned long)~0 == to_len) goto ERR500;
+ buffer_commit(p->tmp_buf, to_len);
+ } else {
+ d = p->conf.mysql_query->ptr + buffer_string_length(p->conf.mysql_query);
+ buffer_append_string_len(p->tmp_buf, b, (size_t)(d - b));
+ break;
+ }
+ }
+ if (mysql_real_query(p->conf.mysql, CONST_BUF_LEN(p->tmp_buf))) {
+ log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
+ goto ERR500;
+ }
+ result = mysql_store_result(p->conf.mysql);
+ cols = mysql_num_fields(result);
+ row = mysql_fetch_row(result);
+ if (!row || cols < 1) {
+ /* no such virtual host */
+ mysql_free_result(result);
+#if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+#endif
+ return HANDLER_GO_ON;
+ }
+
+ /* sanity check that really is a directory */
+ buffer_copy_string(p->tmp_buf, row[0]);
+ buffer_append_slash(p->tmp_buf);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
+ goto ERR500;
+ }
+ if (!S_ISDIR(sce->st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
+ goto ERR500;
+ }
+
+ /* cache the data */
+ buffer_copy_buffer(c->server_name, con->uri.authority);
+ buffer_copy_buffer(c->document_root, p->tmp_buf);
+
+ mysql_free_result(result);
+#if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+#endif
+
+ /* fix virtual server and docroot */
+GO_ON:
+ buffer_copy_buffer(con->server_name, c->server_name);
+ buffer_copy_buffer(con->physical.doc_root, c->document_root);
+
+ return HANDLER_GO_ON;
+
+ERR500:
+ if (result) mysql_free_result(result);
+#if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+#endif
+ con->http_status = 500; /* Internal Error */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_mysql_vhost_plugin_init(plugin *p);
+int mod_mysql_vhost_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("mysql_vhost");
+
+ p->init = mod_mysql_vhost_init;
+ p->cleanup = mod_mysql_vhost_cleanup;
+ p->connection_reset = mod_mysql_vhost_handle_connection_reset;
+
+ p->set_defaults = mod_mysql_vhost_set_defaults;
+ p->handle_docroot = mod_mysql_vhost_handle_docroot;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_openssl.c b/data/lighttpd/lighttpd-1.4.53/src/mod_openssl.c
new file mode 100644
index 000000000..2da3de238
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_openssl.c
@@ -0,0 +1,2139 @@
+#include "first.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef USE_OPENSSL_KERBEROS
+#ifndef OPENSSL_NO_KRB5
+#define OPENSSL_NO_KRB5
+#endif
+#endif
+
+#include "sys-crypto.h"
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+
+#if ! defined OPENSSL_NO_TLSEXT && ! defined SSL_CTRL_SET_TLSEXT_HOSTNAME
+#define OPENSSL_NO_TLSEXT
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+#include <openssl/ecdh.h>
+#endif
+#endif
+
+#include "base.h"
+#include "http_header.h"
+#include "log.h"
+#include "plugin.h"
+
+typedef struct {
+ SSL_CTX *ssl_ctx; /* not patched */
+ /* SNI per host: with COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
+ EVP_PKEY *ssl_pemfile_pkey;
+ X509 *ssl_pemfile_x509;
+ STACK_OF(X509_NAME) *ssl_ca_file_cert_names;
+
+ unsigned short ssl_verifyclient;
+ unsigned short ssl_verifyclient_enforce;
+ unsigned short ssl_verifyclient_depth;
+ unsigned short ssl_verifyclient_export_cert;
+ buffer *ssl_verifyclient_username;
+
+ unsigned short ssl_disable_client_renegotiation;
+ unsigned short ssl_read_ahead;
+ unsigned short ssl_log_noise;
+
+ /*(used only during startup; not patched)*/
+ unsigned short ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */
+ unsigned short ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */
+ unsigned short ssl_empty_fragments; /* whether to not set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
+ unsigned short ssl_use_sslv2;
+ unsigned short ssl_use_sslv3;
+ buffer *ssl_pemfile;
+ buffer *ssl_privkey;
+ buffer *ssl_ca_file;
+ buffer *ssl_ca_crl_file;
+ buffer *ssl_ca_dn_file;
+ buffer *ssl_cipher_list;
+ buffer *ssl_dh_file;
+ buffer *ssl_ec_curve;
+ array *ssl_conf_cmd;
+ buffer *ssl_acme_tls_1;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+} plugin_data;
+
+static int ssl_is_init;
+/* need assigned p->id for deep access of module handler_ctx for connection
+ * i.e. handler_ctx *hctx = con->plugin_ctx[plugin_data_singleton->id]; */
+static plugin_data *plugin_data_singleton;
+#define LOCAL_SEND_BUFSIZE (64 * 1024)
+static char *local_send_buffer;
+
+typedef struct {
+ SSL *ssl;
+ connection *con;
+ int renegotiations; /* count of SSL_CB_HANDSHAKE_START */
+ unsigned short request_env_patched;
+ unsigned short alpn;
+ plugin_config conf;
+ server *srv;
+} handler_ctx;
+
+
+static handler_ctx *
+handler_ctx_init (void)
+{
+ handler_ctx *hctx = calloc(1, sizeof(*hctx));
+ force_assert(hctx);
+ return hctx;
+}
+
+
+static void
+handler_ctx_free (handler_ctx *hctx)
+{
+ if (hctx->ssl) SSL_free(hctx->ssl);
+ free(hctx);
+}
+
+
+INIT_FUNC(mod_openssl_init)
+{
+ plugin_data_singleton = (plugin_data *)calloc(1, sizeof(plugin_data));
+ #ifdef DEBUG_WOLFSSL
+ wolfSSL_Debugging_ON();
+ #endif
+ return plugin_data_singleton;
+}
+
+
+FREE_FUNC(mod_openssl_free)
+{
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ int copy;
+ if (NULL == s) continue;
+ copy = s->ssl_enabled && buffer_string_is_empty(s->ssl_pemfile);
+ buffer_free(s->ssl_pemfile);
+ buffer_free(s->ssl_privkey);
+ buffer_free(s->ssl_ca_file);
+ buffer_free(s->ssl_ca_crl_file);
+ buffer_free(s->ssl_ca_dn_file);
+ buffer_free(s->ssl_cipher_list);
+ buffer_free(s->ssl_dh_file);
+ buffer_free(s->ssl_ec_curve);
+ buffer_free(s->ssl_verifyclient_username);
+ array_free(s->ssl_conf_cmd);
+ buffer_free(s->ssl_acme_tls_1);
+
+ if (copy) continue;
+ SSL_CTX_free(s->ssl_ctx);
+ EVP_PKEY_free(s->ssl_pemfile_pkey);
+ X509_free(s->ssl_pemfile_x509);
+ if (NULL != s->ssl_ca_file_cert_names)
+ sk_X509_NAME_pop_free(s->ssl_ca_file_cert_names,X509_NAME_free);
+ }
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ if (ssl_is_init) {
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000L \
+ && !defined(LIBRESSL_VERSION_NUMBER)
+ /*(OpenSSL libraries handle thread init and deinit)
+ * https://github.com/openssl/openssl/pull/1048 */
+ #else
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+ #if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ ERR_remove_thread_state(NULL);
+ #else
+ ERR_remove_state(0);
+ #endif
+ EVP_cleanup();
+ #endif
+
+ free(local_send_buffer);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+
+static int
+safer_X509_NAME_oneline(X509_NAME *name, char *buf, size_t sz)
+{
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (bio) {
+ int len = X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE);
+ BIO_gets(bio, buf, (int)sz); /*(may be truncated if len >= sz)*/
+ BIO_free(bio);
+ return len; /*return value has similar semantics to that of snprintf()*/
+ }
+ else {
+ buf[0] = '\0';
+ return -1;
+ }
+}
+
+
+static void
+ssl_info_callback (const SSL *ssl, int where, int ret)
+{
+ UNUSED(ret);
+
+ if (0 != (where & SSL_CB_HANDSHAKE_START)) {
+ handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
+ if (hctx->renegotiations >= 0) ++hctx->renegotiations;
+ }
+ #ifdef TLS1_3_VERSION
+ /* https://github.com/openssl/openssl/issues/5721
+ * "TLSv1.3 unexpected InfoCallback after handshake completed" */
+ if (0 != (where & SSL_CB_HANDSHAKE_DONE)) {
+ /* SSL_version() is valid after initial handshake completed */
+ if (SSL_version(ssl) >= TLS1_3_VERSION) {
+ /* https://wiki.openssl.org/index.php/TLS1.3
+ * "Renegotiation is not possible in a TLSv1.3 connection" */
+ handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
+ hctx->renegotiations = -1;
+ }
+ }
+ #endif
+}
+
+/* https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_verify(3)#EXAMPLES */
+static int
+verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+ char buf[256];
+ X509 *err_cert;
+ int err, depth;
+ SSL *ssl;
+ handler_ctx *hctx;
+ server *srv;
+
+ err = X509_STORE_CTX_get_error(ctx);
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+
+ /*
+ * Retrieve the pointer to the SSL of the connection currently treated
+ * and the application specific data stored into the SSL object.
+ */
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ hctx = (handler_ctx *) SSL_get_app_data(ssl);
+ srv = hctx->srv;
+
+ /*
+ * Catch a too long certificate chain. The depth limit set using
+ * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
+ * that whenever the "depth>verify_depth" condition is met, we
+ * have violated the limit and want to log this error condition.
+ * We must do it here, because the CHAIN_TOO_LONG error would not
+ * be found explicitly; only errors introduced by cutting off the
+ * additional certificates would be logged.
+ */
+ if (depth > hctx->conf.ssl_verifyclient_depth) {
+ preverify_ok = 0;
+ err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
+ X509_STORE_CTX_set_error(ctx, err);
+ }
+
+ if (preverify_ok && 0 == depth
+ && !buffer_string_is_empty(hctx->conf.ssl_ca_dn_file)
+ && !buffer_string_is_empty(hctx->conf.ssl_ca_file)) {
+ /* verify that client cert is issued by CA in ssl.ca-dn-file
+ * if both ssl.ca-dn-file and ssl.ca-file were configured */
+ STACK_OF(X509_NAME) * const names = hctx->conf.ssl_ca_file_cert_names;
+ X509_NAME *issuer;
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ err_cert = X509_STORE_CTX_get_current_cert(ctx);
+ #else
+ err_cert = ctx->current_cert;
+ #endif
+ if (NULL == err_cert) return !hctx->conf.ssl_verifyclient_enforce;
+ issuer = X509_get_issuer_name(err_cert);
+ #if 0 /*(?desirable/undesirable to have ssl_ca_file_cert_names sorted?)*/
+ if (-1 != sk_X509_NAME_find(names, issuer))
+ return preverify_ok; /* match */
+ #else
+ for (int i = 0, len = sk_X509_NAME_num(names); i < len; ++i) {
+ if (0 == X509_NAME_cmp(sk_X509_NAME_value(names, i), issuer))
+ return preverify_ok; /* match */
+ }
+ #endif
+
+ preverify_ok = 0;
+ err = X509_V_ERR_CERT_REJECTED;
+ X509_STORE_CTX_set_error(ctx, err);
+ }
+
+ if (preverify_ok) {
+ return preverify_ok;
+ }
+
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ err_cert = X509_STORE_CTX_get_current_cert(ctx);
+ #else
+ err_cert = ctx->current_cert;
+ #endif
+ if (NULL == err_cert) return !hctx->conf.ssl_verifyclient_enforce;
+ safer_X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf));
+ log_error_write(srv, __FILE__, __LINE__, "SDSSSDSS",
+ "SSL: verify error:num=", err, ":",
+ X509_verify_cert_error_string(err), ":depth=", depth,
+ ":subject=", buf);
+
+ /*
+ * At this point, err contains the last verification error. We can use
+ * it for something special
+ */
+ if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
+ err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
+ safer_X509_NAME_oneline(X509_get_issuer_name(err_cert),buf,sizeof(buf));
+ log_error_write(srv, __FILE__, __LINE__, "SS", "SSL: issuer=", buf);
+ }
+
+ return !hctx->conf.ssl_verifyclient_enforce;
+}
+
+#ifndef OPENSSL_NO_TLSEXT
+static int mod_openssl_patch_connection (server *srv, connection *con, handler_ctx *hctx);
+
+static int
+network_ssl_servername_callback (SSL *ssl, int *al, server *srv)
+{
+ const char *servername;
+ handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
+ connection *con = hctx->con;
+ size_t len;
+ UNUSED(al);
+
+ buffer_copy_string(con->uri.scheme, "https");
+
+ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (NULL == servername) {
+#if 0
+ /* this "error" just means the client didn't support it */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "failed to get TLS server name");
+#endif
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ len = strlen(servername);
+ if (len >= 1024) { /*(expecting < 256)*/
+ log_error_write(srv, __FILE__, __LINE__, "sss", "SSL:",
+ "SNI name too long", servername);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ /* use SNI to patch mod_openssl config and then reset COMP_HTTP_HOST */
+ buffer_copy_string_len(con->uri.authority, servername, len);
+ buffer_to_lower(con->uri.authority);
+ #if 0
+ /*(con->uri.authority used below for configuration before request read;
+ * revisit for h2)*/
+ if (0 != http_request_host_policy(con, con->uri.authority, con->uri.scheme))
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ #endif
+
+ con->conditional_is_valid[COMP_HTTP_SCHEME] = 1;
+ con->conditional_is_valid[COMP_HTTP_HOST] = 1;
+ mod_openssl_patch_connection(srv, con, hctx);
+ /* reset COMP_HTTP_HOST so that conditions re-run after request hdrs read */
+ /*(done in response.c:config_cond_cache_reset() after request hdrs read)*/
+ /*config_cond_cache_reset_item(con, COMP_HTTP_HOST);*/
+ /*buffer_clear(con->uri.authority);*/
+
+ if (NULL == hctx->conf.ssl_pemfile_x509
+ || NULL == hctx->conf.ssl_pemfile_pkey) {
+ /* x509/pkey available <=> pemfile was set <=> pemfile got patched:
+ * so this should never happen, unless you nest $SERVER["socket"] */
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "no certificate/private key for TLS server name",
+ con->uri.authority);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ /* first set certificate!
+ * setting private key checks whether certificate matches it */
+ if (1 != SSL_use_certificate(ssl, hctx->conf.ssl_pemfile_x509)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
+ "failed to set certificate for TLS server name",
+ con->uri.authority,
+ ERR_error_string(ERR_get_error(), NULL));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ if (1 != SSL_use_PrivateKey(ssl, hctx->conf.ssl_pemfile_pkey)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
+ "failed to set private key for TLS server name",
+ con->uri.authority,
+ ERR_error_string(ERR_get_error(), NULL));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ if (hctx->conf.ssl_verifyclient) {
+ int mode;
+ if (NULL == hctx->conf.ssl_ca_file_cert_names) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
+ "can't verify client without ssl.ca-file "
+ "or ssl.ca-dn-file for TLS server name",
+ con->uri.authority,
+ ERR_error_string(ERR_get_error(), NULL));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ SSL_set_client_CA_list(
+ ssl, SSL_dup_CA_list(hctx->conf.ssl_ca_file_cert_names));
+ /* forcing verification here is really not that useful
+ * -- a client could just connect without SNI */
+ mode = SSL_VERIFY_PEER;
+ if (hctx->conf.ssl_verifyclient_enforce) {
+ mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ }
+ SSL_set_verify(ssl, mode, verify_callback);
+ SSL_set_verify_depth(ssl, hctx->conf.ssl_verifyclient_depth + 1);
+ } else {
+ SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+
+static X509 *
+x509_load_pem_file (server *srv, const char *file)
+{
+ BIO *in;
+ X509 *x = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (NULL == in) {
+ log_error_write(srv, __FILE__, __LINE__, "S",
+ "SSL: BIO_new(BIO_s_file()) failed");
+ goto error;
+ }
+
+ if (BIO_read_filename(in,file) <= 0) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "SSL: BIO_read_filename('", file,"') failed");
+ goto error;
+ }
+
+ x = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ if (NULL == x) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "SSL: couldn't read X509 certificate from '", file,"'");
+ goto error;
+ }
+
+ BIO_free(in);
+ return x;
+
+error:
+ if (NULL != in) BIO_free(in);
+ return NULL;
+}
+
+
+static EVP_PKEY *
+evp_pkey_load_pem_file (server *srv, const char *file)
+{
+ BIO *in;
+ EVP_PKEY *x = NULL;
+
+ in = BIO_new(BIO_s_file());
+ if (NULL == in) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: BIO_new(BIO_s_file()) failed");
+ goto error;
+ }
+
+ if (BIO_read_filename(in,file) <= 0) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "SSL: BIO_read_filename('", file,"') failed");
+ goto error;
+ }
+
+ x = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
+ if (NULL == x) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "SSL: couldn't read private key from '", file,"'");
+ goto error;
+ }
+
+ BIO_free(in);
+ return x;
+
+error:
+ if (NULL != in) BIO_free(in);
+ return NULL;
+}
+
+
+static int
+network_openssl_load_pemfile (server *srv, plugin_config *s, size_t ndx)
+{
+ #ifdef OPENSSL_NO_TLSEXT
+ data_config *dc = (data_config *)srv->config_context->data[ndx];
+ if ((ndx > 0 && (COMP_SERVER_SOCKET != dc->comp
+ || dc->cond != CONFIG_COND_EQ)) || !s->ssl_enabled) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "ssl.pemfile only works in SSL socket binding context "
+ "as openssl version does not support TLS extensions");
+ return -1;
+ }
+ #else
+ UNUSED(ndx);
+ #endif
+
+ s->ssl_pemfile_x509 = x509_load_pem_file(srv, s->ssl_pemfile->ptr);
+ if (NULL == s->ssl_pemfile_x509) return -1;
+ s->ssl_pemfile_pkey = !buffer_string_is_empty(s->ssl_privkey)
+ ? evp_pkey_load_pem_file(srv, s->ssl_privkey->ptr)
+ : evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr);
+ if (NULL == s->ssl_pemfile_pkey) return -1;
+
+ if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbb", "SSL:",
+ "Private key does not match the certificate public key,"
+ " reason:", ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile, s->ssl_privkey);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifndef OPENSSL_NO_TLSEXT
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002000
+
+static int
+mod_openssl_acme_tls_1 (SSL *ssl, handler_ctx *hctx)
+{
+ server *srv = hctx->srv;
+ buffer *b = srv->tmp_buf;
+ buffer *name = hctx->con->uri.authority;
+ X509 *ssl_pemfile_x509 = NULL;
+ EVP_PKEY *ssl_pemfile_pkey = NULL;
+ size_t len;
+ int rc = SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/
+ if (buffer_string_is_empty(hctx->conf.ssl_acme_tls_1))
+ return SSL_TLSEXT_ERR_NOACK; /*(reuse value here for not-configured)*/
+ buffer_copy_buffer(b, hctx->conf.ssl_acme_tls_1);
+ buffer_append_slash(b);
+
+ /* check if SNI set server name (required for acme-tls/1 protocol)
+ * and perform simple path checks for no '/'
+ * and no leading '.' (e.g. ignore "." or ".." or anything beginning '.') */
+ if (buffer_string_is_empty(name)) return rc;
+ if (NULL != strchr(name->ptr, '/')) return rc;
+ if (name->ptr[0] == '.') return rc;
+ #if 0
+ if (0 != http_request_host_policy(hctx->con, name, hctx->con->uri.scheme))
+ return rc;
+ #endif
+ buffer_append_string_buffer(b, name);
+ len = buffer_string_length(b);
+
+ do {
+ buffer_append_string_len(b, CONST_STR_LEN(".crt.pem"));
+ ssl_pemfile_x509 = x509_load_pem_file(srv, b->ptr);
+ if (NULL == ssl_pemfile_x509) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "Failed to load acme-tls/1 pemfile:", b);
+ break;
+ }
+
+ buffer_string_set_length(b, len); /*(remove ".crt.pem")*/
+ buffer_append_string_len(b, CONST_STR_LEN(".key.pem"));
+ ssl_pemfile_pkey = evp_pkey_load_pem_file(srv, b->ptr);
+ if (NULL == ssl_pemfile_pkey) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "Failed to load acme-tls/1 pemfile:", b);
+ break;
+ }
+
+ #if 0 /* redundant with below? */
+ if (!X509_check_private_key(ssl_pemfile_x509, ssl_pemfile_pkey)) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
+ "Private key does not match acme-tls/1 certificate public key,"
+ " reason:" ERR_error_string(ERR_get_error(), NULL), b);
+ break;
+ }
+ #endif
+
+ /* first set certificate!
+ * setting private key checks whether certificate matches it */
+ if (1 != SSL_use_certificate(ssl, ssl_pemfile_x509)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
+ "failed to set acme-tls/1 certificate for TLS server name",
+ name, ERR_error_string(ERR_get_error(), NULL));
+ break;
+ }
+
+ if (1 != SSL_use_PrivateKey(ssl, ssl_pemfile_pkey)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
+ "failed to set acme-tls/1 private key for TLS server name",
+ name, ERR_error_string(ERR_get_error(), NULL));
+ break;
+ }
+
+ rc = SSL_TLSEXT_ERR_OK;
+ } while (0);
+
+ if (ssl_pemfile_pkey) EVP_PKEY_free(ssl_pemfile_pkey);
+ if (ssl_pemfile_x509) X509_free(ssl_pemfile_x509);
+
+ return rc;
+}
+
+enum {
+ MOD_OPENSSL_ALPN_HTTP11 = 1
+ ,MOD_OPENSSL_ALPN_HTTP10 = 2
+ ,MOD_OPENSSL_ALPN_H2 = 3
+ ,MOD_OPENSSL_ALPN_ACME_TLS_1 = 4
+};
+
+/* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */
+static int
+mod_openssl_alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+{
+ handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
+ unsigned short proto;
+ UNUSED(arg);
+
+ for (unsigned int i = 0, n; i < inlen; i += n) {
+ n = in[i++];
+ if (i+n > inlen) break;
+ switch (n) {
+ #if 0
+ case 2: /* "h2" */
+ if (in[i] == 'h' && in[i+1] == '2') {
+ proto = MOD_OPENSSL_ALPN_H2;
+ break;
+ }
+ continue;
+ #endif
+ case 8: /* "http/1.1" "http/1.0" */
+ if (0 == memcmp(in+i, "http/1.", 7)) {
+ if (in[i+7] == '1') {
+ proto = MOD_OPENSSL_ALPN_HTTP11;
+ break;
+ }
+ if (in[i+7] == '0') {
+ proto = MOD_OPENSSL_ALPN_HTTP10;
+ break;
+ }
+ }
+ continue;
+ case 10: /* "acme-tls/1" */
+ if (0 == memcmp(in+i, "acme-tls/1", 10)) {
+ int rc = mod_openssl_acme_tls_1(ssl, hctx);
+ if (rc == SSL_TLSEXT_ERR_OK) {
+ proto = MOD_OPENSSL_ALPN_ACME_TLS_1;
+ break;
+ }
+ /* (use SSL_TLSEXT_ERR_NOACK for not-configured) */
+ if (rc == SSL_TLSEXT_ERR_NOACK) continue;
+ return rc;
+ }
+ continue;
+ default:
+ continue;
+ }
+
+ hctx->alpn = proto;
+ *out = in+i;
+ *outlen = n;
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+ #if OPENSSL_VERSION_NUMBER < 0x10100000L
+ return SSL_TLSEXT_ERR_NOACK;
+ #else
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ #endif
+}
+
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000 */
+
+#endif /* OPENSSL_NO_TLSEXT */
+
+
+static int
+network_openssl_ssl_conf_cmd (server *srv, plugin_config *s)
+{
+ #ifdef SSL_CONF_FLAG_CMDLINE
+
+ int rc = 0;
+ data_string *ds;
+ SSL_CONF_CTX * const cctx = SSL_CONF_CTX_new();
+ SSL_CONF_CTX_set_ssl_ctx(cctx, s->ssl_ctx);
+ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE
+ | SSL_CONF_FLAG_SERVER
+ | SSL_CONF_FLAG_SHOW_ERRORS
+ | SSL_CONF_FLAG_CERTIFICATE);
+
+ /* always disable null and export ciphers */
+ ds = (data_string *)
+ array_get_element_klen(s->ssl_conf_cmd,
+ CONST_STR_LEN("CipherString"));
+ if (NULL != ds) {
+ buffer_append_string_len(ds->value,
+ CONST_STR_LEN(":!aNULL:!eNULL:!EXP"));
+ }
+
+ for (size_t i = 0; i < s->ssl_conf_cmd->used; ++i) {
+ ds = (data_string *)s->ssl_conf_cmd->data[i];
+ ERR_clear_error();
+ if (SSL_CONF_cmd(cctx, ds->key->ptr, ds->value->ptr) <= 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbbss", "SSL:",
+ "SSL_CONF_cmd", ds->key, ds->value, ":",
+ ERR_error_string(ERR_get_error(), NULL));
+ rc = -1;
+ break;
+ }
+ }
+
+ if (0 == rc && 1 != SSL_CONF_CTX_finish(cctx)) {
+ log_error_write(srv, __FILE__, __LINE__, "sss", "SSL:",
+ "SSL_CONF_CTX_finish():",
+ ERR_error_string(ERR_get_error(), NULL));
+ rc = -1;
+ }
+
+ SSL_CONF_CTX_free(cctx);
+ return rc;
+
+ #else
+
+ UNUSED(s);
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "ssl.openssl.ssl-conf-cmd not available; ignored");
+ return 0;
+
+ #endif
+}
+
+
+static int
+network_init_ssl (server *srv, void *p_d)
+{
+ plugin_data *p = p_d;
+
+ #ifndef OPENSSL_NO_DH
+ /* 1024-bit MODP Group with 160-bit prime order subgroup (RFC5114)
+ * -----BEGIN DH PARAMETERS-----
+ * MIIBDAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y
+ * mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4
+ * +qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV
+ * w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0
+ * sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR
+ * jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5QICAKA=
+ * -----END DH PARAMETERS-----
+ */
+
+ static const unsigned char dh1024_p[]={
+ 0xB1,0x0B,0x8F,0x96,0xA0,0x80,0xE0,0x1D,0xDE,0x92,0xDE,0x5E,
+ 0xAE,0x5D,0x54,0xEC,0x52,0xC9,0x9F,0xBC,0xFB,0x06,0xA3,0xC6,
+ 0x9A,0x6A,0x9D,0xCA,0x52,0xD2,0x3B,0x61,0x60,0x73,0xE2,0x86,
+ 0x75,0xA2,0x3D,0x18,0x98,0x38,0xEF,0x1E,0x2E,0xE6,0x52,0xC0,
+ 0x13,0xEC,0xB4,0xAE,0xA9,0x06,0x11,0x23,0x24,0x97,0x5C,0x3C,
+ 0xD4,0x9B,0x83,0xBF,0xAC,0xCB,0xDD,0x7D,0x90,0xC4,0xBD,0x70,
+ 0x98,0x48,0x8E,0x9C,0x21,0x9A,0x73,0x72,0x4E,0xFF,0xD6,0xFA,
+ 0xE5,0x64,0x47,0x38,0xFA,0xA3,0x1A,0x4F,0xF5,0x5B,0xCC,0xC0,
+ 0xA1,0x51,0xAF,0x5F,0x0D,0xC8,0xB4,0xBD,0x45,0xBF,0x37,0xDF,
+ 0x36,0x5C,0x1A,0x65,0xE6,0x8C,0xFD,0xA7,0x6D,0x4D,0xA7,0x08,
+ 0xDF,0x1F,0xB2,0xBC,0x2E,0x4A,0x43,0x71,
+ };
+
+ static const unsigned char dh1024_g[]={
+ 0xA4,0xD1,0xCB,0xD5,0xC3,0xFD,0x34,0x12,0x67,0x65,0xA4,0x42,
+ 0xEF,0xB9,0x99,0x05,0xF8,0x10,0x4D,0xD2,0x58,0xAC,0x50,0x7F,
+ 0xD6,0x40,0x6C,0xFF,0x14,0x26,0x6D,0x31,0x26,0x6F,0xEA,0x1E,
+ 0x5C,0x41,0x56,0x4B,0x77,0x7E,0x69,0x0F,0x55,0x04,0xF2,0x13,
+ 0x16,0x02,0x17,0xB4,0xB0,0x1B,0x88,0x6A,0x5E,0x91,0x54,0x7F,
+ 0x9E,0x27,0x49,0xF4,0xD7,0xFB,0xD7,0xD3,0xB9,0xA9,0x2E,0xE1,
+ 0x90,0x9D,0x0D,0x22,0x63,0xF8,0x0A,0x76,0xA6,0xA2,0x4C,0x08,
+ 0x7A,0x09,0x1F,0x53,0x1D,0xBF,0x0A,0x01,0x69,0xB6,0xA2,0x8A,
+ 0xD6,0x62,0xA4,0xD1,0x8E,0x73,0xAF,0xA3,0x2D,0x77,0x9D,0x59,
+ 0x18,0xD0,0x8B,0xC8,0x85,0x8F,0x4D,0xCE,0xF9,0x7C,0x2A,0x24,
+ 0x85,0x5E,0x6E,0xEB,0x22,0xB3,0xB2,0xE5,
+ };
+ #endif
+
+ /* load SSL certificates */
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ #ifndef SSL_OP_NO_COMPRESSION
+ #define SSL_OP_NO_COMPRESSION 0
+ #endif
+ #ifndef SSL_MODE_RELEASE_BUFFERS /* OpenSSL >= 1.0.0 */
+ #define SSL_MODE_RELEASE_BUFFERS 0
+ #endif
+ long ssloptions = SSL_OP_ALL
+ | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ | SSL_OP_NO_COMPRESSION;
+
+ if (s->ssl_enabled) {
+ if (buffer_string_is_empty(s->ssl_pemfile)) {
+ /* inherit ssl settings from global scope
+ * (if only ssl.engine = "enable" and no other ssl.* settings)*/
+ if (0 != i && p->config_storage[0]->ssl_enabled) {
+ s->ssl_ctx = p->config_storage[0]->ssl_ctx;
+ continue;
+ }
+ /* PEM file is require */
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ssl.pemfile has to be set "
+ "when ssl.engine = \"enable\"");
+ return -1;
+ }
+ }
+
+ if (buffer_string_is_empty(s->ssl_pemfile)
+ && buffer_string_is_empty(s->ssl_ca_dn_file)
+ && buffer_string_is_empty(s->ssl_ca_file)) continue;
+
+ if (ssl_is_init == 0) {
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000L \
+ && !defined(LIBRESSL_VERSION_NUMBER)
+ OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
+ |OPENSSL_INIT_LOAD_CRYPTO_STRINGS,NULL);
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
+ |OPENSSL_INIT_ADD_ALL_DIGESTS
+ |OPENSSL_INIT_LOAD_CONFIG, NULL);
+ #else
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ #endif
+ ssl_is_init = 1;
+
+ if (0 == RAND_status()) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "not enough entropy in the pool");
+ return -1;
+ }
+
+ local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
+ force_assert(NULL != local_send_buffer);
+ }
+
+ if (!buffer_string_is_empty(s->ssl_pemfile)) {
+ #ifdef OPENSSL_NO_TLSEXT
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ if (COMP_HTTP_HOST == dc->comp) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "can't use ssl.pemfile with $HTTP[\"host\"], "
+ "openssl version does not support TLS "
+ "extensions");
+ return -1;
+ }
+ #endif
+ if (network_openssl_load_pemfile(srv, s, i)) return -1;
+ }
+
+
+ if (!buffer_string_is_empty(s->ssl_ca_dn_file)) {
+ s->ssl_ca_file_cert_names =
+ SSL_load_client_CA_file(s->ssl_ca_dn_file->ptr);
+ if (NULL == s->ssl_ca_file_cert_names) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_ca_dn_file);
+ }
+ }
+
+ if (NULL == s->ssl_ca_file_cert_names
+ && !buffer_string_is_empty(s->ssl_ca_file)) {
+ s->ssl_ca_file_cert_names =
+ SSL_load_client_CA_file(s->ssl_ca_file->ptr);
+ if (NULL == s->ssl_ca_file_cert_names) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_ca_file);
+ }
+ }
+
+ if (buffer_string_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue;
+
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ s->ssl_ctx = (!s->ssl_use_sslv2 && !s->ssl_use_sslv3)
+ ? SSL_CTX_new(TLS_server_method())
+ : SSL_CTX_new(SSLv23_server_method());
+ #else
+ s->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ #endif
+ if (NULL == s->ssl_ctx) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ /* completely useless identifier;
+ * required for client cert verification to work with sessions */
+ if (0 == SSL_CTX_set_session_id_context(
+ s->ssl_ctx,(const unsigned char*)CONST_STR_LEN("lighttpd"))){
+ log_error_write(srv, __FILE__, __LINE__, "ss:s", "SSL:",
+ "failed to set session context",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (s->ssl_empty_fragments) {
+ #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+ ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+ #else
+ ssloptions &= ~0x00000800L; /* hardcode constant */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "WARNING: SSL:",
+ "'insert empty fragments' not supported by the "
+ "openssl version used to compile lighttpd with");
+ #endif
+ }
+
+ SSL_CTX_set_options(s->ssl_ctx, ssloptions);
+ SSL_CTX_set_info_callback(s->ssl_ctx, ssl_info_callback);
+
+ #ifndef HAVE_WOLFSSL_SSL_H /*(wolfSSL does not support SSLv2)*/
+ if (!s->ssl_use_sslv2 && 0 != SSL_OP_NO_SSLv2) {
+ /* disable SSLv2 */
+ if ((SSL_OP_NO_SSLv2
+ & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2))
+ != SSL_OP_NO_SSLv2) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+ #endif
+
+ if (!s->ssl_use_sslv3 && 0 != SSL_OP_NO_SSLv3) {
+ /* disable SSLv3 */
+ if ((SSL_OP_NO_SSLv3
+ & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3))
+ != SSL_OP_NO_SSLv3) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (!buffer_string_is_empty(s->ssl_cipher_list)) {
+ /* Disable support for low encryption ciphers */
+ if (SSL_CTX_set_cipher_list(s->ssl_ctx,s->ssl_cipher_list->ptr)!=1){
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (s->ssl_honor_cipher_order) {
+ SSL_CTX_set_options(s->ssl_ctx,SSL_OP_CIPHER_SERVER_PREFERENCE);
+ }
+ }
+
+ #ifndef OPENSSL_NO_DH
+ {
+ DH *dh;
+ /* Support for Diffie-Hellman key exchange */
+ if (!buffer_string_is_empty(s->ssl_dh_file)) {
+ /* DH parameters from file */
+ BIO *bio;
+ bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r");
+ if (bio == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "SSL: Unable to open file",
+ s->ssl_dh_file->ptr);
+ return -1;
+ }
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (dh == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "SSL: PEM_read_bio_DHparams failed",
+ s->ssl_dh_file->ptr);
+ return -1;
+ }
+ } else {
+ BIGNUM *dh_p, *dh_g;
+ /* Default DH parameters from RFC5114 */
+ dh = DH_new();
+ if (dh == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: DH_new () failed");
+ return -1;
+ }
+ dh_p = BN_bin2bn(dh1024_p,sizeof(dh1024_p), NULL);
+ dh_g = BN_bin2bn(dh1024_g,sizeof(dh1024_g), NULL);
+ if ((dh_p == NULL) || (dh_g == NULL)) {
+ DH_free(dh);
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: BN_bin2bn () failed");
+ return -1;
+ }
+ #if OPENSSL_VERSION_NUMBER < 0x10100000L \
+ || defined(LIBRESSL_VERSION_NUMBER)
+ dh->p = dh_p;
+ dh->g = dh_g;
+ dh->length = 160;
+ #else
+ DH_set0_pqg(dh, dh_p, NULL, dh_g);
+ DH_set_length(dh, 160);
+ #endif
+ }
+ SSL_CTX_set_tmp_dh(s->ssl_ctx,dh);
+ SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE);
+ DH_free(dh);
+ }
+ #else
+ if (!buffer_string_is_empty(s->ssl_dh_file)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "SSL: openssl compiled without DH support, "
+ "can't load parameters from", s->ssl_dh_file->ptr);
+ }
+ #endif
+
+ #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+ #ifndef OPENSSL_NO_ECDH
+ {
+ int nid = 0;
+ /* Support for Elliptic-Curve Diffie-Hellman key exchange */
+ if (!buffer_string_is_empty(s->ssl_ec_curve)) {
+ /* OpenSSL only supports the "named curves"
+ * from RFC 4492, section 5.1.1. */
+ nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr);
+ if (nid == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "SSL: Unknown curve name",
+ s->ssl_ec_curve->ptr);
+ return -1;
+ }
+ } else {
+ #if OPENSSL_VERSION_NUMBER < 0x10002000
+ /* Default curve */
+ nid = OBJ_sn2nid("prime256v1");
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L \
+ || defined(LIBRESSL_VERSION_NUMBER)
+ if (!SSL_CTX_set_ecdh_auto(s->ssl_ctx, 1)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: SSL_CTX_set_ecdh_auto() failed");
+ }
+ #endif
+ }
+ if (nid) {
+ EC_KEY *ecdh;
+ ecdh = EC_KEY_new_by_curve_name(nid);
+ if (ecdh == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "SSL: Unable to create curve",
+ s->ssl_ec_curve->ptr);
+ return -1;
+ }
+ SSL_CTX_set_tmp_ecdh(s->ssl_ctx,ecdh);
+ SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_ECDH_USE);
+ EC_KEY_free(ecdh);
+ }
+ }
+ #endif
+ #endif
+
+ /* load all ssl.ca-files specified in the config into each SSL_CTX
+ * to be prepared for SNI */
+ for (size_t j = 0; j < srv->config_context->used; ++j) {
+ plugin_config *s1 = p->config_storage[j];
+
+ if (!buffer_string_is_empty(s1->ssl_ca_dn_file)) {
+ if (1 != SSL_CTX_load_verify_locations(
+ s->ssl_ctx, s1->ssl_ca_dn_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s1->ssl_ca_dn_file);
+ return -1;
+ }
+ }
+ if (!buffer_string_is_empty(s1->ssl_ca_file)) {
+ if (1 != SSL_CTX_load_verify_locations(
+ s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s1->ssl_ca_file);
+ return -1;
+ }
+ }
+ }
+
+ if (s->ssl_verifyclient) {
+ int mode;
+ if (NULL == s->ssl_ca_file_cert_names) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: You specified ssl.verifyclient.activate "
+ "but no ssl.ca-file or ssl.ca-dn-file");
+ return -1;
+ }
+ SSL_CTX_set_client_CA_list(
+ s->ssl_ctx, SSL_dup_CA_list(s->ssl_ca_file_cert_names));
+ mode = SSL_VERIFY_PEER;
+ if (s->ssl_verifyclient_enforce) {
+ mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ }
+ SSL_CTX_set_verify(s->ssl_ctx, mode, verify_callback);
+ SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth + 1);
+ if (!buffer_string_is_empty(s->ssl_ca_crl_file)) {
+ X509_STORE *store = SSL_CTX_get_cert_store(s->ssl_ctx);
+ if (1 != X509_STORE_load_locations(store, s->ssl_ca_crl_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_crl_file);
+ return -1;
+ }
+ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+ }
+ }
+
+ if (1 != SSL_CTX_use_certificate_chain_file(s->ssl_ctx,
+ s->ssl_pemfile->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile);
+ return -1;
+ }
+
+ if (1 != SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile, s->ssl_privkey);
+ return -1;
+ }
+
+ if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbb", "SSL:",
+ "Private key does not match the certificate public "
+ "key, reason:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile, s->ssl_privkey);
+ return -1;
+ }
+ SSL_CTX_set_default_read_ahead(s->ssl_ctx, s->ssl_read_ahead);
+ SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx)
+ | SSL_MODE_ENABLE_PARTIAL_WRITE
+ | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
+ | SSL_MODE_RELEASE_BUFFERS);
+
+ #ifndef OPENSSL_NO_TLSEXT
+ if (!SSL_CTX_set_tlsext_servername_callback(
+ s->ssl_ctx, network_ssl_servername_callback) ||
+ !SSL_CTX_set_tlsext_servername_arg(s->ssl_ctx, srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "failed to initialize TLS servername callback, "
+ "openssl library does not support TLS servername "
+ "extension");
+ return -1;
+ }
+
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000
+ SSL_CTX_set_alpn_select_cb(s->ssl_ctx,mod_openssl_alpn_select_cb,NULL);
+ #endif
+ #endif
+
+ if (s->ssl_conf_cmd->used) {
+ if (0 != network_openssl_ssl_conf_cmd(srv, s)) return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+SETDEFAULTS_FUNC(mod_openssl_set_defaults)
+{
+ plugin_data *p = p_d;
+ config_values_t cv[] = {
+ { "debug.log-ssl-noise", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "ssl.dh-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "ssl.ec-curve", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "ssl.cipher-list", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "ssl.honor-cipher-order", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "ssl.empty-fragments", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { "ssl.disable-client-renegotiation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { "ssl.read-ahead", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
+ { "ssl.verifyclient.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
+ { "ssl.verifyclient.enforce", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { "ssl.verifyclient.depth", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+ { "ssl.verifyclient.username", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
+ { "ssl.verifyclient.exportcert", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
+ { "ssl.use-sslv2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
+ { "ssl.use-sslv3", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
+ { "ssl.ca-crl-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
+ { "ssl.ca-dn-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
+ { "ssl.openssl.ssl-conf-cmd", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
+ { "ssl.acme-tls-1", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
+ { "ssl.privkey", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+
+ s->ssl_enabled = 0;
+ s->ssl_pemfile = buffer_init();
+ s->ssl_privkey = buffer_init();
+ s->ssl_ca_file = buffer_init();
+ s->ssl_ca_crl_file = buffer_init();
+ s->ssl_ca_dn_file = buffer_init();
+ s->ssl_cipher_list = buffer_init();
+ s->ssl_dh_file = buffer_init();
+ s->ssl_ec_curve = buffer_init();
+ s->ssl_honor_cipher_order = 1;
+ s->ssl_empty_fragments = 0;
+ s->ssl_use_sslv2 = 0;
+ s->ssl_use_sslv3 = 0;
+ s->ssl_verifyclient = 0;
+ s->ssl_verifyclient_enforce = 1;
+ s->ssl_verifyclient_username = buffer_init();
+ s->ssl_verifyclient_depth = 9;
+ s->ssl_verifyclient_export_cert = 0;
+ s->ssl_disable_client_renegotiation = 1;
+ s->ssl_read_ahead = (0 == i)
+ ? 0
+ : p->config_storage[0]->ssl_read_ahead;
+ if (0 != i) buffer_copy_buffer(s->ssl_ca_crl_file, p->config_storage[0]->ssl_ca_crl_file);
+ if (0 != i) buffer_copy_buffer(s->ssl_ca_dn_file, p->config_storage[0]->ssl_ca_dn_file);
+ s->ssl_conf_cmd = (0 == i)
+ ? array_init()
+ : array_init_array(p->config_storage[0]->ssl_conf_cmd);
+ s->ssl_acme_tls_1 = buffer_init();
+
+ cv[0].destination = &(s->ssl_log_noise);
+ cv[1].destination = &(s->ssl_enabled);
+ cv[2].destination = s->ssl_pemfile;
+ cv[3].destination = s->ssl_ca_file;
+ cv[4].destination = s->ssl_dh_file;
+ cv[5].destination = s->ssl_ec_curve;
+ cv[6].destination = s->ssl_cipher_list;
+ cv[7].destination = &(s->ssl_honor_cipher_order);
+ cv[8].destination = &(s->ssl_empty_fragments);
+ cv[9].destination = &(s->ssl_disable_client_renegotiation);
+ cv[10].destination = &(s->ssl_read_ahead);
+ cv[11].destination = &(s->ssl_verifyclient);
+ cv[12].destination = &(s->ssl_verifyclient_enforce);
+ cv[13].destination = &(s->ssl_verifyclient_depth);
+ cv[14].destination = s->ssl_verifyclient_username;
+ cv[15].destination = &(s->ssl_verifyclient_export_cert);
+ cv[16].destination = &(s->ssl_use_sslv2);
+ cv[17].destination = &(s->ssl_use_sslv3);
+ cv[18].destination = s->ssl_ca_crl_file;
+ cv[19].destination = s->ssl_ca_dn_file;
+ cv[20].destination = s->ssl_conf_cmd;
+ cv[21].destination = s->ssl_acme_tls_1;
+ cv[22].destination = s->ssl_privkey;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (0 != i && s->ssl_enabled && buffer_string_is_empty(s->ssl_pemfile)){
+ /* inherit ssl settings from global scope (in network_init_ssl())
+ * (if only ssl.engine = "enable" and no other ssl.* settings)*/
+ for (size_t j = 0; j < config->value->used; ++j) {
+ buffer *k = config->value->data[j]->key;
+ if (0 == strncmp(k->ptr, "ssl.", sizeof("ssl.")-1)
+ && !buffer_is_equal_string(k, CONST_STR_LEN("ssl.engine"))){
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "ssl.pemfile has to be set in same scope "
+ "as other ssl.* directives, unless only "
+ "ssl.engine is set, inheriting ssl.* from "
+ "global scope", k);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ if (0 != i && s->ssl_enabled && config->comp != COMP_SERVER_SOCKET) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ssl.engine is valid only in global scope "
+ "or $SERVER[\"socket\"] condition");
+ }
+
+ if (!array_is_kvstring(s->ssl_conf_cmd)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ssl.openssl.ssl-conf-cmd must be array "
+ "of \"key\" => \"value\" strings");
+ }
+ }
+
+ if (0 != network_init_ssl(srv, p)) return HANDLER_ERROR;
+
+ return HANDLER_GO_ON;
+}
+
+
+#define PATCH(x) \
+ hctx->conf.x = s->x;
+static int
+mod_openssl_patch_connection (server *srv, connection *con, handler_ctx *hctx)
+{
+ plugin_config *s = plugin_data_singleton->config_storage[0];
+
+ /*PATCH(ssl_enabled);*//*(not patched)*/
+ /*PATCH(ssl_pemfile);*//*(not patched)*/
+ /*PATCH(ssl_privkey);*//*(not patched)*/
+ PATCH(ssl_pemfile_x509);
+ PATCH(ssl_pemfile_pkey);
+ PATCH(ssl_ca_file);
+ /*PATCH(ssl_ca_crl_file);*//*(not patched)*/
+ PATCH(ssl_ca_dn_file);
+ PATCH(ssl_ca_file_cert_names);
+ /*PATCH(ssl_cipher_list);*//*(not patched)*/
+ /*PATCH(ssl_dh_file);*//*(not patched)*/
+ /*PATCH(ssl_ec_curve);*//*(not patched)*/
+ /*PATCH(ssl_honor_cipher_order);*//*(not patched)*/
+ /*PATCH(ssl_empty_fragments);*//*(not patched)*/
+ /*PATCH(ssl_use_sslv2);*//*(not patched)*/
+ /*PATCH(ssl_use_sslv3);*//*(not patched)*/
+ /*PATCH(ssl_conf_cmd);*//*(not patched)*/
+
+ PATCH(ssl_verifyclient);
+ PATCH(ssl_verifyclient_enforce);
+ PATCH(ssl_verifyclient_depth);
+ PATCH(ssl_verifyclient_username);
+ PATCH(ssl_verifyclient_export_cert);
+ PATCH(ssl_disable_client_renegotiation);
+ PATCH(ssl_read_ahead);
+ PATCH(ssl_acme_tls_1);
+
+ PATCH(ssl_log_noise);
+
+ /* skip the first, the global context */
+ for (size_t i = 1; i < srv->config_context->used; ++i) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = plugin_data_singleton->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
+ /*PATCH(ssl_pemfile);*//*(not patched)*/
+ /*PATCH(ssl_privkey);*//*(not patched)*/
+ PATCH(ssl_pemfile_x509);
+ PATCH(ssl_pemfile_pkey);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
+ PATCH(ssl_ca_file);
+ PATCH(ssl_ca_file_cert_names);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-dn-file"))) {
+ PATCH(ssl_ca_dn_file);
+ PATCH(ssl_ca_file_cert_names);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.activate"))) {
+ PATCH(ssl_verifyclient);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.enforce"))) {
+ PATCH(ssl_verifyclient_enforce);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.depth"))) {
+ PATCH(ssl_verifyclient_depth);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
+ PATCH(ssl_verifyclient_username);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
+ PATCH(ssl_verifyclient_export_cert);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.disable-client-renegotiation"))) {
+ PATCH(ssl_disable_client_renegotiation);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.read-ahead"))) {
+ PATCH(ssl_read_ahead);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.acme-tls-1"))) {
+ PATCH(ssl_acme_tls_1);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-ssl-noise"))) {
+ PATCH(ssl_log_noise);
+ #if 0 /*(not patched)*/
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-crl-file"))) {
+ PATCH(ssl_ca_crl_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.honor-cipher-order"))) {
+ PATCH(ssl_honor_cipher_order);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.empty-fragments"))) {
+ PATCH(ssl_empty_fragments);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv2"))) {
+ PATCH(ssl_use_sslv2);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv3"))) {
+ PATCH(ssl_use_sslv3);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) {
+ PATCH(ssl_cipher_list);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.dh-file"))) {
+ PATCH(ssl_dh_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ec-curve"))) {
+ PATCH(ssl_ec_curve);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
+ PATCH(ssl_enabled);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.openssl.ssl-conf-cmd"))) {
+ PATCH(ssl_conf_cmd);
+ #endif
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static int
+load_next_chunk (server *srv, chunkqueue *cq, off_t max_bytes,
+ const char **data, size_t *data_len)
+{
+ chunk *c = cq->first;
+
+ /* local_send_buffer is a 64k sendbuffer (LOCAL_SEND_BUFSIZE)
+ *
+ * it has to stay at the same location all the time to satisfy the needs
+ * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
+ *
+ * buffer is allocated once, is NOT realloced (note: not thread-safe)
+ *
+ * (Note: above restriction no longer true since SSL_CTX_set_mode() is
+ * called with SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
+ * */
+
+ force_assert(NULL != c);
+
+ switch (c->type) {
+ case MEM_CHUNK:
+ *data = NULL;
+ *data_len = 0;
+ do {
+ size_t have;
+
+ force_assert(c->offset >= 0
+ && c->offset <= (off_t)buffer_string_length(c->mem));
+
+ have = buffer_string_length(c->mem) - c->offset;
+
+ /* copy small mem chunks into single large buffer before SSL_write()
+ * to reduce number times write() called underneath SSL_write() and
+ * potentially reduce number of packets generated if TCP_NODELAY */
+ if (*data_len) {
+ size_t space = LOCAL_SEND_BUFSIZE - *data_len;
+ if (have > space)
+ have = space;
+ if (have > (size_t)max_bytes - *data_len)
+ have = (size_t)max_bytes - *data_len;
+ if (*data != local_send_buffer) {
+ memcpy(local_send_buffer, *data, *data_len);
+ *data = local_send_buffer;
+ }
+ memcpy(local_send_buffer+*data_len,c->mem->ptr+c->offset,have);
+ *data_len += have;
+ continue;
+ }
+
+ if ((off_t) have > max_bytes) have = max_bytes;
+
+ *data = c->mem->ptr + c->offset;
+ *data_len = have;
+ } while ((c = c->next) && c->type == MEM_CHUNK
+ && *data_len < LOCAL_SEND_BUFSIZE
+ && (off_t) *data_len < max_bytes);
+ return 0;
+
+ case FILE_CHUNK:
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ {
+ off_t offset, toSend;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+
+ if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
+ if (toSend > max_bytes) toSend = max_bytes;
+
+ if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "lseek: ", strerror(errno));
+ return -1;
+ }
+ if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "read: ", strerror(errno));
+ return -1;
+ }
+
+ *data = local_send_buffer;
+ *data_len = toSend;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+connection_write_cq_ssl (server *srv, connection *con,
+ chunkqueue *cq, off_t max_bytes)
+{
+ handler_ctx *hctx = con->plugin_ctx[plugin_data_singleton->id];
+ SSL *ssl = hctx->ssl;
+
+ chunkqueue_remove_finished_chunks(cq);
+
+ while (max_bytes > 0 && NULL != cq->first) {
+ const char *data;
+ size_t data_len;
+ int r;
+
+ if (0 != load_next_chunk(srv,cq,max_bytes,&data,&data_len)) return -1;
+
+ /**
+ * SSL_write man-page
+ *
+ * WARNING
+ * When an SSL_write() operation has to be repeated because of
+ * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
+ * repeated with the same arguments.
+ */
+
+ ERR_clear_error();
+ r = SSL_write(ssl, data, data_len);
+
+ if (hctx->renegotiations > 1
+ && hctx->conf.ssl_disable_client_renegotiation) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: renegotiation initiated by client, killing connection");
+ return -1;
+ }
+
+ if (r <= 0) {
+ int ssl_r;
+ unsigned long err;
+
+ switch ((ssl_r = SSL_get_error(ssl, r))) {
+ case SSL_ERROR_WANT_READ:
+ con->is_readable = -1;
+ return 0; /* try again later */
+ case SSL_ERROR_WANT_WRITE:
+ con->is_writable = -1;
+ return 0; /* try again later */
+ case SSL_ERROR_SYSCALL:
+ /* perhaps we have error waiting in our error-queue */
+ if (0 != (err = ERR_get_error())) {
+ do {
+ log_error_write(srv, __FILE__, __LINE__, "sdds",
+ "SSL:", ssl_r, r,
+ ERR_error_string(err, NULL));
+ } while((err = ERR_get_error()));
+ } else if (r == -1) {
+ /* no, but we have errno */
+ switch(errno) {
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sddds",
+ "SSL:", ssl_r, r, errno,
+ strerror(errno));
+ break;
+ }
+ } else {
+ /* neither error-queue nor errno ? */
+ log_error_write(srv, __FILE__, __LINE__, "sddds",
+ "SSL (error):", ssl_r, r, errno,
+ strerror(errno));
+ }
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ /* clean shutdown on the remote side */
+
+ if (r == 0) return -2;
+
+ /* fall through */
+ default:
+ while((err = ERR_get_error())) {
+ log_error_write(srv, __FILE__, __LINE__, "sdds",
+ "SSL:", ssl_r, r,
+ ERR_error_string(err, NULL));
+ }
+ break;
+ }
+ return -1;
+ }
+
+ chunkqueue_mark_written(cq, r);
+ max_bytes -= r;
+
+ if ((size_t) r < data_len) break; /* try again later */
+ }
+
+ return 0;
+}
+
+
+static int
+connection_read_cq_ssl (server *srv, connection *con,
+ chunkqueue *cq, off_t max_bytes)
+{
+ handler_ctx *hctx = con->plugin_ctx[plugin_data_singleton->id];
+ int r, ssl_err, len;
+ char *mem = NULL;
+ size_t mem_len = 0;
+
+ /*(code transform assumption; minimize diff)*/
+ force_assert(cq == con->read_queue);
+ UNUSED(max_bytes);
+
+ ERR_clear_error();
+ do {
+ len = SSL_pending(hctx->ssl);
+ mem_len = len < 2048 ? 2048 : (size_t)len;
+ mem = chunkqueue_get_memory(con->read_queue, &mem_len);
+#if 0
+ /* overwrite everything with 0 */
+ memset(mem, 0, mem_len);
+#endif
+
+ len = SSL_read(hctx->ssl, mem, mem_len);
+ if (len > 0) {
+ chunkqueue_use_memory(con->read_queue, len);
+ con->bytes_read += len;
+ } else {
+ chunkqueue_use_memory(con->read_queue, 0);
+ }
+
+ if (hctx->renegotiations > 1
+ && hctx->conf.ssl_disable_client_renegotiation) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "SSL: renegotiation initiated by client, killing connection");
+ return -1;
+ }
+
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000
+ if (hctx->alpn) {
+ if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1) {
+ chunkqueue_reset(con->read_queue);
+ /* initiate handshake in order to send ServerHello.
+ * Once TLS handshake is complete, return -1 to result in
+ * CON_STATE_ERROR so that socket connection is quickly closed*/
+ if (1 == SSL_do_handshake(hctx->ssl)) return -1;
+ len = -1;
+ break;
+ }
+ hctx->alpn = 0;
+ }
+ #endif
+ } while (len > 0
+ && (hctx->conf.ssl_read_ahead || SSL_pending(hctx->ssl) > 0));
+
+ if (len < 0) {
+ int oerrno = errno;
+ switch ((r = SSL_get_error(hctx->ssl, len))) {
+ case SSL_ERROR_WANT_WRITE:
+ con->is_writable = -1;
+ /* fall through */
+ case SSL_ERROR_WANT_READ:
+ con->is_readable = 0;
+
+ /* the manual says we have to call SSL_read with the same arguments
+ * next time. we ignore this restriction; no one has complained
+ * about it in 1.5 yet, so it probably works anyway.
+ */
+
+ return 0;
+ case SSL_ERROR_SYSCALL:
+ /**
+ * man SSL_get_error()
+ *
+ * SSL_ERROR_SYSCALL
+ * Some I/O error occurred. The OpenSSL error queue may contain
+ * more information on the error. If the error queue is empty
+ * (i.e. ERR_get_error() returns 0), ret can be used to find out
+ * more about the error: If ret == 0, an EOF was observed that
+ * violates the protocol. If ret == -1, the underlying BIO
+ * reported an I/O error (for socket I/O on Unix systems, consult
+ * errno for details).
+ *
+ */
+ while((ssl_err = ERR_get_error())) {
+ /* get all errors from the error-queue */
+ log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
+ r, ERR_error_string(ssl_err, NULL));
+ }
+
+ switch(oerrno) {
+ default:
+ /* (oerrno should be something like ECONNABORTED not 0
+ * if client disconnected before anything was sent
+ * (e.g. TCP connection probe), but it does not appear
+ * that openssl provides such notification, not even
+ * something like SSL_R_SSL_HANDSHAKE_FAILURE) */
+ if (0==oerrno && 0==cq->bytes_in && !hctx->conf.ssl_log_noise)
+ break;
+
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
+ len, r, oerrno,
+ strerror(oerrno));
+ break;
+ }
+
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ /* clean shutdown on the remote side */
+
+ if (r == 0) {
+ /* FIXME: later */
+ }
+
+ /* fall through */
+ default:
+ while((ssl_err = ERR_get_error())) {
+ switch (ERR_GET_REASON(ssl_err)) {
+ case SSL_R_SSL_HANDSHAKE_FAILURE:
+ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA
+ case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+ #endif
+ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+ #endif
+ #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
+ case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+ #endif
+ if (!hctx->conf.ssl_log_noise) continue;
+ break;
+ default:
+ break;
+ }
+ /* get all errors from the error-queue */
+ log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
+ r, ERR_error_string(ssl_err, NULL));
+ }
+ break;
+ }
+ return -1;
+ } else if (len == 0) {
+ con->is_readable = 0;
+ /* the other end close the connection -> KEEP-ALIVE */
+
+ return -2;
+ } else {
+ return 0;
+ }
+}
+
+
+CONNECTION_FUNC(mod_openssl_handle_con_accept)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx;
+ server_socket *srv_sock = con->srv_socket;
+ if (!srv_sock->is_ssl) return HANDLER_GO_ON;
+
+ hctx = handler_ctx_init();
+ hctx->con = con;
+ hctx->srv = srv;
+ con->plugin_ctx[p->id] = hctx;
+ mod_openssl_patch_connection(srv, con, hctx);
+
+ /* connect fd to SSL */
+ hctx->ssl = SSL_new(p->config_storage[srv_sock->sidx]->ssl_ctx);
+ if (NULL == hctx->ssl) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return HANDLER_ERROR;
+ }
+
+ buffer_copy_string_len(con->proto, CONST_STR_LEN("https"));
+ con->network_read = connection_read_cq_ssl;
+ con->network_write = connection_write_cq_ssl;
+ SSL_set_app_data(hctx->ssl, hctx);
+ SSL_set_accept_state(hctx->ssl);
+
+ if (1 != (SSL_set_fd(hctx->ssl, con->fd))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return HANDLER_ERROR;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static void
+mod_openssl_close_notify(server *srv, handler_ctx *hctx);
+
+
+CONNECTION_FUNC(mod_openssl_handle_con_shut_wr)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ if (SSL_is_init_finished(hctx->ssl)) {
+ mod_openssl_close_notify(srv, hctx);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static void
+mod_openssl_close_notify(server *srv, handler_ctx *hctx)
+{
+ int ret, ssl_r;
+ unsigned long err;
+ ERR_clear_error();
+ switch ((ret = SSL_shutdown(hctx->ssl))) {
+ case 1:
+ /* ok */
+ break;
+ case 0:
+ /* wait for fd-event
+ *
+ * FIXME: wait for fdevent and call SSL_shutdown again
+ *
+ */
+
+ /* Drain SSL read buffers in case pending records need processing.
+ * Limit to reading 16k to avoid denial of service when the CPU
+ * processing TLS is slower than arrival speed of TLS data packets.
+ *
+ * references:
+ *
+ * "New session ticket breaks bidirectional shutdown of TLS 1.3 connection"
+ * https://github.com/openssl/openssl/issues/6262
+ *
+ * The peer is still allowed to send data after receiving the
+ * "close notify" event. If the peer did send data it need to be
+ * processed by calling SSL_read() before calling SSL_shutdown() a
+ * second time. SSL_read() will indicate the end of the peer data by
+ * returning <= 0 and SSL_get_error() returning
+ * SSL_ERROR_ZERO_RETURN. It is recommended to call SSL_read()
+ * between SSL_shutdown() calls.
+ *
+ * Additional discussion in "Auto retry in shutdown"
+ * https://github.com/openssl/openssl/pull/6340
+ */
+ err = 0;
+ do {
+ char buf[4096];
+ ret = SSL_read(hctx->ssl, buf, (int)sizeof(buf));
+ } while (ret > 0 && (err += (unsigned long)ret) < 16384);
+
+ ERR_clear_error();
+ if (-1 != (ret = SSL_shutdown(hctx->ssl))) break;
+
+ /* fall through */
+ default:
+
+ switch ((ssl_r = SSL_get_error(hctx->ssl, ret))) {
+ case SSL_ERROR_ZERO_RETURN:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ /*con->is_writable=-1;*//*(no effect; shutdown() called below)*/
+ case SSL_ERROR_WANT_READ:
+ break;
+ case SSL_ERROR_SYSCALL:
+ /* perhaps we have error waiting in our error-queue */
+ if (0 != (err = ERR_get_error())) {
+ do {
+ log_error_write(srv, __FILE__, __LINE__, "sdds",
+ "SSL:", ssl_r, ret,
+ ERR_error_string(err, NULL));
+ } while((err = ERR_get_error()));
+ } else if (errno != 0) {
+ /*ssl bug (see lighttpd ticket #2213): sometimes errno==0*/
+ switch(errno) {
+ case EPIPE:
+ case ECONNRESET:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sddds",
+ "SSL (error):", ssl_r, ret, errno,
+ strerror(errno));
+ break;
+ }
+ }
+
+ break;
+ default:
+ while((err = ERR_get_error())) {
+ log_error_write(srv, __FILE__, __LINE__, "sdds",
+ "SSL:", ssl_r, ret,
+ ERR_error_string(err, NULL));
+ }
+
+ break;
+ }
+ }
+ ERR_clear_error();
+}
+
+
+CONNECTION_FUNC(mod_openssl_handle_con_close)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL != hctx) {
+ handler_ctx_free(hctx);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+
+static void
+https_add_ssl_client_entries (server *srv, connection *con, handler_ctx *hctx)
+{
+ X509 *xs;
+ X509_NAME *xn;
+ int i, nentries;
+
+ long vr = SSL_get_verify_result(hctx->ssl);
+ if (vr != X509_V_OK) {
+ char errstr[256];
+ ERR_error_string_n(vr, errstr, sizeof(errstr));
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("FAILED:"));
+ buffer_append_string(srv->tmp_buf, errstr);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_BUF_LEN(srv->tmp_buf));
+ return;
+ } else if (!(xs = SSL_get_peer_certificate(hctx->ssl))) {
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_STR_LEN("NONE"));
+ return;
+ } else {
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_STR_LEN("SUCCESS"));
+ }
+
+ xn = X509_get_subject_name(xs);
+ {
+ char buf[256];
+ int len = safer_X509_NAME_oneline(xn, buf, sizeof(buf));
+ if (len > 0) {
+ if (len >= (int)sizeof(buf)) len = (int)sizeof(buf)-1;
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_S_DN"),
+ buf, (size_t)len);
+ }
+ }
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
+ for (i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
+ int xobjnid;
+ const char * xobjsn;
+ X509_NAME_ENTRY *xe;
+
+ if (!(xe = X509_NAME_get_entry(xn, i))) {
+ continue;
+ }
+ xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
+ xobjsn = OBJ_nid2sn(xobjnid);
+ if (xobjsn) {
+ buffer_string_set_length(srv->tmp_buf,sizeof("SSL_CLIENT_S_DN_")-1);
+ buffer_append_string(srv->tmp_buf, xobjsn);
+ http_header_env_set(con,
+ CONST_BUF_LEN(srv->tmp_buf),
+ (const char*)X509_NAME_ENTRY_get_data(xe)->data,
+ X509_NAME_ENTRY_get_data(xe)->length);
+ }
+ }
+
+ {
+ ASN1_INTEGER *xsn = X509_get_serialNumber(xs);
+ BIGNUM *serialBN = ASN1_INTEGER_to_BN(xsn, NULL);
+ char *serialHex = BN_bn2hex(serialBN);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_M_SERIAL"),
+ serialHex, strlen(serialHex));
+ OPENSSL_free(serialHex);
+ BN_free(serialBN);
+ }
+
+ if (!buffer_string_is_empty(hctx->conf.ssl_verifyclient_username)) {
+ /* pick one of the exported values as "REMOTE_USER", for example
+ * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID"
+ * or
+ * ssl.verifyclient.username = "SSL_CLIENT_S_DN_emailAddress"
+ */
+ buffer *varname = hctx->conf.ssl_verifyclient_username;
+ buffer *vb = http_header_env_get(con, CONST_BUF_LEN(varname));
+ if (vb) { /* same as http_auth.c:http_auth_setenv() */
+ http_header_env_set(con,
+ CONST_STR_LEN("REMOTE_USER"),
+ CONST_BUF_LEN(vb));
+ http_header_env_set(con,
+ CONST_STR_LEN("AUTH_TYPE"),
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"));
+ }
+ }
+
+ if (hctx->conf.ssl_verifyclient_export_cert) {
+ BIO *bio;
+ if (NULL != (bio = BIO_new(BIO_s_mem()))) {
+ buffer *cert = srv->tmp_buf;
+ int n;
+
+ PEM_write_bio_X509(bio, xs);
+ n = BIO_pending(bio);
+
+ buffer_string_prepare_copy(cert, n);
+ BIO_read(bio, cert->ptr, n);
+ BIO_free(bio);
+ buffer_commit(cert, n);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CLIENT_CERT"),
+ CONST_BUF_LEN(cert));
+ }
+ }
+ X509_free(xs);
+}
+
+
+static void
+http_cgi_ssl_env (server *srv, connection *con, handler_ctx *hctx)
+{
+ const char *s;
+ const SSL_CIPHER *cipher;
+ UNUSED(srv);
+
+ s = SSL_get_version(hctx->ssl);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_PROTOCOL"),
+ s, strlen(s));
+
+ if ((cipher = SSL_get_current_cipher(hctx->ssl))) {
+ int usekeysize, algkeysize;
+ char buf[LI_ITOSTRING_LENGTH];
+ s = SSL_CIPHER_get_name(cipher);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CIPHER"),
+ s, strlen(s));
+ usekeysize = SSL_CIPHER_get_bits(cipher, &algkeysize);
+ li_itostrn(buf, sizeof(buf), usekeysize);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CIPHER_USEKEYSIZE"),
+ buf, strlen(buf));
+ li_itostrn(buf, sizeof(buf), algkeysize);
+ http_header_env_set(con,
+ CONST_STR_LEN("SSL_CIPHER_ALGKEYSIZE"),
+ buf, strlen(buf));
+ }
+}
+
+
+CONNECTION_FUNC(mod_openssl_handle_request_env)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (hctx->request_env_patched) return HANDLER_GO_ON;
+ hctx->request_env_patched = 1;
+
+ http_cgi_ssl_env(srv, con, hctx);
+ if (hctx->conf.ssl_verifyclient) {
+ https_add_ssl_client_entries(srv, con, hctx);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+CONNECTION_FUNC(mod_openssl_handle_uri_raw)
+{
+ /* mod_openssl must be loaded prior to mod_auth
+ * if mod_openssl is configured to set REMOTE_USER based on client cert */
+ /* mod_openssl must be loaded after mod_extforward
+ * if mod_openssl config is based on lighttpd.conf remote IP conditional
+ * using remote IP address set by mod_extforward, *unless* PROXY protocol
+ * is enabled with extforward.hap-PROXY = "enable", in which case the
+ * reverse is true: mod_extforward must be loaded after mod_openssl */
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ mod_openssl_patch_connection(srv, con, hctx);
+ if (hctx->conf.ssl_verifyclient) {
+ mod_openssl_handle_request_env(srv, con, p);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+CONNECTION_FUNC(mod_openssl_handle_request_reset)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ hctx->request_env_patched = 0;
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+
+int mod_openssl_plugin_init (plugin *p);
+int mod_openssl_plugin_init (plugin *p)
+{
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("openssl");
+ p->init = mod_openssl_init;
+ p->cleanup = mod_openssl_free;
+ p->priv_defaults= mod_openssl_set_defaults;
+
+ p->handle_connection_accept = mod_openssl_handle_con_accept;
+ p->handle_connection_shut_wr = mod_openssl_handle_con_shut_wr;
+ p->handle_connection_close = mod_openssl_handle_con_close;
+ p->handle_uri_raw = mod_openssl_handle_uri_raw;
+ p->handle_request_env = mod_openssl_handle_request_env;
+ p->connection_reset = mod_openssl_handle_request_reset;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_proxy.c b/data/lighttpd/lighttpd-1.4.53/src/mod_proxy.c
new file mode 100644
index 000000000..91f9c2f3c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_proxy.c
@@ -0,0 +1,1038 @@
+#include "first.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gw_backend.h"
+#include "base.h"
+#include "array.h"
+#include "buffer.h"
+#include "http_kv.h"
+#include "http_header.h"
+#include "log.h"
+#include "sock_addr.h"
+#include "status_counter.h"
+
+/**
+ *
+ * HTTP reverse proxy
+ *
+ * TODO: - HTTP/1.1
+ * - HTTP/1.1 persistent connection with upstream servers
+ */
+
+/* (future: might split struct and move part to http-header-glue.c) */
+typedef struct http_header_remap_opts {
+ const array *urlpaths;
+ const array *hosts_request;
+ const array *hosts_response;
+ int https_remap;
+ int upgrade;
+ int connect_method;
+ /*(not used in plugin_config, but used in handler_ctx)*/
+ const buffer *http_host;
+ const buffer *forwarded_host;
+ const data_string *forwarded_urlpath;
+} http_header_remap_opts;
+
+typedef enum {
+ PROXY_FORWARDED_NONE = 0x00,
+ PROXY_FORWARDED_FOR = 0x01,
+ PROXY_FORWARDED_PROTO = 0x02,
+ PROXY_FORWARDED_HOST = 0x04,
+ PROXY_FORWARDED_BY = 0x08,
+ PROXY_FORWARDED_REMOTE_USER = 0x10
+} proxy_forwarded_t;
+
+typedef struct {
+ gw_plugin_config gw;
+ array *forwarded_params;
+ array *header_params;
+ unsigned short replace_http_host;
+ unsigned int forwarded;
+
+ http_header_remap_opts header;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+static int proxy_check_extforward;
+
+typedef struct {
+ gw_handler_ctx gw;
+ http_response_opts opts;
+ plugin_config conf;
+} handler_ctx;
+
+
+INIT_FUNC(mod_proxy_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+
+FREE_FUNC(mod_proxy_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->forwarded_params);
+ array_free(s->header_params);
+
+ /*assert(0 == offsetof(s->gw));*/
+ gw_plugin_config_free(&s->gw);
+ /*free(s);*//*free'd by gw_plugin_config_free()*/
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
+ plugin_data *p = p_d;
+ data_unset *du;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "proxy.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "proxy.replace-http-host", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "proxy.forwarded", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "proxy.header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "proxy.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->gw.debug = 0;
+ s->replace_http_host = 0;
+ s->forwarded_params = array_init();
+ s->forwarded = PROXY_FORWARDED_NONE;
+ s->header_params = array_init();
+ s->gw.ext_mapping = array_init();
+
+ cv[0].destination = NULL; /* T_CONFIG_LOCAL */
+ cv[1].destination = &(s->gw.debug);
+ cv[2].destination = NULL; /* T_CONFIG_LOCAL */
+ cv[3].destination = &(s->replace_http_host);
+ cv[4].destination = s->forwarded_params;
+ cv[5].destination = s->header_params;
+ cv[6].destination = s->gw.ext_mapping;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "proxy.server");
+ if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, du, i, 0)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "proxy.balance");
+ if (!gw_set_defaults_balance(srv, &s->gw, du)) {
+ return HANDLER_ERROR;
+ }
+
+ /* disable check-local for all exts (default enabled) */
+ if (s->gw.exts) { /*(check after gw_set_defaults_backend())*/
+ for (size_t j = 0; j < s->gw.exts->used; ++j) {
+ gw_extension *ex = s->gw.exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ ex->hosts[n]->check_local = 0;
+ }
+ }
+ }
+
+ if (!array_is_kvany(s->forwarded_params)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for proxy.forwarded; expected ( \"param\" => \"value\" )");
+ return HANDLER_ERROR;
+ }
+ for (size_t j = 0, used = s->forwarded_params->used; j < used; ++j) {
+ proxy_forwarded_t param;
+ du = s->forwarded_params->data[j];
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("by"))) {
+ param = PROXY_FORWARDED_BY;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("for"))) {
+ param = PROXY_FORWARDED_FOR;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("host"))) {
+ param = PROXY_FORWARDED_HOST;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proto"))) {
+ param = PROXY_FORWARDED_PROTO;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("remote_user"))) {
+ param = PROXY_FORWARDED_REMOTE_USER;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "proxy.forwarded keys must be one of: by, for, host, proto, remote_user, but not:", du->key);
+ return HANDLER_ERROR;
+ }
+ if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
+ s->forwarded |= param;
+ } else if (!buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "proxy.forwarded values must be one of: 0, 1, enable, disable; error for key:", du->key);
+ return HANDLER_ERROR;
+ }
+ } else if (du->type == TYPE_INTEGER) {
+ data_integer *di = (data_integer *)du;
+ if (di->value) s->forwarded |= param;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "proxy.forwarded values must be one of: 0, 1, enable, disable; error for key:", du->key);
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (!array_is_kvany(s->header_params)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) )");
+ return HANDLER_ERROR;
+ }
+ for (size_t j = 0, used = s->header_params->used; j < used; ++j) {
+ data_array *da = (data_array *)s->header_params->data[j];
+ if (buffer_is_equal_string(da->key, CONST_STR_LEN("https-remap"))) {
+ data_string *ds = (data_string *)da;
+ if (ds->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for proxy.header; expected \"enable\" or \"disable\" for https-remap");
+ return HANDLER_ERROR;
+ }
+ s->header.https_remap = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
+ continue;
+ }
+ else if (buffer_is_equal_string(da->key, CONST_STR_LEN("upgrade"))) {
+ data_string *ds = (data_string *)da;
+ if (ds->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for proxy.header; expected \"upgrade\" => \"enable\" or \"disable\"");
+ return HANDLER_ERROR;
+ }
+ s->header.upgrade = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
+ continue;
+ }
+ else if (buffer_is_equal_string(da->key, CONST_STR_LEN("connect"))) {
+ data_string *ds = (data_string *)da;
+ if (ds->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for proxy.header; expected \"connect\" => \"enable\" or \"disable\"");
+ return HANDLER_ERROR;
+ }
+ s->header.connect_method = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
+ continue;
+ }
+ if (da->type != TYPE_ARRAY || !array_is_kvstring(da->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key);
+ return HANDLER_ERROR;
+ }
+ if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-urlpath"))) {
+ s->header.urlpaths = da->value;
+ }
+ else if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-host-request"))) {
+ s->header.hosts_request = da->value;
+ }
+ else if (buffer_is_equal_string(da->key, CONST_STR_LEN("map-host-response"))) {
+ s->header.hosts_response = da->value;
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "unexpected key for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[i];
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_extforward"))) {
+ proxy_check_extforward = 1;
+ break;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+/* (future: might move to http-header-glue.c) */
+static const buffer * http_header_remap_host_match (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req, size_t alen)
+{
+ const array *hosts = is_req
+ ? remap_hdrs->hosts_request
+ : remap_hdrs->hosts_response;
+ if (hosts) {
+ const char * const s = b->ptr+off;
+ for (size_t i = 0, used = hosts->used; i < used; ++i) {
+ const data_string * const ds = (data_string *)hosts->data[i];
+ const buffer *k = ds->key;
+ size_t mlen = buffer_string_length(k);
+ if (1 == mlen && k->ptr[0] == '-') {
+ /* match with authority provided in Host (if is_req)
+ * (If no Host in client request, then matching against empty
+ * string will probably not match, and no remap will be
+ * performed) */
+ k = is_req
+ ? remap_hdrs->http_host
+ : remap_hdrs->forwarded_host;
+ if (NULL == k) continue;
+ mlen = buffer_string_length(k);
+ }
+ if (mlen == alen && 0 == strncasecmp(s, k->ptr, alen)) {
+ if (buffer_is_equal_string(ds->value, CONST_STR_LEN("-"))) {
+ return remap_hdrs->http_host;
+ }
+ else if (!buffer_string_is_empty(ds->value)) {
+ /*(save first matched request host for response match)*/
+ if (is_req && NULL == remap_hdrs->forwarded_host)
+ remap_hdrs->forwarded_host = ds->value;
+ return ds->value;
+ } /*(else leave authority as-is and stop matching)*/
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/* (future: might move to http-header-glue.c) */
+static size_t http_header_remap_host (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req, size_t alen)
+{
+ const buffer * const m =
+ http_header_remap_host_match(b, off, remap_hdrs, is_req, alen);
+ if (NULL == m) return alen; /*(no match; return original authority length)*/
+
+ buffer_substr_replace(b, off, alen, m);
+ return buffer_string_length(m); /*(length of replacement authority)*/
+}
+
+
+/* (future: might move to http-header-glue.c) */
+static size_t http_header_remap_urlpath (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req)
+{
+ const array *urlpaths = remap_hdrs->urlpaths;
+ if (urlpaths) {
+ const char * const s = b->ptr+off;
+ const size_t plen = buffer_string_length(b) - off; /*(urlpath len)*/
+ if (is_req) { /* request */
+ for (size_t i = 0, used = urlpaths->used; i < used; ++i) {
+ const data_string * const ds = (data_string *)urlpaths->data[i];
+ const size_t mlen = buffer_string_length(ds->key);
+ if (mlen <= plen && 0 == memcmp(s, ds->key->ptr, mlen)) {
+ if (NULL == remap_hdrs->forwarded_urlpath)
+ remap_hdrs->forwarded_urlpath = ds;
+ buffer_substr_replace(b, off, mlen, ds->value);
+ return buffer_string_length(ds->value);/*(replacement len)*/
+ }
+ }
+ }
+ else { /* response; perform reverse map */
+ if (NULL != remap_hdrs->forwarded_urlpath) {
+ const data_string * const ds = remap_hdrs->forwarded_urlpath;
+ const size_t mlen = buffer_string_length(ds->value);
+ if (mlen <= plen && 0 == memcmp(s, ds->value->ptr, mlen)) {
+ buffer_substr_replace(b, off, mlen, ds->key);
+ return buffer_string_length(ds->key); /*(replacement len)*/
+ }
+ }
+ for (size_t i = 0, used = urlpaths->used; i < used; ++i) {
+ const data_string * const ds = (data_string *)urlpaths->data[i];
+ const size_t mlen = buffer_string_length(ds->value);
+ if (mlen <= plen && 0 == memcmp(s, ds->value->ptr, mlen)) {
+ buffer_substr_replace(b, off, mlen, ds->key);
+ return buffer_string_length(ds->key); /*(replacement len)*/
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* (future: might move to http-header-glue.c) */
+static void http_header_remap_uri (buffer *b, size_t off, http_header_remap_opts *remap_hdrs, int is_req)
+{
+ /* find beginning of URL-path (might be preceded by scheme://authority
+ * (caller should make sure any leading whitespace is prior to offset) */
+ if (b->ptr[off] != '/') {
+ char *s = b->ptr+off;
+ size_t alen; /*(authority len (host len))*/
+ size_t slen; /*(scheme len)*/
+ const buffer *m;
+ /* skip over scheme and authority of URI to find beginning of URL-path
+ * (value might conceivably be relative URL-path instead of URI) */
+ if (NULL == (s = strchr(s, ':')) || s[1] != '/' || s[2] != '/') return;
+ slen = s - (b->ptr+off);
+ s += 3;
+ off = (size_t)(s - b->ptr);
+ if (NULL != (s = strchr(s, '/'))) {
+ alen = (size_t)(s - b->ptr) - off;
+ if (0 == alen) return; /*(empty authority, e.g. "http:///")*/
+ }
+ else {
+ alen = buffer_string_length(b) - off;
+ if (0 == alen) return; /*(empty authority, e.g. "http:///")*/
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+ }
+
+ /* remap authority (if configured) and set offset to url-path */
+ m = http_header_remap_host_match(b, off, remap_hdrs, is_req, alen);
+ if (NULL != m) {
+ if (remap_hdrs->https_remap
+ && (is_req ? 5==slen && 0==memcmp(b->ptr+off-slen-3,"https",5)
+ : 4==slen && 0==memcmp(b->ptr+off-slen-3,"http",4))){
+ if (is_req) {
+ memcpy(b->ptr+off-slen-3+4,"://",3); /*("https"=>"http")*/
+ --off;
+ ++alen;
+ }
+ else {/*(!is_req)*/
+ memcpy(b->ptr+off-slen-3+4,"s://",4); /*("http" =>"https")*/
+ ++off;
+ --alen;
+ }
+ }
+ buffer_substr_replace(b, off, alen, m);
+ alen = buffer_string_length(m);/*(length of replacement authority)*/
+ }
+ off += alen;
+ }
+
+ /* remap URLs (if configured) */
+ http_header_remap_urlpath(b, off, remap_hdrs, is_req);
+}
+
+
+/* (future: might move to http-header-glue.c) */
+static void http_header_remap_setcookie (buffer *b, size_t off, http_header_remap_opts *remap_hdrs)
+{
+ /* Given the special-case of Set-Cookie and the (too) loosely restricted
+ * characters allowed, for best results, the Set-Cookie value should be the
+ * entire string in b from offset to end of string. In response headers,
+ * lighttpd may concatenate multiple Set-Cookie headers into single entry
+ * in con->response.headers, separated by "\r\nSet-Cookie: " */
+ for (char *s = b->ptr+off, *e; *s; s = e) {
+ size_t len;
+ {
+ while (*s != ';' && *s != '\n' && *s != '\0') ++s;
+ if (*s == '\n') {
+ /*(include +1 for '\n', but leave ' ' for ++s below)*/
+ s += sizeof("Set-Cookie:");
+ }
+ if ('\0' == *s) return;
+ do { ++s; } while (*s == ' ' || *s == '\t');
+ if ('\0' == *s) return;
+ e = s+1;
+ if ('=' == *s) continue;
+ /*(interested only in Domain and Path attributes)*/
+ while (*e != '=' && *e != '\0') ++e;
+ if ('\0' == *e) return;
+ ++e;
+ switch ((int)(e - s - 1)) {
+ case 4:
+ if (0 == strncasecmp(s, "path", 4)) {
+ if (*e == '"') ++e;
+ if (*e != '/') continue;
+ off = (size_t)(e - b->ptr);
+ len = http_header_remap_urlpath(b, off, remap_hdrs, 0);
+ e = b->ptr+off+len; /*(b may have been reallocated)*/
+ continue;
+ }
+ break;
+ case 6:
+ if (0 == strncasecmp(s, "domain", 6)) {
+ size_t alen = 0;
+ if (*e == '"') ++e;
+ if (*e == '.') ++e;
+ if (*e == ';') continue;
+ off = (size_t)(e - b->ptr);
+ for (char c; (c = e[alen]) != ';' && c != ' ' && c != '\t'
+ && c != '\r' && c != '\0'; ++alen);
+ len = http_header_remap_host(b, off, remap_hdrs, 0, alen);
+ e = b->ptr+off+len; /*(b may have been reallocated)*/
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+static void buffer_append_string_backslash_escaped(buffer *b, const char *s, size_t len) {
+ /* (future: might move to buffer.c) */
+ size_t j = 0;
+ char *p;
+
+ buffer_string_prepare_append(b, len*2 + 4);
+ p = b->ptr + buffer_string_length(b);
+
+ for (size_t i = 0; i < len; ++i) {
+ int c = s[i];
+ if (c == '"' || c == '\\' || c == 0x7F || (c < 0x20 && c != '\t'))
+ p[j++] = '\\';
+ p[j++] = c;
+ }
+
+ buffer_commit(b, j);
+}
+
+static void proxy_set_Forwarded(connection *con, const unsigned int flags) {
+ buffer *b = NULL, *efor = NULL, *eproto = NULL, *ehost = NULL;
+ int semicolon = 0;
+
+ if (proxy_check_extforward) {
+ efor =
+ http_header_env_get(con, CONST_STR_LEN("_L_EXTFORWARD_ACTUAL_FOR"));
+ eproto =
+ http_header_env_get(con, CONST_STR_LEN("_L_EXTFORWARD_ACTUAL_PROTO"));
+ ehost =
+ http_header_env_get(con, CONST_STR_LEN("_L_EXTFORWARD_ACTUAL_HOST"));
+ }
+
+ /* note: set "Forwarded" prior to updating X-Forwarded-For (below) */
+
+ if (flags)
+ b = http_header_request_get(con, HTTP_HEADER_FORWARDED, CONST_STR_LEN("Forwarded"));
+
+ if (flags && NULL == b) {
+ buffer *xff =
+ http_header_request_get(con, HTTP_HEADER_X_FORWARDED_FOR, CONST_STR_LEN("X-Forwarded-For"));
+ http_header_request_set(con, HTTP_HEADER_FORWARDED,
+ CONST_STR_LEN("Forwarded"),
+ CONST_STR_LEN("x")); /*(must not be blank for _get below)*/
+ #ifdef __COVERITY__
+ force_assert(NULL != b); /*(not NULL because created directly above)*/
+ #endif
+ b = http_header_request_get(con, HTTP_HEADER_FORWARDED, CONST_STR_LEN("Forwarded"));
+ buffer_clear(b);
+ if (NULL != xff) {
+ /* use X-Forwarded-For contents to seed Forwarded */
+ char *s = xff->ptr;
+ size_t used = buffer_string_length(xff);
+ for (size_t i=0, j, ipv6; i < used; ++i) {
+ while (s[i] == ' ' || s[i] == '\t' || s[i] == ',') ++i;
+ if (s[i] == '\0') break;
+ j = i;
+ do {
+ ++i;
+ } while (s[i]!=' ' && s[i]!='\t' && s[i]!=',' && s[i]!='\0');
+ buffer_append_string_len(b, CONST_STR_LEN("for="));
+ /* over-simplified test expecting only IPv4 or IPv6 addresses,
+ * (not expecting :port, so treat existence of colon as IPv6,
+ * and not expecting unix paths, especially not containing ':')
+ * quote all strings, backslash-escape since IPs not validated*/
+ ipv6 = (NULL != memchr(s+j, ':', i-j)); /*(over-simplified) */
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ if (ipv6)
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ buffer_append_string_backslash_escaped(b, s+j, i-j);
+ if (ipv6)
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ buffer_append_string_len(b, CONST_STR_LEN(", "));
+ }
+ }
+ } else if (flags) { /*(NULL != b)*/
+ buffer_append_string_len(b, CONST_STR_LEN(", "));
+ }
+
+ if (flags & PROXY_FORWARDED_FOR) {
+ int family = sock_addr_get_family(&con->dst_addr);
+ buffer_append_string_len(b, CONST_STR_LEN("for="));
+ if (NULL != efor) {
+ /* over-simplified test expecting only IPv4 or IPv6 addresses,
+ * (not expecting :port, so treat existence of colon as IPv6,
+ * and not expecting unix paths, especially not containing ':')
+ * quote all strings and backslash-escape since IPs not validated
+ * (should be IP from original con->dst_addr_buf,
+ * so trustable and without :port) */
+ int ipv6 = (NULL != strchr(efor->ptr, ':'));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ if (ipv6) buffer_append_string_len(b, CONST_STR_LEN("["));
+ buffer_append_string_backslash_escaped(
+ b, CONST_BUF_LEN(efor));
+ if (ipv6) buffer_append_string_len(b, CONST_STR_LEN("]"));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ } else if (family == AF_INET) {
+ /*(Note: if :port is added, then must be quoted-string:
+ * e.g. for="...:port")*/
+ buffer_append_string_buffer(b, con->dst_addr_buf);
+ } else if (family == AF_INET6) {
+ buffer_append_string_len(b, CONST_STR_LEN("\"["));
+ buffer_append_string_buffer(b, con->dst_addr_buf);
+ buffer_append_string_len(b, CONST_STR_LEN("]\""));
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ buffer_append_string_backslash_escaped(
+ b, CONST_BUF_LEN(con->dst_addr_buf));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ }
+ semicolon = 1;
+ }
+
+ if (flags & PROXY_FORWARDED_BY) {
+ int family = sock_addr_get_family(&con->srv_socket->addr);
+ /* Note: getsockname() and inet_ntop() are expensive operations.
+ * (recommendation: do not to enable by=... unless required)
+ * future: might use con->srv_socket->srv_token if addr is not
+ * INADDR_ANY or in6addr_any, but must omit optional :port
+ * from con->srv_socket->srv_token for consistency */
+
+ if (semicolon) buffer_append_string_len(b, CONST_STR_LEN(";"));
+ buffer_append_string_len(b, CONST_STR_LEN("by="));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ #ifdef HAVE_SYS_UN_H
+ /* special-case: might need to encode unix domain socket path */
+ if (family == AF_UNIX) {
+ buffer_append_string_backslash_escaped(
+ b, CONST_BUF_LEN(con->srv_socket->srv_token));
+ }
+ else
+ #endif
+ {
+ sock_addr addr;
+ socklen_t addrlen = sizeof(addr);
+ if (0 == getsockname(con->fd,(struct sockaddr *)&addr, &addrlen)) {
+ sock_addr_stringify_append_buffer(b, &addr);
+ }
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ semicolon = 1;
+ }
+
+ if (flags & PROXY_FORWARDED_PROTO) {
+ /* expecting "http" or "https"
+ * (not checking if quoted-string and encoding needed) */
+ if (semicolon) buffer_append_string_len(b, CONST_STR_LEN(";"));
+ buffer_append_string_len(b, CONST_STR_LEN("proto="));
+ if (NULL != eproto) {
+ buffer_append_string_buffer(b, eproto);
+ } else if (con->srv_socket->is_ssl) {
+ buffer_append_string_len(b, CONST_STR_LEN("https"));
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("http"));
+ }
+ semicolon = 1;
+ }
+
+ if (flags & PROXY_FORWARDED_HOST) {
+ if (NULL != ehost) {
+ if (semicolon)
+ buffer_append_string_len(b, CONST_STR_LEN(";"));
+ buffer_append_string_len(b, CONST_STR_LEN("host=\""));
+ buffer_append_string_backslash_escaped(
+ b, CONST_BUF_LEN(ehost));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ semicolon = 1;
+ } else if (!buffer_string_is_empty(con->request.http_host)) {
+ if (semicolon)
+ buffer_append_string_len(b, CONST_STR_LEN(";"));
+ buffer_append_string_len(b, CONST_STR_LEN("host=\""));
+ buffer_append_string_backslash_escaped(
+ b, CONST_BUF_LEN(con->request.http_host));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ semicolon = 1;
+ }
+ }
+
+ if (flags & PROXY_FORWARDED_REMOTE_USER) {
+ buffer *remote_user =
+ http_header_env_get(con, CONST_STR_LEN("REMOTE_USER"));
+ if (NULL != remote_user) {
+ if (semicolon)
+ buffer_append_string_len(b, CONST_STR_LEN(";"));
+ buffer_append_string_len(b, CONST_STR_LEN("remote_user=\""));
+ buffer_append_string_backslash_escaped(
+ b, CONST_BUF_LEN(remote_user));
+ buffer_append_string_len(b, CONST_STR_LEN("\""));
+ semicolon = 1;
+ }
+ }
+
+ /* legacy X-* headers, including X-Forwarded-For */
+
+ b = (NULL != efor) ? efor : con->dst_addr_buf;
+ http_header_request_set(con, HTTP_HEADER_X_FORWARDED_FOR,
+ CONST_STR_LEN("X-Forwarded-For"),
+ CONST_BUF_LEN(b));
+
+ b = (NULL != ehost) ? ehost : con->request.http_host;
+ if (!buffer_string_is_empty(b)) {
+ http_header_request_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("X-Host"),
+ CONST_BUF_LEN(b));
+ http_header_request_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("X-Forwarded-Host"),
+ CONST_BUF_LEN(b));
+ }
+
+ b = (NULL != eproto) ? eproto : con->uri.scheme;
+ http_header_request_set(con, HTTP_HEADER_X_FORWARDED_PROTO,
+ CONST_STR_LEN("X-Forwarded-Proto"),
+ CONST_BUF_LEN(b));
+}
+
+
+static handler_t proxy_create_env(server *srv, gw_handler_ctx *gwhctx) {
+ handler_ctx *hctx = (handler_ctx *)gwhctx;
+ connection *con = hctx->gw.remote_conn;
+ const int remap_headers = (NULL != hctx->conf.header.urlpaths
+ || NULL != hctx->conf.header.hosts_request);
+ const int upgrade = hctx->conf.header.upgrade
+ && (NULL != http_header_request_get(con, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade")));
+ size_t rsz = (size_t)(con->read_queue->bytes_out - hctx->gw.wb->bytes_in);
+ buffer * const b = chunkqueue_prepend_buffer_open_sz(hctx->gw.wb, rsz < 65536 ? rsz : con->header_len);
+
+ /* build header */
+
+ /* request line */
+ http_method_append(b, con->request.http_method);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ buffer_append_string_buffer(b, con->request.uri);
+ if (remap_headers)
+ http_header_remap_uri(b, buffer_string_length(b) - buffer_string_length(con->request.uri), &hctx->conf.header, 1);
+ if (!upgrade)
+ buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
+ else
+ buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1\r\n"));
+
+ if (hctx->conf.replace_http_host && !buffer_string_is_empty(hctx->gw.host->id)) {
+ if (hctx->gw.conf.debug > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "SBS",
+ "proxy - using \"", hctx->gw.host->id, "\" as HTTP Host");
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("Host: "));
+ buffer_append_string_buffer(b, hctx->gw.host->id);
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ } else if (!buffer_string_is_empty(con->request.http_host)) {
+ buffer_append_string_len(b, CONST_STR_LEN("Host: "));
+ buffer_append_string_buffer(b, con->request.http_host);
+ if (remap_headers) {
+ size_t alen = buffer_string_length(con->request.http_host);
+ http_header_remap_host(b, buffer_string_length(b) - alen, &hctx->conf.header, 1, alen);
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ }
+
+ /* "Forwarded" and legacy X- headers */
+ proxy_set_Forwarded(con, hctx->conf.forwarded);
+
+ if (HTTP_METHOD_GET != con->request.http_method
+ && HTTP_METHOD_HEAD != con->request.http_method
+ && con->request.content_length >= 0) {
+ /* set Content-Length if client sent Transfer-Encoding: chunked
+ * and not streaming to backend (request body has been fully received) */
+ buffer *vb = http_header_request_get(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ if (NULL == vb) {
+ char buf[LI_ITOSTRING_LENGTH];
+ li_itostrn(buf, sizeof(buf), con->request.content_length);
+ http_header_request_set(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"), buf, strlen(buf));
+ }
+ }
+
+ /* request header */
+ for (size_t i = 0, used = con->request.headers->used; i < used; ++i) {
+ data_string *ds = (data_string *)con->request.headers->data[i];
+ const size_t klen = buffer_string_length(ds->key);
+ size_t vlen;
+ switch (klen) {
+ default:
+ break;
+ case 4:
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Host"))) continue; /*(handled further above)*/
+ break;
+ case 10:
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Connection"))) continue;
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Set-Cookie"))) continue; /*(response header only; avoid accidental reflection)*/
+ break;
+ case 16:
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;
+ break;
+ case 5:
+ /* Do not emit HTTP_PROXY in environment.
+ * Some executables use HTTP_PROXY to configure
+ * outgoing proxy. See also https://httpoxy.org/ */
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) continue;
+ break;
+ case 0:
+ continue;
+ }
+
+ vlen = buffer_string_length(ds->value);
+ if (0 == vlen) continue;
+
+ if (buffer_string_space(b) < klen + vlen + 4) {
+ size_t extend = b->size * 2 - buffer_string_length(b);
+ extend = extend > klen + vlen + 4 ? extend : klen + vlen + 4 + 4095;
+ buffer_string_prepare_append(b, extend);
+ }
+
+ buffer_append_string_len(b, ds->key->ptr, klen);
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
+ buffer_append_string_len(b, ds->value->ptr, vlen);
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+
+ if (!remap_headers) continue;
+
+ /* check for hdrs for which to remap URIs in-place after append to b */
+
+ switch (klen) {
+ default:
+ continue;
+ #if 0 /* "URI" is HTTP response header (non-standard; historical in Apache) */
+ case 3:
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("URI"))) break;
+ continue;
+ #endif
+ #if 0 /* "Location" is HTTP response header */
+ case 8:
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Location"))) break;
+ continue;
+ #endif
+ case 11: /* "Destination" is WebDAV request header */
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Destination"))) break;
+ continue;
+ case 16: /* "Content-Location" may be HTTP request or response header */
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Content-Location"))) break;
+ continue;
+ }
+
+ http_header_remap_uri(b, buffer_string_length(b) - vlen - 2, &hctx->conf.header, 1);
+ }
+
+ if (!upgrade)
+ buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n"));
+ else
+ buffer_append_string_len(b, CONST_STR_LEN("Connection: close, upgrade\r\n\r\n"));
+
+ hctx->gw.wb_reqlen = buffer_string_length(b);
+ chunkqueue_prepend_buffer_commit(hctx->gw.wb);
+
+ if (con->request.content_length) {
+ chunkqueue_append_chunkqueue(hctx->gw.wb, con->request_content_queue);
+ if (con->request.content_length > 0)
+ hctx->gw.wb_reqlen += con->request.content_length; /* total req size */
+ else /* as-yet-unknown total request size (Transfer-Encoding: chunked)*/
+ hctx->gw.wb_reqlen = -hctx->gw.wb_reqlen;
+ }
+
+ status_counter_inc(srv, CONST_STR_LEN("proxy.requests"));
+ return HANDLER_GO_ON;
+}
+
+
+static handler_t proxy_create_env_connect(server *srv, gw_handler_ctx *gwhctx) {
+ handler_ctx *hctx = (handler_ctx *)gwhctx;
+ connection *con = hctx->gw.remote_conn;
+ con->http_status = 200; /* OK */
+ con->file_started = 1;
+ gw_set_transparent(srv, &hctx->gw);
+ http_response_upgrade_read_body_unknown(srv, con);
+
+ status_counter_inc(srv, CONST_STR_LEN("proxy.requests"));
+ return HANDLER_GO_ON;
+}
+
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+#define PATCH_GW(x) \
+ p->conf.gw.x = s->gw.x;
+static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH_GW(exts);
+ PATCH_GW(exts_auth);
+ PATCH_GW(exts_resp);
+ PATCH_GW(debug);
+ PATCH_GW(ext_mapping);
+ PATCH_GW(balance);
+ PATCH(replace_http_host);
+ PATCH(forwarded);
+ PATCH(header); /*(copies struct)*/
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
+ PATCH_GW(exts);
+ PATCH_GW(exts_auth);
+ PATCH_GW(exts_resp);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
+ PATCH_GW(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
+ PATCH_GW(balance);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.map-extensions"))) {
+ PATCH_GW(ext_mapping);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.replace-http-host"))) {
+ PATCH(replace_http_host);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.forwarded"))) {
+ PATCH(forwarded);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.header"))) {
+ PATCH(header); /*(copies struct)*/
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH_GW
+#undef PATCH
+
+static handler_t proxy_response_headers(server *srv, connection *con, struct http_response_opts_t *opts) {
+ /* response headers just completed */
+ handler_ctx *hctx = (handler_ctx *)opts->pdata;
+
+ if (con->response.htags & HTTP_HEADER_UPGRADE) {
+ if (hctx->conf.header.upgrade && con->http_status == 101) {
+ /* 101 Switching Protocols; transition to transparent proxy */
+ gw_set_transparent(srv, &hctx->gw);
+ http_response_upgrade_read_body_unknown(srv, con);
+ }
+ else {
+ con->response.htags &= ~HTTP_HEADER_UPGRADE;
+ #if 0
+ /* preserve prior questionable behavior; likely broken behavior
+ * anyway if backend thinks connection is being upgraded but client
+ * does not receive Connection: upgrade */
+ http_header_response_unset(con, HTTP_HEADER_UPGRADE,
+ CONST_STR_LEN("Upgrade"))
+ #endif
+ }
+ }
+
+ /* rewrite paths, if needed */
+
+ if (NULL == hctx->conf.header.urlpaths
+ && NULL == hctx->conf.header.hosts_response)
+ return HANDLER_GO_ON;
+
+ if (con->response.htags & HTTP_HEADER_LOCATION) {
+ buffer *vb = http_header_response_get(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"));
+ if (vb) http_header_remap_uri(vb, 0, &hctx->conf.header, 0);
+ }
+ if (con->response.htags & HTTP_HEADER_CONTENT_LOCATION) {
+ buffer *vb = http_header_response_get(con, HTTP_HEADER_CONTENT_LOCATION, CONST_STR_LEN("Content-Location"));
+ if (vb) http_header_remap_uri(vb, 0, &hctx->conf.header, 0);
+ }
+ if (con->response.htags & HTTP_HEADER_SET_COOKIE) {
+ buffer *vb = http_header_response_get(con, HTTP_HEADER_SET_COOKIE, CONST_STR_LEN("Set-Cookie"));
+ if (vb) http_header_remap_setcookie(vb, 0, &hctx->conf.header);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ handler_t rc;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ mod_proxy_patch_connection(srv, con, p);
+ if (NULL == p->conf.gw.exts) return HANDLER_GO_ON;
+
+ rc = gw_check_extension(srv, con, (gw_plugin_data *)p, 1, sizeof(handler_ctx));
+ if (HANDLER_GO_ON != rc) return rc;
+
+ if (con->mode == p->id) {
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ hctx->gw.create_env = proxy_create_env;
+ hctx->gw.response = chunk_buffer_acquire();
+ hctx->gw.opts.backend = BACKEND_PROXY;
+ hctx->gw.opts.pdata = hctx;
+ hctx->gw.opts.headers = proxy_response_headers;
+
+ hctx->conf = p->conf; /*(copies struct)*/
+ hctx->conf.header.http_host = con->request.http_host;
+ hctx->conf.header.upgrade &= (con->request.http_version == HTTP_VERSION_1_1);
+ /* mod_proxy currently sends all backend requests as http.
+ * https-remap is a flag since it might not be needed if backend
+ * honors Forwarded or X-Forwarded-Proto headers, e.g. by using
+ * lighttpd mod_extforward or similar functionality in backend*/
+ if (hctx->conf.header.https_remap) {
+ hctx->conf.header.https_remap =
+ buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https"));
+ }
+
+ if (con->request.http_method == HTTP_METHOD_CONNECT) {
+ /*(note: not requiring HTTP/1.1 due to too many non-compliant
+ * clients such as 'openssl s_client')*/
+ if (hctx->conf.header.connect_method) {
+ hctx->gw.create_env = proxy_create_env_connect;
+ }
+ else {
+ con->http_status = 405; /* Method Not Allowed */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_proxy_plugin_init(plugin *p);
+int mod_proxy_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("proxy");
+
+ p->init = mod_proxy_init;
+ p->cleanup = mod_proxy_free;
+ p->set_defaults = mod_proxy_set_defaults;
+ p->connection_reset = gw_connection_reset;
+ p->handle_uri_clean = mod_proxy_check_extension;
+ p->handle_subrequest = gw_handle_subrequest;
+ p->handle_trigger = gw_handle_trigger;
+ p->handle_waitpid = gw_handle_waitpid_cb;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_redirect.c b/data/lighttpd/lighttpd-1.4.53/src/mod_redirect.c
new file mode 100644
index 000000000..94c76d8ee
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_redirect.c
@@ -0,0 +1,203 @@
+#include "first.h"
+
+#include "base.h"
+#include "keyvalue.h"
+#include "log.h"
+#include "buffer.h"
+#include "burl.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ pcre_keyvalue_buffer *redirect;
+ data_config *context; /* to which apply me */
+ unsigned short redirect_code;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_redirect_init) {
+ return calloc(1, sizeof(plugin_data));
+}
+
+FREE_FUNC(mod_redirect_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ pcre_keyvalue_buffer_free(s->redirect);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "url.redirect-code", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ /* 0 */
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+ size_t j;
+ data_unset *du;
+ data_array *da;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->redirect = pcre_keyvalue_buffer_init();
+ s->redirect_code = 301;
+
+ cv[0].destination = s->redirect;
+ cv[1].destination = &(s->redirect_code);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (s->redirect_code < 100 || s->redirect_code >= 1000) s->redirect_code = 301;
+
+ if (NULL == (du = array_get_element(config->value, "url.redirect"))) {
+ /* no url.redirect defined */
+ continue;
+ }
+
+ da = (data_array *)du;
+
+ if (du->type != TYPE_ARRAY || !array_is_kvstring(da->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for url.redirect; expected list of \"regex\" => \"redirect\"");
+ return HANDLER_ERROR;
+ }
+
+ for (j = 0; j < da->value->used; j++) {
+ data_string *ds = (data_string *)da->value->data[j];
+ if (srv->srvconf.http_url_normalize) {
+ pcre_keyvalue_burl_normalize_key(ds->key, srv->tmp_buf);
+ pcre_keyvalue_burl_normalize_value(ds->value, srv->tmp_buf);
+ }
+ if (0 != pcre_keyvalue_buffer_append(srv, s->redirect, ds->key, ds->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre-compile failed for", ds->key);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ p->conf.redirect = s->redirect;
+ p->conf.redirect_code = s->redirect_code;
+ p->conf.context = NULL;
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (0 == strcmp(du->key->ptr, "url.redirect")) {
+ p->conf.redirect = s->redirect;
+ p->conf.context = dc;
+ } else if (0 == strcmp(du->key->ptr, "url.redirect-code")) {
+ p->conf.redirect_code = s->redirect_code;
+ }
+ }
+ }
+
+ return 0;
+}
+
+URIHANDLER_FUNC(mod_redirect_uri_handler) {
+ plugin_data *p = p_d;
+ struct burl_parts_t burl;
+ pcre_keyvalue_ctx ctx;
+ handler_t rc;
+
+ mod_redirect_patch_connection(srv, con, p);
+ if (!p->conf.redirect->used) return HANDLER_GO_ON;
+ ctx.cache = p->conf.context
+ ? &con->cond_cache[p->conf.context->context_ndx]
+ : NULL;
+ ctx.burl = &burl;
+ burl.scheme = con->uri.scheme;
+ burl.authority = con->uri.authority;
+ burl.port = sock_addr_get_port(&con->srv_socket->addr);
+ burl.path = con->uri.path_raw;
+ burl.query = con->uri.query;
+ if (buffer_string_is_empty(burl.authority))
+ burl.authority = con->server_name;
+
+ /* redirect URL on match
+ * e.g. redirect /base/ to /index.php?section=base
+ */
+ rc = pcre_keyvalue_buffer_process(p->conf.redirect, &ctx,
+ con->request.uri, srv->tmp_buf);
+ if (HANDLER_FINISHED == rc) {
+ http_header_response_set(con, HTTP_HEADER_LOCATION,
+ CONST_STR_LEN("Location"),
+ CONST_BUF_LEN(srv->tmp_buf));
+ con->http_status = p->conf.redirect_code;
+ con->mode = DIRECT;
+ con->file_finished = 1;
+ }
+ else if (HANDLER_ERROR == rc) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre_exec() error while processing uri:",
+ con->request.uri);
+ }
+ return rc;
+}
+
+int mod_redirect_plugin_init(plugin *p);
+int mod_redirect_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("redirect");
+
+ p->init = mod_redirect_init;
+ p->handle_uri_clean = mod_redirect_uri_handler;
+ p->set_defaults = mod_redirect_set_defaults;
+ p->cleanup = mod_redirect_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_rewrite.c b/data/lighttpd/lighttpd-1.4.53/src/mod_rewrite.c
new file mode 100644
index 000000000..1280d9784
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_rewrite.c
@@ -0,0 +1,340 @@
+#include "first.h"
+
+#include "base.h"
+#include "keyvalue.h"
+#include "log.h"
+#include "buffer.h"
+#include "burl.h"
+
+#include "plugin.h"
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ pcre_keyvalue_buffer *rewrite;
+ pcre_keyvalue_buffer *rewrite_NF;
+ data_config *context, *context_NF; /* to which apply me */
+ int rewrite_repeat_idx, rewrite_NF_repeat_idx;
+} plugin_config;
+
+typedef struct {
+ enum { REWRITE_STATE_UNSET, REWRITE_STATE_FINISHED} state;
+ int loops;
+} handler_ctx;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static handler_ctx * handler_ctx_init(void) {
+ handler_ctx * hctx;
+
+ hctx = calloc(1, sizeof(*hctx));
+
+ hctx->state = REWRITE_STATE_UNSET;
+ hctx->loops = 0;
+
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+INIT_FUNC(mod_rewrite_init) {
+ return calloc(1, sizeof(plugin_data));
+}
+
+FREE_FUNC(mod_rewrite_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ pcre_keyvalue_buffer_free(s->rewrite);
+ pcre_keyvalue_buffer_free(s->rewrite_NF);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+ return HANDLER_GO_ON;
+}
+
+static int parse_config_entry(server *srv, array *ca, pcre_keyvalue_buffer *kvb, const char *option, size_t olen) {
+ data_unset *du;
+
+ if (NULL != (du = array_get_element_klen(ca, option, olen))) {
+ data_array *da;
+ size_t j;
+
+ da = (data_array *)du;
+
+ if (du->type != TYPE_ARRAY || !array_is_kvstring(da->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "unexpected value for ", option, "; expected list of \"regex\" => \"subst\"");
+ return HANDLER_ERROR;
+ }
+
+ for (j = 0; j < da->value->used; j++) {
+ data_string *ds = (data_string *)da->value->data[j];
+ if (srv->srvconf.http_url_normalize) {
+ pcre_keyvalue_burl_normalize_key(ds->key, srv->tmp_buf);
+ pcre_keyvalue_burl_normalize_value(ds->value, srv->tmp_buf);
+ }
+ if (0 != pcre_keyvalue_buffer_append(srv, kvb, ds->key, ds->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre-compile failed for", ds->key);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return 0;
+}
+
+SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
+ size_t i = 0;
+ config_values_t cv[] = {
+ { "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+
+ /* these functions only rewrite if the target is not already in the filestore
+ *
+ * url.rewrite-repeat-if-not-file is the equivalent of url.rewrite-repeat
+ * url.rewrite-if-not-file is the equivalent of url.rewrite-once
+ *
+ */
+ { "url.rewrite-repeat-if-not-file", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "url.rewrite-if-not-file", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+
+ /* old names, still supported
+ *
+ * url.rewrite remapped to url.rewrite-once
+ * url.rewrite-final is url.rewrite-once
+ *
+ */
+ { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data *p = p_d;
+
+ if (!p) return HANDLER_ERROR;
+
+ /* 0 */
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->rewrite = pcre_keyvalue_buffer_init();
+ s->rewrite_NF = pcre_keyvalue_buffer_init();
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ parse_config_entry(srv, config->value, s->rewrite, CONST_STR_LEN("url.rewrite-once"));
+ parse_config_entry(srv, config->value, s->rewrite, CONST_STR_LEN("url.rewrite-final"));
+ parse_config_entry(srv, config->value, s->rewrite_NF, CONST_STR_LEN("url.rewrite-if-not-file"));
+ s->rewrite_NF_repeat_idx = (int)s->rewrite_NF->used;
+ parse_config_entry(srv, config->value, s->rewrite_NF, CONST_STR_LEN("url.rewrite-repeat-if-not-file"));
+ parse_config_entry(srv, config->value, s->rewrite, CONST_STR_LEN("url.rewrite"));
+ s->rewrite_repeat_idx = (int)s->rewrite->used;
+ parse_config_entry(srv, config->value, s->rewrite, CONST_STR_LEN("url.rewrite-repeat"));
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(rewrite);
+ PATCH(rewrite_NF);
+ p->conf.context = NULL;
+ p->conf.context_NF = NULL;
+ PATCH(rewrite_repeat_idx);
+ PATCH(rewrite_NF_repeat_idx);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
+ PATCH(rewrite);
+ p->conf.context = dc;
+ PATCH(rewrite_repeat_idx);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
+ PATCH(rewrite);
+ p->conf.context = dc;
+ PATCH(rewrite_repeat_idx);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
+ PATCH(rewrite);
+ p->conf.context = dc;
+ PATCH(rewrite_repeat_idx);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-if-not-file"))) {
+ PATCH(rewrite_NF);
+ p->conf.context_NF = dc;
+ PATCH(rewrite_NF_repeat_idx);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat-if-not-file"))) {
+ PATCH(rewrite_NF);
+ p->conf.context_NF = dc;
+ PATCH(rewrite_NF_repeat_idx);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
+ PATCH(rewrite);
+ p->conf.context = dc;
+ PATCH(rewrite_repeat_idx);
+ }
+ }
+ }
+
+ return 0;
+}
+
+URIHANDLER_FUNC(mod_rewrite_con_reset) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (con->plugin_ctx[p->id]) {
+ handler_ctx_free(con->plugin_ctx[p->id]);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t process_rewrite_rules(server *srv, connection *con, plugin_data *p, pcre_keyvalue_buffer *kvb, int repeat_idx) {
+ handler_ctx *hctx;
+ struct burl_parts_t burl;
+ pcre_keyvalue_ctx ctx;
+ handler_t rc;
+
+ if (con->plugin_ctx[p->id]) {
+ hctx = con->plugin_ctx[p->id];
+
+ if (hctx->loops++ > 100) {
+ data_config *dc = p->conf.context;
+ if (NULL == dc) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request");
+ return HANDLER_ERROR;
+ }
+ log_error_write(srv, __FILE__, __LINE__, "SbbSBS",
+ "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat ($", dc->comp_key, dc->op, "\"", dc->string, "\")");
+
+ return HANDLER_ERROR;
+ }
+
+ if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
+ }
+
+ ctx.cache = p->conf.context ? &con->cond_cache[p->conf.context->context_ndx] : NULL;
+ ctx.burl = &burl;
+ burl.scheme = con->uri.scheme;
+ burl.authority = con->uri.authority;
+ burl.port = sock_addr_get_port(&con->srv_socket->addr);
+ burl.path = con->uri.path_raw;
+ burl.query = con->uri.query;
+ if (buffer_string_is_empty(burl.authority))
+ burl.authority = con->server_name;
+
+ rc = pcre_keyvalue_buffer_process(kvb, &ctx, con->request.uri, srv->tmp_buf);
+ if (HANDLER_FINISHED == rc && !buffer_is_empty(srv->tmp_buf) && srv->tmp_buf->ptr[0] == '/') {
+ buffer_copy_buffer(con->request.uri, srv->tmp_buf);
+ if (con->plugin_ctx[p->id] == NULL) {
+ hctx = handler_ctx_init();
+ con->plugin_ctx[p->id] = hctx;
+ } else {
+ hctx = con->plugin_ctx[p->id];
+ }
+ if (ctx.m < repeat_idx) hctx->state = REWRITE_STATE_FINISHED;
+ buffer_reset(con->physical.path);
+ rc = HANDLER_COMEBACK;
+ }
+ else if (HANDLER_FINISHED == rc) {
+ rc = HANDLER_ERROR;
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "mod_rewrite invalid result (not beginning with '/') while processing uri:",
+ con->request.uri);
+ }
+ else if (HANDLER_ERROR == rc) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre_exec() error while processing uri:",
+ con->request.uri);
+ }
+ return rc;
+}
+
+URIHANDLER_FUNC(mod_rewrite_physical) {
+ plugin_data *p = p_d;
+ stat_cache_entry *sce;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ mod_rewrite_patch_connection(srv, con, p);
+ p->conf.context = p->conf.context_NF;
+ if (!p->conf.rewrite_NF->used) return HANDLER_GO_ON;
+
+ /* skip if physical.path is a regular file */
+ sce = NULL;
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ if (S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
+ }
+
+ return process_rewrite_rules(srv, con, p, p->conf.rewrite_NF, p->conf.rewrite_NF_repeat_idx);
+}
+
+URIHANDLER_FUNC(mod_rewrite_uri_handler) {
+ plugin_data *p = p_d;
+
+ mod_rewrite_patch_connection(srv, con, p);
+ if (!p->conf.rewrite->used) return HANDLER_GO_ON;
+
+ return process_rewrite_rules(srv, con, p, p->conf.rewrite, p->conf.rewrite_repeat_idx);
+}
+
+int mod_rewrite_plugin_init(plugin *p);
+int mod_rewrite_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("rewrite");
+
+ p->init = mod_rewrite_init;
+ /* it has to stay _raw as we are matching on uri + querystring
+ */
+
+ p->handle_uri_raw = mod_rewrite_uri_handler;
+ p->handle_physical = mod_rewrite_physical;
+ p->cleanup = mod_rewrite_free;
+ p->connection_reset = mod_rewrite_con_reset;
+ p->set_defaults = mod_rewrite_set_defaults;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_rrdtool.c b/data/lighttpd/lighttpd-1.4.53/src/mod_rrdtool.c
new file mode 100644
index 000000000..009943d01
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_rrdtool.c
@@ -0,0 +1,482 @@
+#include "first.h"
+
+#include "base.h"
+#include "fdevent.h"
+#include "log.h"
+
+#include "plugin.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+
+typedef struct {
+ buffer *path_rrdtool_bin;
+ buffer *path_rrd;
+
+ double requests, *requests_ptr;
+ double bytes_written, *bytes_written_ptr;
+ double bytes_read, *bytes_read_ptr;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *cmd;
+ buffer *resp;
+
+ int read_fd, write_fd;
+ pid_t rrdtool_pid;
+ pid_t srv_pid;
+
+ int rrdtool_running;
+ time_t rrdtool_startup_ts;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_rrd_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->resp = buffer_init();
+ p->cmd = buffer_init();
+
+ return p;
+}
+
+FREE_FUNC(mod_rrd_free) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->path_rrdtool_bin);
+ buffer_free(s->path_rrd);
+
+ free(s);
+ }
+ }
+ buffer_free(p->cmd);
+ buffer_free(p->resp);
+
+ free(p->config_storage);
+
+ if (p->read_fd >= 0) close(p->read_fd);
+ if (p->write_fd >= 0) close(p->write_fd);
+
+ if (p->rrdtool_pid > 0 && p->srv_pid == srv->pid) {
+ /* collect status */
+ while (-1 == waitpid(p->rrdtool_pid, NULL, 0) && errno == EINTR) ;
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+static int mod_rrd_create_pipe(server *srv, plugin_data *p) {
+ char *args[3];
+ int to_rrdtool_fds[2];
+ int from_rrdtool_fds[2];
+ /* mod_rrdtool does not work with server.max-workers > 0
+ * since the data between workers is not aggregated,
+ * and it is not valid to send data to rrdtool more than once a sec
+ * (which would happen with multiple workers writing to same pipe)
+ * If pipes were to be shared, then existing pipes would need to be
+ * reused here, if they already exist (not -1), and after flushing
+ * existing contents (read and discard from read-end of pipes). */
+ if (pipe(to_rrdtool_fds)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "pipe failed: ", strerror(errno));
+ return -1;
+ }
+ if (pipe(from_rrdtool_fds)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "pipe failed: ", strerror(errno));
+ return -1;
+ }
+ fdevent_setfd_cloexec(to_rrdtool_fds[1]);
+ fdevent_setfd_cloexec(from_rrdtool_fds[0]);
+ *(const char **)&args[0] = p->conf.path_rrdtool_bin->ptr;
+ *(const char **)&args[1] = "-";
+ args[2] = NULL;
+
+ p->rrdtool_pid = fdevent_fork_execve(args[0], args, NULL, to_rrdtool_fds[0], from_rrdtool_fds[1], -1, -1);
+
+ if (-1 != p->rrdtool_pid) {
+ close(from_rrdtool_fds[1]);
+ close(to_rrdtool_fds[0]);
+ if (p->read_fd >= 0) close(p->read_fd);
+ if (p->write_fd >= 0) close(p->write_fd);
+ p->write_fd = to_rrdtool_fds[1];
+ p->read_fd = from_rrdtool_fds[0];
+ p->srv_pid = srv->pid;
+ return 0;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "SBss", "fork/exec(", p->conf.path_rrdtool_bin, "):", strerror(errno));
+ close(to_rrdtool_fds[0]);
+ close(to_rrdtool_fds[1]);
+ close(from_rrdtool_fds[0]);
+ close(from_rrdtool_fds[1]);
+ return -1;
+ }
+}
+
+/* read/write wrappers to catch EINTR */
+
+/* write to blocking socket; blocks until all data is sent, write returns 0 or an error (apart from EINTR) occurs. */
+static ssize_t safe_write(int fd, const void *buf, size_t count) {
+ ssize_t res, sum = 0;
+
+ for (;;) {
+ res = write(fd, buf, count);
+ if (res >= 0) {
+ sum += res;
+ /* do not try again if res == 0 */
+ if (res == 0 || (size_t) res == count) return sum;
+ count -= res;
+ buf = (const char*) buf + res;
+ continue;
+ }
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ return -1;
+ }
+ }
+}
+
+/* this assumes we get enough data on a successful read */
+static ssize_t safe_read(int fd, buffer *b) {
+ ssize_t res;
+
+ buffer_string_prepare_copy(b, 4095);
+
+ do {
+ res = read(fd, b->ptr, b->size-1);
+ } while (-1 == res && errno == EINTR);
+
+ if (res >= 0) buffer_commit(b, res);
+ return res;
+}
+
+static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
+ struct stat st;
+
+ /* check if DB already exists */
+ if (0 == stat(s->path_rrd->ptr, &st)) {
+ /* check if it is plain file */
+ if (!S_ISREG(st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "not a regular file:", s->path_rrd);
+ return HANDLER_ERROR;
+ }
+
+ /* still create DB if it's empty file */
+ if (st.st_size > 0) {
+ return HANDLER_GO_ON;
+ }
+ }
+
+ /* create a new one */
+ buffer_copy_string_len(p->cmd, CONST_STR_LEN("create "));
+ buffer_append_string_buffer(p->cmd, s->path_rrd);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(
+ " --step 60 "
+ "DS:InOctets:ABSOLUTE:600:U:U "
+ "DS:OutOctets:ABSOLUTE:600:U:U "
+ "DS:Requests:ABSOLUTE:600:U:U "
+ "RRA:AVERAGE:0.5:1:600 "
+ "RRA:AVERAGE:0.5:6:700 "
+ "RRA:AVERAGE:0.5:24:775 "
+ "RRA:AVERAGE:0.5:288:797 "
+ "RRA:MAX:0.5:1:600 "
+ "RRA:MAX:0.5:6:700 "
+ "RRA:MAX:0.5:24:775 "
+ "RRA:MAX:0.5:288:797 "
+ "RRA:MIN:0.5:1:600 "
+ "RRA:MIN:0.5:6:700 "
+ "RRA:MIN:0.5:24:775 "
+ "RRA:MIN:0.5:288:797\n"));
+
+ if (-1 == (safe_write(p->write_fd, CONST_BUF_LEN(p->cmd)))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-write: failed", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+
+ if (-1 == safe_read(p->read_fd, p->resp)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-read: failed", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+ log_error_write(srv, __FILE__, __LINE__, "sbb",
+ "rrdtool-response:", p->cmd, p->resp);
+
+ return HANDLER_ERROR;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(path_rrdtool_bin);
+ PATCH(path_rrd);
+
+ p->conf.bytes_written_ptr = &(s->bytes_written);
+ p->conf.bytes_read_ptr = &(s->bytes_read);
+ p->conf.requests_ptr = &(s->requests);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
+ PATCH(path_rrd);
+ /* get pointers to double values */
+
+ p->conf.bytes_written_ptr = &(s->bytes_written);
+ p->conf.bytes_read_ptr = &(s->bytes_read);
+ p->conf.requests_ptr = &(s->requests);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int mod_rrd_exec(server *srv, plugin_data *p) {
+ if (mod_rrd_create_pipe(srv, p)) {
+ return -1;
+ }
+
+ p->rrdtool_running = 1;
+ p->rrdtool_startup_ts = srv->cur_ts;
+ return 0;
+}
+
+SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+ int activate = 0;
+
+ config_values_t cv[] = {
+ { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ force_assert(srv->config_context->used > 0);
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->path_rrdtool_bin = buffer_init();
+ s->path_rrd = buffer_init();
+ s->requests = 0;
+ s->bytes_written = 0;
+ s->bytes_read = 0;
+
+ cv[0].destination = s->path_rrdtool_bin;
+ cv[1].destination = s->path_rrd;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (i > 0 && !buffer_string_is_empty(s->path_rrdtool_bin)) {
+ /* path_rrdtool_bin is a global option */
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "rrdtool.binary can only be set as a global option.");
+
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->path_rrd)) activate = 1;
+ }
+
+ p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
+ p->rrdtool_running = 0;
+ p->read_fd = -1;
+ p->write_fd = -1;
+
+ if (!activate) return HANDLER_GO_ON;
+
+ /* check for dir */
+
+ if (buffer_string_is_empty(p->conf.path_rrdtool_bin)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "rrdtool.binary has to be set");
+ return HANDLER_ERROR;
+ }
+
+ return 0 == mod_rrd_exec(srv, p) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
+
+static void mod_rrd_fatal_error(server *srv, plugin_data *p) {
+ /* future: might send kill() signal to p->rrdtool_pid to trigger restart */
+ p->rrdtool_running = 0;
+ UNUSED(srv);
+}
+
+TRIGGER_FUNC(mod_rrd_trigger) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ if (!p->rrdtool_running) {
+ /* limit restart to once every 5 sec */
+ /*(0 == p->rrdtool_pid if never activated; not used)*/
+ if (-1 == p->rrdtool_pid
+ && p->srv_pid == srv->pid
+ && p->rrdtool_startup_ts + 5 < srv->cur_ts) {
+ mod_rrd_exec(srv, p);
+ }
+ return HANDLER_GO_ON;
+ }
+
+ if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (buffer_string_is_empty(s->path_rrd)) continue;
+
+ /* write the data down every minute */
+
+ if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_GO_ON;
+
+ buffer_copy_string_len(p->cmd, CONST_STR_LEN("update "));
+ buffer_append_string_buffer(p->cmd, s->path_rrd);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(" N:"));
+ buffer_append_int(p->cmd, s->bytes_read);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
+ buffer_append_int(p->cmd, s->bytes_written);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
+ buffer_append_int(p->cmd, s->requests);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN("\n"));
+
+ if (-1 == safe_write(p->write_fd, CONST_BUF_LEN(p->cmd))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-write: failed", strerror(errno));
+
+ mod_rrd_fatal_error(srv, p);
+ return HANDLER_GO_ON;
+ }
+
+ if (-1 == safe_read(p->read_fd, p->resp)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-read: failed", strerror(errno));
+
+ mod_rrd_fatal_error(srv, p);
+ return HANDLER_GO_ON;
+ }
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+ /* don't fail on this error if we just started (graceful restart, the old one might have just updated too) */
+ if (!(strstr(p->resp->ptr, "(minimum one second step)") && (srv->cur_ts - srv->startup_ts < 3))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbb",
+ "rrdtool-response:", p->cmd, p->resp);
+
+ mod_rrd_fatal_error(srv, p);
+ return HANDLER_GO_ON;
+ }
+ }
+ s->requests = 0;
+ s->bytes_written = 0;
+ s->bytes_read = 0;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_rrd_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) {
+ plugin_data *p = p_d;
+ if (pid != p->rrdtool_pid) return HANDLER_GO_ON;
+ if (srv->pid != p->srv_pid) return HANDLER_GO_ON;
+
+ p->rrdtool_running = 0;
+ p->rrdtool_pid = -1;
+
+ /* limit restart to once every 5 sec */
+ if (p->rrdtool_startup_ts + 5 < srv->cur_ts)
+ mod_rrd_exec(srv, p);
+
+ UNUSED(status);
+ return HANDLER_FINISHED;
+}
+
+REQUESTDONE_FUNC(mod_rrd_account) {
+ plugin_data *p = p_d;
+
+ /*(0 == p->rrdtool_pid if never activated; not used)*/
+ if (0 == p->rrdtool_pid) return HANDLER_GO_ON;
+ mod_rrd_patch_connection(srv, con, p);
+
+ *(p->conf.requests_ptr) += 1;
+ *(p->conf.bytes_written_ptr) += con->bytes_written;
+ *(p->conf.bytes_read_ptr) += con->bytes_read;
+
+ return HANDLER_GO_ON;
+}
+
+int mod_rrdtool_plugin_init(plugin *p);
+int mod_rrdtool_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("rrd");
+
+ p->init = mod_rrd_init;
+ p->cleanup = mod_rrd_free;
+ p->set_defaults= mod_rrd_set_defaults;
+
+ p->handle_trigger = mod_rrd_trigger;
+ p->handle_waitpid = mod_rrd_waitpid_cb;
+ p->handle_request_done = mod_rrd_account;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_scgi.c b/data/lighttpd/lighttpd-1.4.53/src/mod_scgi.c
new file mode 100644
index 000000000..785e66a30
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_scgi.c
@@ -0,0 +1,327 @@
+#include "first.h"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gw_backend.h"
+typedef gw_plugin_config plugin_config;
+typedef gw_plugin_data plugin_data;
+typedef gw_handler_ctx handler_ctx;
+
+#include "base.h"
+#include "buffer.h"
+#include "log.h"
+#include "status_counter.h"
+
+#include "sys-endian.h"
+
+enum { LI_PROTOCOL_SCGI, LI_PROTOCOL_UWSGI };
+
+SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
+ plugin_data *p = p_d;
+ data_unset *du;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "scgi.protocol", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "scgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "scgi.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+ force_assert(p->config_storage);
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ force_assert(s);
+ s->exts = NULL;
+ s->exts_auth = NULL;
+ s->exts_resp = NULL;
+ s->debug = 0;
+ s->proto = LI_PROTOCOL_SCGI;
+ s->ext_mapping = array_init();
+
+ cv[0].destination = s->exts; /* not used; T_CONFIG_LOCAL */
+ cv[1].destination = &(s->debug);
+ cv[2].destination = NULL; /* not used; T_CONFIG_LOCAL */
+ cv[3].destination = s->ext_mapping;
+ cv[4].destination = NULL; /* not used; T_CONFIG_LOCAL */
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "scgi.server");
+ if (!gw_set_defaults_backend(srv, p, du, i, 1)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "scgi.balance");
+ if (!gw_set_defaults_balance(srv, s, du)) {
+ return HANDLER_ERROR;
+ }
+
+ if (NULL != (du = array_get_element(config->value, "scgi.protocol"))) {
+ data_string *ds = (data_string *)du;
+ if (du->type == TYPE_STRING
+ && buffer_is_equal_string(ds->value, CONST_STR_LEN("scgi"))) {
+ s->proto = LI_PROTOCOL_SCGI;
+ } else if (du->type == TYPE_STRING
+ && buffer_is_equal_string(ds->value, CONST_STR_LEN("uwsgi"))) {
+ s->proto = LI_PROTOCOL_UWSGI;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "unexpected type for key: ", "scgi.protocol", "expected \"scgi\" or \"uwsgi\"");
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static int scgi_env_add_scgi(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
+ buffer *env = venv;
+ char *dst;
+ size_t len;
+
+ if (!key || !val) return -1;
+
+ len = key_len + val_len + 2;
+
+ if (buffer_string_space(env) < len) {
+ size_t extend = env->size * 2 - buffer_string_length(env);
+ extend = extend > len ? extend : len + 4095;
+ buffer_string_prepare_append(env, extend);
+ }
+
+ dst = buffer_string_prepare_append(env, len);
+ memcpy(dst, key, key_len);
+ dst[key_len] = '\0';
+ memcpy(dst + key_len + 1, val, val_len);
+ dst[key_len + 1 + val_len] = '\0';
+ buffer_commit(env, len);
+
+ return 0;
+}
+
+
+#ifdef __LITTLE_ENDIAN__
+#define uwsgi_htole16(x) (x)
+#else /* __BIG_ENDIAN__ */
+#define uwsgi_htole16(x) ((uint16_t) (((x) & 0xff) << 8 | ((x) & 0xff00) >> 8))
+#endif
+
+
+static int scgi_env_add_uwsgi(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
+ buffer *env = venv;
+ char *dst;
+ size_t len;
+ uint16_t uwlen;
+
+ if (!key || !val) return -1;
+ if (key_len > USHRT_MAX || val_len > USHRT_MAX) return -1;
+
+ len = 2 + key_len + 2 + val_len;
+
+ if (buffer_string_space(env) < len) {
+ size_t extend = env->size * 2 - buffer_string_length(env);
+ extend = extend > len ? extend : len + 4095;
+ buffer_string_prepare_append(env, extend);
+ }
+
+ dst = buffer_string_prepare_append(env, len);
+ uwlen = uwsgi_htole16((uint16_t)key_len);
+ memcpy(dst, (char *)&uwlen, 2);
+ memcpy(dst + 2, key, key_len);
+ uwlen = uwsgi_htole16((uint16_t)val_len);
+ memcpy(dst + 2 + key_len, (char *)&uwlen, 2);
+ memcpy(dst + 2 + key_len + 2, val, val_len);
+ buffer_commit(env, len);
+
+ return 0;
+}
+
+
+static handler_t scgi_create_env(server *srv, handler_ctx *hctx) {
+ gw_host *host = hctx->host;
+ connection *con = hctx->remote_conn;
+ http_cgi_opts opts = { 0, 0, host->docroot, NULL };
+ http_cgi_header_append_cb scgi_env_add = hctx->conf.proto == LI_PROTOCOL_SCGI
+ ? scgi_env_add_scgi
+ : scgi_env_add_uwsgi;
+ size_t offset;
+ size_t rsz = (size_t)(con->read_queue->bytes_out - hctx->wb->bytes_in);
+ buffer * const b = chunkqueue_prepend_buffer_open_sz(hctx->wb, rsz < 65536 ? rsz : con->header_len);
+
+ /* save space for 9 digits (plus ':'), though incoming HTTP request
+ * currently limited to 64k (65535, so 5 chars) */
+ buffer_copy_string_len(b, CONST_STR_LEN(" "));
+
+ if (0 != http_cgi_headers(srv, con, &opts, scgi_env_add, b)) {
+ con->http_status = 400;
+ con->mode = DIRECT;
+ buffer_clear(b);
+ chunkqueue_remove_finished_chunks(hctx->wb);
+ return HANDLER_FINISHED;
+ }
+
+ if (hctx->conf.proto == LI_PROTOCOL_SCGI) {
+ size_t len;
+ scgi_env_add(b, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
+ buffer_clear(srv->tmp_buf);
+ buffer_append_int(srv->tmp_buf, buffer_string_length(b)-10);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(":"));
+ len = buffer_string_length(srv->tmp_buf);
+ offset = 10 - len;
+ memcpy(b->ptr+offset, srv->tmp_buf->ptr, len);
+ buffer_append_string_len(b, CONST_STR_LEN(","));
+ } else { /* LI_PROTOCOL_UWSGI */
+ /* http://uwsgi-docs.readthedocs.io/en/latest/Protocol.html */
+ size_t len = buffer_string_length(b)-10;
+ uint32_t uwsgi_header;
+ if (len > USHRT_MAX) {
+ con->http_status = 431; /* Request Header Fields Too Large */
+ con->mode = DIRECT;
+ buffer_clear(b);
+ chunkqueue_remove_finished_chunks(hctx->wb);
+ return HANDLER_FINISHED;
+ }
+ offset = 10 - 4;
+ uwsgi_header = ((uint32_t)uwsgi_htole16((uint16_t)len)) << 8;
+ memcpy(b->ptr+offset, (char *)&uwsgi_header, 4);
+ }
+
+ hctx->wb_reqlen = buffer_string_length(b) - offset;
+ chunkqueue_prepend_buffer_commit(hctx->wb);
+ #if 0
+ hctx->wb->first->offset += (off_t)offset;
+ hctx->wb->bytes_in -= (off_t)offset;
+ #else
+ chunkqueue_mark_written(hctx->wb, offset);
+ #endif
+
+ if (con->request.content_length) {
+ chunkqueue_append_chunkqueue(hctx->wb, con->request_content_queue);
+ if (con->request.content_length > 0)
+ hctx->wb_reqlen += con->request.content_length; /* total req size */
+ else /* as-yet-unknown total request size (Transfer-Encoding: chunked)*/
+ hctx->wb_reqlen = -hctx->wb_reqlen;
+ }
+
+ status_counter_inc(srv, CONST_STR_LEN("scgi.requests"));
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(exts);
+ PATCH(exts_auth);
+ PATCH(exts_resp);
+ PATCH(proto);
+ PATCH(debug);
+ PATCH(balance);
+ PATCH(ext_mapping);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
+ PATCH(exts);
+ PATCH(exts_auth);
+ PATCH(exts_resp);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.protocol"))) {
+ PATCH(proto);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.balance"))) {
+ PATCH(balance);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
+ PATCH(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.map-extensions"))) {
+ PATCH(ext_mapping);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
+ plugin_data *p = p_d;
+ handler_t rc;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ scgi_patch_connection(srv, con, p);
+ if (NULL == p->conf.exts) return HANDLER_GO_ON;
+
+ rc = gw_check_extension(srv, con, p, uri_path_handler, 0);
+ if (HANDLER_GO_ON != rc) return rc;
+
+ if (con->mode == p->id) {
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ hctx->opts.backend = BACKEND_SCGI;
+ hctx->create_env = scgi_create_env;
+ hctx->response = chunk_buffer_acquire();
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/* uri-path handler */
+static handler_t scgi_check_extension_1(server *srv, connection *con, void *p_d) {
+ return scgi_check_extension(srv, con, p_d, 1);
+}
+
+/* start request handler */
+static handler_t scgi_check_extension_2(server *srv, connection *con, void *p_d) {
+ return scgi_check_extension(srv, con, p_d, 0);
+}
+
+
+
+int mod_scgi_plugin_init(plugin *p);
+int mod_scgi_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("scgi");
+
+ p->init = gw_init;
+ p->cleanup = gw_free;
+ p->set_defaults = mod_scgi_set_defaults;
+ p->connection_reset = gw_connection_reset;
+ p->handle_uri_clean = scgi_check_extension_1;
+ p->handle_subrequest_start = scgi_check_extension_2;
+ p->handle_subrequest = gw_handle_subrequest;
+ p->handle_trigger = gw_handle_trigger;
+ p->handle_waitpid = gw_handle_waitpid_cb;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_secdownload.c b/data/lighttpd/lighttpd-1.4.53/src/mod_secdownload.c
new file mode 100644
index 000000000..41d6a2c75
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_secdownload.c
@@ -0,0 +1,571 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "base64.h"
+#include "http_auth.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sys-crypto.h"
+#ifdef USE_OPENSSL_CRYPTO
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#endif
+
+#include "md5.h"
+
+/*
+ * mod_secdownload verifies a checksum associated with a timestamp
+ * and a path.
+ *
+ * It takes an URL of the form:
+ * securl := <uri-prefix> <mac> <protected-path>
+ * uri-prefix := '/' any* # whatever was configured: must start with a '/')
+ * mac := [a-zA-Z0-9_-]{mac_len} # mac length depends on selected algorithm
+ * protected-path := '/' <timestamp> <rel-path>
+ * timestamp := [a-f0-9]{8} # timestamp when the checksum was calculated
+ * # to prevent access after timeout (active requests
+ * # will finish successfully even after the timeout)
+ * rel-path := '/' any* # the protected path; changing the path breaks the
+ * # checksum
+ *
+ * The timestamp is the `epoch` timestamp in hex, i.e. time in seconds
+ * since 00:00:00 UTC on 1 January 1970.
+ *
+ * mod_secdownload supports various MAC algorithms:
+ *
+ * # md5
+ * mac_len := 32 (and hex only)
+ * mac := md5-hex(<secrect><rel-path><timestamp>) # lowercase hex
+ * perl example:
+ use Digest::MD5 qw(md5_hex);
+ my $secret = "verysecret";
+ my $rel_path = "/index.html"
+ my $xtime = sprintf("%08x", time);
+ my $url = '/'. md5_hex($secret . $rel_path . $xtime) . '/' . $xtime . $rel_path;
+ *
+ * # hmac-sha1
+ * mac_len := 27 (no base64 padding)
+ * mac := base64-url(hmac-sha1(<secret>, <protected-path>))
+ * perl example:
+ use Digest::SHA qw(hmac_sha1);
+ use MIME::Base64 qw(encode_base64url);
+ my $secret = "verysecret";
+ my $rel_path = "/index.html"
+ my $protected_path = '/' . sprintf("%08x", time) . $rel_path;
+ my $url = '/'. encode_base64url(hmac_sha1($protected_path, $secret)) . $protected_path;
+ *
+ * # hmac-256
+ * mac_len := 43 (no base64 padding)
+ * mac := base64-url(hmac-256(<secret>, <protected-path>))
+ use Digest::SHA qw(hmac_sha256);
+ use MIME::Base64 qw(encode_base64url);
+ my $secret = "verysecret";
+ my $rel_path = "/index.html"
+ my $protected_path = '/' . sprintf("%08x", time) . $rel_path;
+ my $url = '/'. encode_base64url(hmac_sha256($protected_path, $secret)) . $protected_path;
+ *
+ */
+
+/* plugin config for all request/connections */
+
+typedef enum {
+ SECDL_INVALID = 0,
+ SECDL_MD5 = 1,
+ SECDL_HMAC_SHA1 = 2,
+ SECDL_HMAC_SHA256 = 3,
+} secdl_algorithm;
+
+typedef struct {
+ buffer *doc_root;
+ buffer *secret;
+ buffer *uri_prefix;
+ secdl_algorithm algorithm;
+
+ unsigned int timeout;
+ unsigned short path_segments;
+ unsigned short hash_querystr;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+static int const_time_memeq(const char *a, const char *b, size_t len) {
+ /* constant time memory compare, unless the compiler figures it out */
+ char diff = 0;
+ size_t i;
+ for (i = 0; i < len; ++i) {
+ diff |= (a[i] ^ b[i]);
+ }
+ return 0 == diff;
+}
+
+static const char* secdl_algorithm_names[] = {
+ "invalid",
+ "md5",
+ "hmac-sha1",
+ "hmac-sha256",
+};
+
+static secdl_algorithm algorithm_from_string(buffer *name) {
+ size_t ndx;
+
+ if (buffer_string_is_empty(name)) return SECDL_INVALID;
+
+ for (ndx = 1; ndx < sizeof(secdl_algorithm_names)/sizeof(secdl_algorithm_names[0]); ++ndx) {
+ if (0 == strcmp(secdl_algorithm_names[ndx], name->ptr)) return (secdl_algorithm)ndx;
+ }
+
+ return SECDL_INVALID;
+}
+
+static size_t secdl_algorithm_mac_length(secdl_algorithm alg) {
+ switch (alg) {
+ case SECDL_INVALID:
+ break;
+ case SECDL_MD5:
+ return 32;
+ case SECDL_HMAC_SHA1:
+ return 27;
+ case SECDL_HMAC_SHA256:
+ return 43;
+ }
+ return 0;
+}
+
+static int secdl_verify_mac(server *srv, plugin_config *config, const char* protected_path, const char* mac, size_t maclen) {
+ UNUSED(srv);
+ if (0 == maclen || secdl_algorithm_mac_length(config->algorithm) != maclen) return 0;
+
+ switch (config->algorithm) {
+ case SECDL_INVALID:
+ break;
+ case SECDL_MD5:
+ {
+ li_MD5_CTX Md5Ctx;
+ const char *ts_str;
+ const char *rel_uri;
+ unsigned char HA1[16];
+ unsigned char md5bin[16];
+
+ if (0 != http_auth_md5_hex2bin(mac, maclen, md5bin)) return 0;
+
+ /* legacy message:
+ * protected_path := '/' <timestamp-hex> <rel-path>
+ * timestamp-hex := [0-9a-f]{8}
+ * rel-path := '/' any*
+ * (the protected path was already verified)
+ * message = <secret><rel-path><timestamp-hex>
+ */
+ ts_str = protected_path + 1;
+ rel_uri = ts_str + 8;
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(config->secret));
+ li_MD5_Update(&Md5Ctx, rel_uri, strlen(rel_uri));
+ li_MD5_Update(&Md5Ctx, ts_str, 8);
+ li_MD5_Final(HA1, &Md5Ctx);
+
+ return const_time_memeq((char *)HA1, (char *)md5bin, sizeof(md5bin));
+ }
+ case SECDL_HMAC_SHA1:
+#ifdef USE_OPENSSL_CRYPTO
+ {
+ unsigned char digest[20];
+ char base64_digest[27];
+
+ if (NULL == HMAC(
+ EVP_sha1(),
+ (unsigned char const*) config->secret->ptr, buffer_string_length(config->secret),
+ (unsigned char const*) protected_path, strlen(protected_path),
+ digest, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "hmac-sha1: HMAC() failed");
+ return 0;
+ }
+
+ li_to_base64_no_padding(base64_digest, 27, digest, 20, BASE64_URL);
+
+ return (27 == maclen) && const_time_memeq(mac, base64_digest, 27);
+ }
+#endif
+ break;
+ case SECDL_HMAC_SHA256:
+#ifdef USE_OPENSSL_CRYPTO
+ {
+ unsigned char digest[32];
+ char base64_digest[43];
+
+ if (NULL == HMAC(
+ EVP_sha256(),
+ (unsigned char const*) config->secret->ptr, buffer_string_length(config->secret),
+ (unsigned char const*) protected_path, strlen(protected_path),
+ digest, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "hmac-sha256: HMAC() failed");
+ return 0;
+ }
+
+ li_to_base64_no_padding(base64_digest, 43, digest, 32, BASE64_URL);
+
+ return (43 == maclen) && const_time_memeq(mac, base64_digest, 43);
+ }
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_secdownload_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_secdownload_free) {
+ plugin_data *p = p_d;
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->secret);
+ buffer_free(s->doc_root);
+ buffer_free(s->uri_prefix);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "secdownload.timeout", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "secdownload.algorithm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "secdownload.path-segments", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "secdownload.hash-querystr", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+ buffer *algorithm = buffer_init();
+
+ s = calloc(1, sizeof(plugin_config));
+ s->secret = buffer_init();
+ s->doc_root = buffer_init();
+ s->uri_prefix = buffer_init();
+ s->timeout = 60;
+ s->path_segments = 0;
+ s->hash_querystr = 0;
+
+ cv[0].destination = s->secret;
+ cv[1].destination = s->doc_root;
+ cv[2].destination = s->uri_prefix;
+ cv[3].destination = &(s->timeout);
+ cv[4].destination = algorithm;
+ cv[5].destination = &(s->path_segments);
+ cv[6].destination = &(s->hash_querystr);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ buffer_free(algorithm);
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_is_empty(algorithm)) {
+ s->algorithm = algorithm_from_string(algorithm);
+ switch (s->algorithm) {
+ case SECDL_INVALID:
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid secdownload.algorithm:",
+ algorithm);
+ buffer_free(algorithm);
+ return HANDLER_ERROR;
+#ifndef USE_OPENSSL_CRYPTO
+ case SECDL_HMAC_SHA1:
+ case SECDL_HMAC_SHA256:
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "unsupported secdownload.algorithm:",
+ algorithm);
+#endif
+ default:
+ break;
+ }
+ }
+
+ buffer_free(algorithm);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/**
+ * checks if the supplied string is a hex string
+ *
+ * @param str a possible hex string
+ * @return if the supplied string is a valid hex string 1 is returned otherwise 0
+ */
+
+static int is_hex_len(const char *str, size_t len) {
+ size_t i;
+
+ if (NULL == str) return 0;
+
+ for (i = 0; i < len && *str; i++, str++) {
+ /* illegal characters */
+ if (!((*str >= '0' && *str <= '9') ||
+ (*str >= 'a' && *str <= 'f') ||
+ (*str >= 'A' && *str <= 'F'))
+ ) {
+ return 0;
+ }
+ }
+
+ return i == len;
+}
+
+/**
+ * checks if the supplied string is a base64 (modified URL) string
+ *
+ * @param str a possible base64 (modified URL) string
+ * @return if the supplied string is a valid base64 (modified URL) string 1 is returned otherwise 0
+ */
+
+static int is_base64_len(const char *str, size_t len) {
+ size_t i;
+
+ if (NULL == str) return 0;
+
+ for (i = 0; i < len && *str; i++, str++) {
+ /* illegal characters */
+ if (!((*str >= '0' && *str <= '9') ||
+ (*str >= 'a' && *str <= 'z') ||
+ (*str >= 'A' && *str <= 'Z') ||
+ (*str == '-') || (*str == '_'))
+ ) {
+ return 0;
+ }
+ }
+
+ return i == len;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(secret);
+ PATCH(doc_root);
+ PATCH(uri_prefix);
+ PATCH(timeout);
+ PATCH(algorithm);
+ PATCH(path_segments);
+ PATCH(hash_querystr);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
+ PATCH(secret);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
+ PATCH(doc_root);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
+ PATCH(uri_prefix);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
+ PATCH(timeout);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.algorithm"))) {
+ PATCH(algorithm);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.path-segments"))) {
+ PATCH(path_segments);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.hash-querystr"))) {
+ PATCH(hash_querystr);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+URIHANDLER_FUNC(mod_secdownload_uri_handler) {
+ plugin_data *p = p_d;
+ const char *rel_uri, *ts_str, *mac_str, *protected_path;
+ time_t ts = 0;
+ size_t i, mac_len;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_secdownload_patch_connection(srv, con, p);
+
+ if (buffer_string_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
+
+ if (buffer_string_is_empty(p->conf.secret)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "secdownload.secret has to be set");
+ con->http_status = 500;
+ return HANDLER_FINISHED;
+ }
+
+ if (buffer_string_is_empty(p->conf.doc_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "secdownload.document-root has to be set");
+ con->http_status = 500;
+ return HANDLER_FINISHED;
+ }
+
+ if (SECDL_INVALID == p->conf.algorithm) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "secdownload.algorithm has to be set");
+ con->http_status = 500;
+ return HANDLER_FINISHED;
+ }
+
+ mac_len = secdl_algorithm_mac_length(p->conf.algorithm);
+
+ if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, buffer_string_length(p->conf.uri_prefix))) return HANDLER_GO_ON;
+
+ mac_str = con->uri.path->ptr + buffer_string_length(p->conf.uri_prefix);
+
+ if (!is_base64_len(mac_str, mac_len)) return HANDLER_GO_ON;
+
+ protected_path = mac_str + mac_len;
+ if (*protected_path != '/') return HANDLER_GO_ON;
+
+ ts_str = protected_path + 1;
+ if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
+ if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
+
+ for (i = 0; i < 8; i++) {
+ ts = (ts << 4) + hex2int(ts_str[i]);
+ }
+
+ /* timed-out */
+ if ( (srv->cur_ts > ts && (unsigned int) (srv->cur_ts - ts) > p->conf.timeout) ||
+ (srv->cur_ts < ts && (unsigned int) (ts - srv->cur_ts) > p->conf.timeout) ) {
+ /* "Gone" as the url will never be valid again instead of "408 - Timeout" where the request may be repeated */
+ con->http_status = 410;
+
+ return HANDLER_FINISHED;
+ }
+
+ rel_uri = ts_str + 8;
+
+ if (p->conf.path_segments) {
+ const char *rel_uri_end = rel_uri;
+ unsigned int count = p->conf.path_segments;
+ do {
+ rel_uri_end = strchr(rel_uri_end+1, '/');
+ } while (rel_uri_end && --count);
+ if (rel_uri_end) {
+ buffer_copy_string_len(srv->tmp_buf, protected_path,
+ rel_uri_end - protected_path);
+ protected_path = srv->tmp_buf->ptr;
+ }
+ }
+
+ if (p->conf.hash_querystr && !buffer_is_empty(con->uri.query)) {
+ buffer *b = srv->tmp_buf;
+ if (protected_path != b->ptr) {
+ buffer_copy_string(b, protected_path);
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("?"));
+ buffer_append_string_buffer(b, con->uri.query);
+ /* assign last in case b->ptr is reallocated */
+ protected_path = b->ptr;
+ }
+
+ if (!secdl_verify_mac(srv, &p->conf, protected_path, mac_str, mac_len)) {
+ con->http_status = 403;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "mac invalid:",
+ con->uri.path);
+ }
+
+ return HANDLER_FINISHED;
+ }
+
+ /* starting with the last / we should have relative-path to the docroot
+ */
+
+ buffer_copy_buffer(con->physical.doc_root, p->conf.doc_root);
+ buffer_copy_buffer(con->physical.basedir, p->conf.doc_root);
+ buffer_copy_string(con->physical.rel_path, rel_uri);
+ buffer_copy_buffer(con->physical.path, con->physical.doc_root);
+ buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
+
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_secdownload_plugin_init(plugin *p);
+int mod_secdownload_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("secdownload");
+
+ p->init = mod_secdownload_init;
+ p->handle_physical = mod_secdownload_uri_handler;
+ p->set_defaults = mod_secdownload_set_defaults;
+ p->cleanup = mod_secdownload_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_setenv.c b/data/lighttpd/lighttpd-1.4.53/src/mod_setenv.c
new file mode 100644
index 000000000..43eb7abe3
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_setenv.c
@@ -0,0 +1,314 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *request_header;
+ array *set_request_header;
+ array *response_header;
+ array *set_response_header;
+ array *environment;
+ array *set_environment;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+typedef struct {
+ int handled; /* make sure that we only apply the headers once */
+ plugin_config conf;
+} handler_ctx;
+
+static handler_ctx * handler_ctx_init(void) {
+ handler_ctx * hctx;
+
+ hctx = calloc(1, sizeof(*hctx));
+
+ hctx->handled = 0;
+
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+
+/* init the plugin data */
+INIT_FUNC(mod_setenv_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_setenv_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->request_header);
+ array_free(s->response_header);
+ array_free(s->environment);
+ array_free(s->set_request_header);
+ array_free(s->set_response_header);
+ array_free(s->set_environment);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "setenv.set-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "setenv.set-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "setenv.set-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->request_header = array_init();
+ s->response_header = array_init();
+ s->environment = array_init();
+ s->set_request_header = array_init();
+ s->set_response_header = array_init();
+ s->set_environment = array_init();
+
+ cv[0].destination = s->request_header;
+ cv[1].destination = s->response_header;
+ cv[2].destination = s->environment;
+ cv[3].destination = s->set_request_header;
+ cv[4].destination = s->set_response_header;
+ cv[5].destination = s->set_environment;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if ( !array_is_kvstring(s->request_header)
+ || !array_is_kvstring(s->response_header)
+ || !array_is_kvstring(s->environment)
+ || !array_is_kvstring(s->set_request_header)
+ || !array_is_kvstring(s->set_response_header)
+ || !array_is_kvstring(s->set_environment)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for setenv.xxxxxx; expected list of \"envvar\" => \"value\"");
+ return HANDLER_ERROR;
+ }
+
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(request_header);
+ PATCH(set_request_header);
+ PATCH(response_header);
+ PATCH(set_response_header);
+ PATCH(environment);
+ PATCH(set_environment);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
+ PATCH(request_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.set-request-header"))) {
+ PATCH(set_request_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
+ PATCH(response_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.set-response-header"))) {
+ PATCH(set_response_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
+ PATCH(environment);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.set-environment"))) {
+ PATCH(set_environment);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_setenv_uri_handler) {
+ plugin_data *p = p_d;
+ size_t k;
+ handler_ctx *hctx;
+
+ if (con->plugin_ctx[p->id]) {
+ hctx = con->plugin_ctx[p->id];
+ } else {
+ hctx = handler_ctx_init();
+
+ con->plugin_ctx[p->id] = hctx;
+ }
+
+ if (hctx->handled) {
+ return HANDLER_GO_ON;
+ }
+
+ hctx->handled = 1;
+
+ mod_setenv_patch_connection(srv, con, p);
+ memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
+
+ for (k = 0; k < p->conf.request_header->used; k++) {
+ data_string *ds = (data_string *)p->conf.request_header->data[k];
+ enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
+ http_header_request_append(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
+ }
+
+ for (k = 0; k < hctx->conf.set_request_header->used; ++k) {
+ data_string *ds = (data_string *)hctx->conf.set_request_header->data[k];
+ enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
+ !buffer_string_is_empty(ds->value)
+ ? http_header_request_set(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value))
+ : http_header_request_unset(con, id, CONST_BUF_LEN(ds->key));
+ }
+
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_setenv_handle_request_env) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (hctx->handled > 1) return HANDLER_GO_ON;
+ hctx->handled = 2;
+ UNUSED(srv);
+
+ for (size_t k = 0; k < hctx->conf.environment->used; ++k) {
+ data_string *ds = (data_string *)hctx->conf.environment->data[k];
+ http_header_env_append(con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
+ }
+
+ for (size_t k = 0; k < hctx->conf.set_environment->used; ++k) {
+ data_string *ds = (data_string *)hctx->conf.set_environment->data[k];
+ http_header_env_set(con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
+ }
+
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_setenv_handle_response_start) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ UNUSED(srv);
+
+ for (size_t k = 0; k < hctx->conf.response_header->used; ++k) {
+ data_string *ds = (data_string *)hctx->conf.response_header->data[k];
+ enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
+ http_header_response_insert(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
+ }
+
+ for (size_t k = 0; k < hctx->conf.set_response_header->used; ++k) {
+ data_string *ds = (data_string *)hctx->conf.set_response_header->data[k];
+ enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(ds->key));
+ !buffer_string_is_empty(ds->value)
+ ? http_header_response_set(con, id, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value))
+ : http_header_response_unset(con, id, CONST_BUF_LEN(ds->key));
+ }
+
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_setenv_reset) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (con->plugin_ctx[p->id]) {
+ handler_ctx_free(con->plugin_ctx[p->id]);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_setenv_plugin_init(plugin *p);
+int mod_setenv_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("setenv");
+
+ p->init = mod_setenv_init;
+ p->handle_uri_clean = mod_setenv_uri_handler;
+ p->handle_request_env = mod_setenv_handle_request_env;
+ p->handle_response_start = mod_setenv_handle_response_start;
+ p->set_defaults = mod_setenv_set_defaults;
+ p->cleanup = mod_setenv_free;
+
+ p->connection_reset = mod_setenv_reset;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_simple_vhost.c b/data/lighttpd/lighttpd-1.4.53/src/mod_simple_vhost.c
new file mode 100644
index 000000000..1fae140f1
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_simple_vhost.c
@@ -0,0 +1,287 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "stat_cache.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+typedef struct {
+ buffer *server_root;
+ buffer *default_host;
+ buffer *document_root;
+
+ buffer *docroot_cache_key;
+ buffer *docroot_cache_value;
+ buffer *docroot_cache_servername;
+
+ unsigned short debug;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *doc_root;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_simple_vhost_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->doc_root = buffer_init();
+
+ return p;
+}
+
+FREE_FUNC(mod_simple_vhost_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+
+ buffer_free(s->document_root);
+ buffer_free(s->default_host);
+ buffer_free(s->server_root);
+
+ buffer_free(s->docroot_cache_key);
+ buffer_free(s->docroot_cache_value);
+ buffer_free(s->docroot_cache_servername);
+
+ free(s);
+ }
+
+ free(p->config_storage);
+ }
+
+ buffer_free(p->doc_root);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ config_values_t cv[] = {
+ { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+
+ s->server_root = buffer_init();
+ s->default_host = buffer_init();
+ s->document_root = buffer_init();
+
+ s->docroot_cache_key = buffer_init();
+ s->docroot_cache_value = buffer_init();
+ s->docroot_cache_servername = buffer_init();
+
+ s->debug = 0;
+
+ cv[0].destination = s->server_root;
+ cv[1].destination = s->default_host;
+ cv[2].destination = s->document_root;
+ cv[3].destination = &(s->debug);
+
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->server_root))
+ buffer_append_slash(s->server_root);
+ if (!buffer_string_is_empty(s->document_root))
+ buffer_append_slash(s->document_root);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static void build_doc_root_path(buffer *out, buffer *sroot, buffer *host, buffer *droot) {
+ force_assert(!buffer_string_is_empty(sroot));
+ buffer_copy_buffer(out, sroot);
+
+ if (!buffer_string_is_empty(host)) {
+ /* a hostname has to start with a alpha-numerical character
+ * and must not contain a slash "/"
+ */
+ char *dp;
+ if (NULL == (dp = strchr(host->ptr, ':'))) {
+ buffer_append_string_buffer(out, host);
+ } else {
+ buffer_append_string_len(out, host->ptr, dp - host->ptr);
+ }
+ }
+
+ if (!buffer_string_is_empty(droot)) {
+ buffer_append_path_len(out, CONST_BUF_LEN(droot));
+ }
+ else {
+ buffer_append_slash(out);
+ }
+}
+
+static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
+ stat_cache_entry *sce = NULL;
+
+ build_doc_root_path(out, p->conf.server_root, host, p->conf.document_root);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ strerror(errno), out);
+ }
+ return -1;
+ } else if (!S_ISDIR(sce->st.st_mode)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(server_root);
+ PATCH(default_host);
+ PATCH(document_root);
+
+ PATCH(docroot_cache_key);
+ PATCH(docroot_cache_value);
+ PATCH(docroot_cache_servername);
+
+ PATCH(debug);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
+ PATCH(server_root);
+ PATCH(docroot_cache_key);
+ PATCH(docroot_cache_value);
+ PATCH(docroot_cache_servername);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
+ PATCH(default_host);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
+ PATCH(document_root);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
+ PATCH(debug);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
+ plugin_data *p = p_data;
+
+ /*
+ * cache the last successfull translation from hostname (authority) to docroot
+ * - this saves us a stat() call
+ *
+ */
+
+ mod_simple_vhost_patch_connection(srv, con, p);
+
+ /* build_doc_root() requires a server_root; skip module if simple-vhost.server-root is not set
+ * or set to an empty string (especially don't cache any results!)
+ */
+ if (buffer_string_is_empty(p->conf.server_root)) return HANDLER_GO_ON;
+
+ if (!buffer_string_is_empty(p->conf.docroot_cache_key) &&
+ !buffer_string_is_empty(con->uri.authority) &&
+ buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
+ /* cache hit */
+ buffer_copy_buffer(con->server_name, p->conf.docroot_cache_servername);
+ buffer_copy_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
+ } else {
+ /* build document-root */
+ if (buffer_string_is_empty(con->uri.authority) ||
+ build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
+ /* not found, fallback the default-host */
+ if (0 == build_doc_root(srv, con, p,
+ p->doc_root,
+ p->conf.default_host)) {
+ /* default host worked */
+ buffer_copy_buffer(con->server_name, p->conf.default_host);
+ buffer_copy_buffer(con->physical.doc_root, p->doc_root);
+ /* do not cache default host */
+ }
+ return HANDLER_GO_ON;
+ }
+
+ /* found host */
+ buffer_copy_buffer(con->server_name, con->uri.authority);
+ buffer_copy_buffer(con->physical.doc_root, p->doc_root);
+
+ /* copy to cache */
+ buffer_copy_buffer(p->conf.docroot_cache_key, con->uri.authority);
+ buffer_copy_buffer(p->conf.docroot_cache_value, p->doc_root);
+ buffer_copy_buffer(p->conf.docroot_cache_servername, con->server_name);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_simple_vhost_plugin_init(plugin *p);
+int mod_simple_vhost_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("simple_vhost");
+
+ p->init = mod_simple_vhost_init;
+ p->set_defaults = mod_simple_vhost_set_defaults;
+ p->handle_docroot = mod_simple_vhost_docroot;
+ p->cleanup = mod_simple_vhost_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_skeleton.c b/data/lighttpd/lighttpd-1.4.53/src/mod_skeleton.c
new file mode 100644
index 000000000..464f7b8de
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_skeleton.c
@@ -0,0 +1,183 @@
+#include "first.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "plugin.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "array.h"
+
+/**
+ * this is a skeleton for a lighttpd plugin
+ *
+ * just replaces every occurrence of 'skeleton' by your plugin name
+ *
+ * e.g. in vim:
+ *
+ * :%s/skeleton/myhandler/
+ *
+ */
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *match;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+
+#if 0 /* (needed if module keeps state for request) */
+
+typedef struct {
+ size_t foo;
+} handler_ctx;
+
+static handler_ctx * handler_ctx_init() {
+ handler_ctx * hctx = calloc(1, sizeof(*hctx));
+ force_assert(hctx);
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+#endif
+
+
+/* init the plugin data */
+INIT_FUNC(mod_skeleton_init) {
+ return calloc(1, sizeof(plugin_data));
+}
+
+/* destroy the plugin data */
+FREE_FUNC(mod_skeleton_free) {
+ plugin_data *p = p_d;
+ UNUSED(srv);
+ if (!p) return HANDLER_GO_ON;
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ array_free(s->match);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+ force_assert(p->config_storage);
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+ force_assert(s);
+ s->match = array_init();
+
+ cv[0].destination = s->match;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->match)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for skeleton.array; expected list of \"urlpath\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(match);
+
+ /* skip the first, the global context */
+ for (size_t 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 (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
+ PATCH(match);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_skeleton_uri_handler) {
+ plugin_data *p = p_d;
+ UNUSED(srv);
+
+ /* determine whether or not module participates in request */
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+ if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ /* get module config for request */
+ mod_skeleton_patch_connection(srv, con, p);
+
+ if (NULL == array_match_value_suffix(p->conf.match, con->uri.path)) {
+ return HANDLER_GO_ON;
+ }
+
+ /* module participates in request; business logic here */
+
+ con->http_status = 403; /* example: reject request with 403 Forbidden */
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_skeleton_plugin_init(plugin *p);
+int mod_skeleton_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("skeleton");
+ p->data = NULL;
+ p->init = mod_skeleton_init;
+ p->cleanup = mod_skeleton_free;
+ p->set_defaults= mod_skeleton_set_defaults;
+
+ p->handle_uri_clean = mod_skeleton_uri_handler;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_sockproxy.c b/data/lighttpd/lighttpd-1.4.53/src/mod_sockproxy.c
new file mode 100644
index 000000000..27d69ee8c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_sockproxy.c
@@ -0,0 +1,180 @@
+#include "first.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gw_backend.h"
+typedef gw_plugin_config plugin_config;
+typedef gw_plugin_data plugin_data;
+typedef gw_handler_ctx handler_ctx;
+
+#include "base.h"
+#include "array.h"
+#include "buffer.h"
+#include "log.h"
+#include "status_counter.h"
+
+/**
+ *
+ * socket proxy (with optional buffering)
+ *
+ */
+
+SETDEFAULTS_FUNC(mod_sockproxy_set_defaults) {
+ plugin_data *p = p_d;
+ data_unset *du;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "sockproxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "sockproxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "sockproxy.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+ force_assert(p->config_storage);
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ force_assert(s);
+ s->exts = NULL;
+ s->exts_auth = NULL;
+ s->exts_resp = NULL;
+ s->debug = 0;
+
+ cv[0].destination = NULL; /* T_CONFIG_LOCAL */
+ cv[1].destination = &(s->debug);
+ cv[2].destination = NULL; /* T_CONFIG_LOCAL */
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "sockproxy.server");
+ if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, du, i, 0)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(config->value, "sockproxy.balance");
+ if (!gw_set_defaults_balance(srv, s, du)) {
+ return HANDLER_ERROR;
+ }
+
+ /* disable check-local for all exts (default enabled) */
+ if (s->exts) { /*(check after gw_set_defaults_backend())*/
+ for (size_t j = 0; j < s->exts->used; ++j) {
+ gw_extension *ex = s->exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ ex->hosts[n]->check_local = 0;
+ }
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static handler_t sockproxy_create_env_connect(server *srv, handler_ctx *hctx) {
+ connection *con = hctx->remote_conn;
+ con->file_started = 1;
+ gw_set_transparent(srv, hctx);
+ http_response_upgrade_read_body_unknown(srv, con);
+
+ status_counter_inc(srv, CONST_STR_LEN("sockproxy.requests"));
+ return HANDLER_GO_ON;
+}
+
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_sockproxy_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(exts);
+ PATCH(exts_auth);
+ PATCH(exts_resp);
+ PATCH(debug);
+ PATCH(ext_mapping);
+ PATCH(balance);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("sockproxy.server"))) {
+ PATCH(exts);
+ PATCH(exts_auth);
+ PATCH(exts_resp);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("sockproxy.debug"))) {
+ PATCH(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("sockproxy.balance"))) {
+ PATCH(balance);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static handler_t mod_sockproxy_connection_accept(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ handler_t rc;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ mod_sockproxy_patch_connection(srv, con, p);
+ if (NULL == p->conf.exts) return HANDLER_GO_ON;
+
+ /*(fake con->uri.path for matching purposes in gw_check_extension())*/
+ buffer_copy_string_len(con->uri.path, CONST_STR_LEN("/"));
+
+ rc = gw_check_extension(srv, con, p, 1, 0);
+ if (HANDLER_GO_ON != rc) return rc;
+
+ if (con->mode == p->id) {
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ hctx->opts.backend = BACKEND_PROXY;
+ hctx->create_env = sockproxy_create_env_connect;
+ hctx->response = chunk_buffer_acquire();
+ con->http_status = -1; /*(skip HTTP processing)*/
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_sockproxy_plugin_init(plugin *p);
+int mod_sockproxy_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("sockproxy");
+
+ p->init = gw_init;
+ p->cleanup = gw_free;
+ p->set_defaults = mod_sockproxy_set_defaults;
+ p->connection_reset = gw_connection_reset;
+ p->handle_connection_accept= mod_sockproxy_connection_accept;
+ p->handle_subrequest = gw_handle_subrequest;
+ p->handle_trigger = gw_handle_trigger;
+ p->handle_waitpid = gw_handle_waitpid_cb;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi.c b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi.c
new file mode 100644
index 000000000..f05f8a6e8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi.c
@@ -0,0 +1,1365 @@
+#include "first.h"
+
+#include "base.h"
+#include "fdevent.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include "response.h"
+
+#include "mod_ssi.h"
+
+#include "sys-socket.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sys-strings.h"
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include "etag.h"
+
+static handler_ctx * handler_ctx_init(plugin_data *p) {
+ handler_ctx *hctx = calloc(1, sizeof(*hctx));
+ force_assert(hctx);
+ hctx->timefmt = p->timefmt;
+ hctx->stat_fn = p->stat_fn;
+ hctx->ssi_vars = p->ssi_vars;
+ hctx->ssi_cgi_env = p->ssi_cgi_env;
+ memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+/* The newest modified time of included files for include statement */
+static volatile time_t include_file_last_mtime = 0;
+
+/* init the plugin data */
+INIT_FUNC(mod_ssi_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->timefmt = buffer_init();
+ p->stat_fn = buffer_init();
+
+ p->ssi_vars = array_init();
+ p->ssi_cgi_env = array_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_ssi_free) {
+ plugin_data *p = p_d;
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->ssi_extension);
+ buffer_free(s->content_type);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ array_free(p->ssi_vars);
+ array_free(p->ssi_cgi_env);
+ buffer_free(p->timefmt);
+ buffer_free(p->stat_fn);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "ssi.content-type", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "ssi.conditional-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "ssi.exec", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "ssi.recursion-max", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->ssi_extension = array_init();
+ s->content_type = buffer_init();
+ s->conditional_requests = 0;
+ s->ssi_exec = 1;
+ s->ssi_recursion_max = 0;
+
+ cv[0].destination = s->ssi_extension;
+ cv[1].destination = s->content_type;
+ cv[2].destination = &(s->conditional_requests);
+ cv[3].destination = &(s->ssi_exec);
+ cv[4].destination = &(s->ssi_recursion_max);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->ssi_extension)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for ssi.extension; expected list of \"ext\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static int ssi_env_add(void *venv, const char *key, size_t klen, const char *val, size_t vlen) {
+ array_insert_key_value((array *)venv, key, klen, val, vlen);
+ return 0;
+}
+
+static int build_ssi_cgi_vars(server *srv, connection *con, handler_ctx *p) {
+ http_cgi_opts opts = { 0, 0, NULL, NULL };
+ /* temporarily remove Authorization from request headers
+ * so that Authorization does not end up in SSI environment */
+ buffer *vb_auth = http_header_request_get(con, HTTP_HEADER_AUTHORIZATION, CONST_STR_LEN("Authorization"));
+ buffer b_auth;
+ if (vb_auth) {
+ memcpy(&b_auth, vb_auth, sizeof(buffer));
+ memset(vb_auth, 0, sizeof(buffer));
+ }
+
+ array_reset_data_strings(p->ssi_cgi_env);
+
+ if (0 != http_cgi_headers(srv, con, &opts, ssi_env_add, p->ssi_cgi_env)) {
+ con->http_status = 400;
+ return -1;
+ }
+
+ if (vb_auth) {
+ memcpy(vb_auth, &b_auth, sizeof(buffer));
+ }
+
+ return 0;
+}
+
+static int mod_ssi_process_file(server *srv, connection *con, handler_ctx *p, struct stat *st);
+
+static int process_ssi_stmt(server *srv, connection *con, handler_ctx *p, const char **l, size_t n, struct stat *st) {
+
+ /**
+ * <!--#element attribute=value attribute=value ... -->
+ *
+ * config DONE
+ * errmsg -- missing
+ * sizefmt DONE
+ * timefmt DONE
+ * echo DONE
+ * var DONE
+ * encoding -- missing
+ * exec DONE
+ * cgi -- never
+ * cmd DONE
+ * fsize DONE
+ * file DONE
+ * virtual DONE
+ * flastmod DONE
+ * file DONE
+ * virtual DONE
+ * include DONE
+ * file DONE
+ * virtual DONE
+ * printenv DONE
+ * set DONE
+ * var DONE
+ * value DONE
+ *
+ * if DONE
+ * elif DONE
+ * else DONE
+ * endif DONE
+ *
+ *
+ * expressions
+ * AND, OR DONE
+ * comp DONE
+ * ${...} -- missing
+ * $... DONE
+ * '...' DONE
+ * ( ... ) DONE
+ *
+ *
+ *
+ * ** all DONE **
+ * DATE_GMT
+ * The current date in Greenwich Mean Time.
+ * DATE_LOCAL
+ * The current date in the local time zone.
+ * DOCUMENT_NAME
+ * The filename (excluding directories) of the document requested by the user.
+ * DOCUMENT_URI
+ * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
+ * LAST_MODIFIED
+ * The last modification date of the document requested by the user.
+ * USER_NAME
+ * Contains the owner of the file which included it.
+ *
+ */
+
+ size_t i, ssicmd = 0;
+ char buf[255];
+ buffer *b = NULL;
+
+ static const struct {
+ const char *var;
+ enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
+ SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
+ SSI_ELSE, SSI_ENDIF, SSI_EXEC, SSI_COMMENT } type;
+ } ssicmds[] = {
+ { "echo", SSI_ECHO },
+ { "include", SSI_INCLUDE },
+ { "flastmod", SSI_FLASTMOD },
+ { "fsize", SSI_FSIZE },
+ { "config", SSI_CONFIG },
+ { "printenv", SSI_PRINTENV },
+ { "set", SSI_SET },
+ { "if", SSI_IF },
+ { "elif", SSI_ELIF },
+ { "endif", SSI_ENDIF },
+ { "else", SSI_ELSE },
+ { "exec", SSI_EXEC },
+ { "comment", SSI_COMMENT },
+
+ { NULL, SSI_UNSET }
+ };
+
+ for (i = 0; ssicmds[i].var; i++) {
+ if (0 == strcmp(l[1], ssicmds[i].var)) {
+ ssicmd = ssicmds[i].type;
+ break;
+ }
+ }
+
+ switch(ssicmd) {
+ case SSI_ECHO: {
+ /* echo */
+ int var = 0;
+ /* int enc = 0; */
+ const char *var_val = NULL;
+
+ static const struct {
+ const char *var;
+ enum {
+ SSI_ECHO_UNSET,
+ SSI_ECHO_DATE_GMT,
+ SSI_ECHO_DATE_LOCAL,
+ SSI_ECHO_DOCUMENT_NAME,
+ SSI_ECHO_DOCUMENT_URI,
+ SSI_ECHO_LAST_MODIFIED,
+ SSI_ECHO_USER_NAME,
+ SSI_ECHO_SCRIPT_URI,
+ SSI_ECHO_SCRIPT_URL,
+ } type;
+ } echovars[] = {
+ { "DATE_GMT", SSI_ECHO_DATE_GMT },
+ { "DATE_LOCAL", SSI_ECHO_DATE_LOCAL },
+ { "DOCUMENT_NAME", SSI_ECHO_DOCUMENT_NAME },
+ { "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
+ { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
+ { "USER_NAME", SSI_ECHO_USER_NAME },
+ { "SCRIPT_URI", SSI_ECHO_SCRIPT_URI },
+ { "SCRIPT_URL", SSI_ECHO_SCRIPT_URL },
+
+ { NULL, SSI_ECHO_UNSET }
+ };
+
+/*
+ static const struct {
+ const char *var;
+ enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
+ } encvars[] = {
+ { "url", SSI_ENC_URL },
+ { "none", SSI_ENC_NONE },
+ { "entity", SSI_ENC_ENTITY },
+
+ { NULL, SSI_ENC_UNSET }
+ };
+*/
+
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "var")) {
+ int j;
+
+ var_val = l[i+1];
+
+ for (j = 0; echovars[j].var; j++) {
+ if (0 == strcmp(l[i+1], echovars[j].var)) {
+ var = echovars[j].type;
+ break;
+ }
+ }
+ } else if (0 == strcmp(l[i], "encoding")) {
+/*
+ int j;
+
+ for (j = 0; encvars[j].var; j++) {
+ if (0 == strcmp(l[i+1], encvars[j].var)) {
+ enc = encvars[j].type;
+ break;
+ }
+ }
+*/
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+
+ if (p->if_is_false) break;
+
+ if (!var_val) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: ",
+ l[1], "var is missing");
+ break;
+ }
+
+ switch(var) {
+ case SSI_ECHO_USER_NAME: {
+ struct passwd *pw;
+
+ b = srv->tmp_buf;
+#ifdef HAVE_PWD_H
+ if (NULL == (pw = getpwuid(st->st_uid))) {
+ buffer_copy_int(b, st->st_uid);
+ } else {
+ buffer_copy_string(b, pw->pw_name);
+ }
+#else
+ buffer_copy_int(b, st->st_uid);
+#endif
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+ break;
+ }
+ case SSI_ECHO_LAST_MODIFIED: {
+ time_t t = st->st_mtime;
+
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ }
+ case SSI_ECHO_DATE_LOCAL: {
+ time_t t = time(NULL);
+
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ }
+ case SSI_ECHO_DATE_GMT: {
+ time_t t = time(NULL);
+
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ }
+ case SSI_ECHO_DOCUMENT_NAME: {
+ char *sl;
+
+ if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->physical.path));
+ } else {
+ chunkqueue_append_mem(con->write_queue, sl + 1, strlen(sl + 1));
+ }
+ break;
+ }
+ case SSI_ECHO_DOCUMENT_URI: {
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.path));
+ break;
+ }
+ case SSI_ECHO_SCRIPT_URI: {
+ if (!buffer_string_is_empty(con->uri.scheme) && !buffer_string_is_empty(con->uri.authority)) {
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.scheme));
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("://"));
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.authority));
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->request.uri));
+ if (!buffer_string_is_empty(con->uri.query)) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("?"));
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.query));
+ }
+ }
+ break;
+ }
+ case SSI_ECHO_SCRIPT_URL: {
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->request.uri));
+ if (!buffer_string_is_empty(con->uri.query)) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("?"));
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.query));
+ }
+ break;
+ }
+ default: {
+ data_string *ds;
+ /* check if it is a cgi-var or a ssi-var */
+
+ if (NULL != (ds = (data_string *)array_get_element_klen(p->ssi_cgi_env, var_val, strlen(var_val))) ||
+ NULL != (ds = (data_string *)array_get_element_klen(p->ssi_vars, var_val, strlen(var_val)))) {
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(ds->value));
+ } else {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ }
+
+ break;
+ }
+ }
+ break;
+ }
+ case SSI_INCLUDE:
+ case SSI_FLASTMOD:
+ case SSI_FSIZE: {
+ const char * file_path = NULL, *virt_path = NULL;
+ struct stat stb;
+ char *sl;
+
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "file")) {
+ file_path = l[i+1];
+ } else if (0 == strcmp(l[i], "virtual")) {
+ virt_path = l[i+1];
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+
+ if (!file_path && !virt_path) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: ",
+ l[1], "file or virtual are missing");
+ break;
+ }
+
+ if (file_path && virt_path) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: ",
+ l[1], "only one of file and virtual is allowed here");
+ break;
+ }
+
+
+ if (p->if_is_false) break;
+
+ if (file_path) {
+ /* current doc-root */
+ if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
+ buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
+ } else {
+ buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
+ }
+
+ buffer_copy_string(srv->tmp_buf, file_path);
+ buffer_urldecode_path(srv->tmp_buf);
+ if (!buffer_is_valid_UTF8(srv->tmp_buf)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "SSI invalid UTF-8 after url-decode:", srv->tmp_buf);
+ break;
+ }
+ buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
+ buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
+ } else {
+ /* virtual */
+ size_t remain;
+
+ if (virt_path[0] == '/') {
+ buffer_copy_string(srv->tmp_buf, virt_path);
+ } else {
+ /* there is always a / */
+ sl = strrchr(con->uri.path->ptr, '/');
+
+ buffer_copy_string_len(srv->tmp_buf, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
+ buffer_append_string(srv->tmp_buf, virt_path);
+ }
+
+ buffer_urldecode_path(srv->tmp_buf);
+ if (!buffer_is_valid_UTF8(srv->tmp_buf)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "SSI invalid UTF-8 after url-decode:", srv->tmp_buf);
+ break;
+ }
+ buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
+
+ /* we have an uri */
+
+ /* Destination physical path (similar to code in mod_webdav.c)
+ * src con->physical.path might have been remapped with mod_alias, mod_userdir.
+ * (but neither modifies con->physical.rel_path)
+ * Find matching prefix to support relative paths to current physical path.
+ * Aliasing of paths underneath current con->physical.basedir might not work.
+ * Likewise, mod_rewrite URL rewriting might thwart this comparison.
+ * Use mod_redirect instead of mod_alias to remap paths *under* this basedir.
+ * Use mod_redirect instead of mod_rewrite on *any* parts of path to basedir.
+ * (Related, use mod_auth to protect this basedir, but avoid attempting to
+ * use mod_auth on paths underneath this basedir, as target path is not
+ * validated with mod_auth)
+ */
+
+ /* find matching URI prefix
+ * check if remaining con->physical.rel_path matches suffix
+ * of con->physical.basedir so that we can use it to
+ * remap Destination physical path */
+ {
+ const char *sep, *sep2;
+ sep = con->uri.path->ptr;
+ sep2 = srv->tmp_buf->ptr;
+ for (i = 0; sep[i] && sep[i] == sep2[i]; ++i) ;
+ while (i != 0 && sep[--i] != '/') ; /* find matching directory path */
+ }
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(srv->tmp_buf);
+ }
+ remain = buffer_string_length(con->uri.path) - i;
+ if (!con->conf.force_lowercase_filenames
+ ? buffer_is_equal_right_len(con->physical.path, con->physical.rel_path, remain)
+ :(buffer_string_length(con->physical.path) >= remain
+ && 0 == strncasecmp(con->physical.path->ptr+buffer_string_length(con->physical.path)-remain, con->physical.rel_path->ptr+i, remain))) {
+ buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, buffer_string_length(con->physical.path)-remain);
+ buffer_append_string_len(p->stat_fn, srv->tmp_buf->ptr+i, buffer_string_length(srv->tmp_buf)-i);
+ } else {
+ /* unable to perform physical path remap here;
+ * assume doc_root/rel_path and no remapping */
+ buffer_copy_buffer(p->stat_fn, con->physical.doc_root);
+ buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
+ }
+ }
+
+ if (0 == stat(p->stat_fn->ptr, &stb)) {
+ time_t t = stb.st_mtime;
+
+ switch (ssicmd) {
+ case SSI_FSIZE:
+ b = srv->tmp_buf;
+ if (p->sizefmt) {
+ int j = 0;
+ const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
+
+ off_t s = stb.st_size;
+
+ for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
+
+ buffer_copy_int(b, s);
+ buffer_append_string(b, abr[j]);
+ } else {
+ buffer_copy_int(b, stb.st_size);
+ }
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+ break;
+ case SSI_FLASTMOD:
+ if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
+ } else {
+ chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
+ }
+ break;
+ case SSI_INCLUDE:
+ /* Keep the newest mtime of included files */
+ if (stb.st_mtime > include_file_last_mtime)
+ include_file_last_mtime = stb.st_mtime;
+
+ if (file_path || 0 == p->conf.ssi_recursion_max) {
+ /* don't process if #include file="..." is used */
+ chunkqueue_append_file(con->write_queue, p->stat_fn, 0, stb.st_size);
+ } else {
+ buffer *upsave, *ppsave, *prpsave;
+
+ /* only allow predefined recursion depth */
+ if (p->ssi_recursion_depth >= p->conf.ssi_recursion_max) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(error: include directives recurse deeper than pre-defined ssi.recursion-max)"));
+ break;
+ }
+
+ /* prevents simple infinite loop */
+ if (buffer_is_equal(con->physical.path, p->stat_fn)) {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(error: include directives create an infinite loop)"));
+ break;
+ }
+
+ /* save and restore con->physical.path, con->physical.rel_path, and con->uri.path around include
+ *
+ * srv->tmp_buf contains url-decoded, path-simplified, and lowercased (if con->conf.force_lowercase) uri path of target.
+ * con->uri.path and con->physical.rel_path are set to the same since we only operate on filenames here,
+ * not full re-run of all modules for subrequest */
+ upsave = con->uri.path;
+ ppsave = con->physical.path;
+ prpsave = con->physical.rel_path;
+
+ con->physical.path = p->stat_fn;
+ p->stat_fn = buffer_init();
+
+ con->uri.path = con->physical.rel_path = buffer_init_buffer(srv->tmp_buf);
+
+ /*(ignore return value; muddle along as best we can if error occurs)*/
+ ++p->ssi_recursion_depth;
+ mod_ssi_process_file(srv, con, p, &stb);
+ --p->ssi_recursion_depth;
+
+ buffer_free(con->uri.path);
+ con->uri.path = upsave;
+ con->physical.rel_path = prpsave;
+
+ buffer_free(p->stat_fn);
+ p->stat_fn = con->physical.path;
+ con->physical.path = ppsave;
+ }
+
+ break;
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "ssi: stating failed ",
+ p->stat_fn, strerror(errno));
+ }
+ break;
+ }
+ case SSI_SET: {
+ const char *key = NULL, *val = NULL;
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "var")) {
+ key = l[i+1];
+ } else if (0 == strcmp(l[i], "value")) {
+ val = l[i+1];
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+
+ if (p->if_is_false) break;
+
+ if (key && val) {
+ array_insert_key_value(p->ssi_vars, key, strlen(key), val, strlen(val));
+ } else if (key || val) {
+ log_error_write(srv, __FILE__, __LINE__, "sSSss",
+ "ssi: var and value have to be set in <!--#set", l[1], "=", l[2], "-->");
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ssi: var and value have to be set in <!--#set var=... value=... -->");
+ }
+ break;
+ }
+ case SSI_CONFIG:
+ if (p->if_is_false) break;
+
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "timefmt")) {
+ buffer_copy_string(p->timefmt, l[i+1]);
+ } else if (0 == strcmp(l[i], "sizefmt")) {
+ if (0 == strcmp(l[i+1], "abbrev")) {
+ p->sizefmt = 1;
+ } else if (0 == strcmp(l[i+1], "bytes")) {
+ p->sizefmt = 0;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sssss",
+ "ssi: unknown value for attribute '",
+ l[i],
+ "' for ",
+ l[1], l[i+1]);
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+ break;
+ case SSI_PRINTENV:
+ if (p->if_is_false) break;
+
+ b = srv->tmp_buf;
+ buffer_clear(b);
+ for (i = 0; i < p->ssi_vars->used; i++) {
+ data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
+
+ buffer_append_string_buffer(b, ds->key);
+ buffer_append_string_len(b, CONST_STR_LEN("="));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+ for (i = 0; i < p->ssi_cgi_env->used; i++) {
+ data_string *ds = (data_string *)p->ssi_cgi_env->data[p->ssi_cgi_env->sorted[i]];
+
+ buffer_append_string_buffer(b, ds->key);
+ buffer_append_string_len(b, CONST_STR_LEN("="));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+ break;
+ case SSI_EXEC: {
+ const char *cmd = NULL;
+ pid_t pid;
+ chunk *c;
+ char *args[4];
+
+ if (!p->conf.ssi_exec) { /* <!--#exec ... --> disabled by config */
+ break;
+ }
+
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "cmd")) {
+ cmd = l[i+1];
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+
+ if (p->if_is_false) break;
+
+ /*
+ * as exec is assumed evil it is implemented synchronously
+ */
+
+ if (!cmd) break;
+
+ /* send cmd output to a temporary file */
+ if (0 != chunkqueue_append_mem_to_tempfile(srv, con->write_queue, "", 0)) break;
+ c = con->write_queue->last;
+
+ *(const char **)&args[0] = "/bin/sh";
+ *(const char **)&args[1] = "-c";
+ *(const char **)&args[2] = cmd;
+ args[3] = NULL;
+
+ /*(expects STDIN_FILENO open to /dev/null)*/
+ pid = fdevent_fork_execve(args[0], args, NULL, -1, c->file.fd, -1, -1);
+ if (-1 == pid) {
+ log_error_write(srv, __FILE__, __LINE__, "sss", "spawning exec failed:", strerror(errno), cmd);
+ } else {
+ struct stat stb;
+ int status;
+
+ /* wait for the client to end */
+ /* NOTE: synchronous; blocks entire lighttpd server */
+
+ /*
+ * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
+ */
+ while (-1 == waitpid(pid, &status, 0)) {
+ if (errno != EINTR) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
+ break;
+ }
+ }
+ if (!WIFEXITED(status)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "process exited abnormally:", cmd);
+ }
+ if (0 == fstat(c->file.fd, &stb)) {
+ c->file.length = stb.st_size;
+ }
+ }
+
+ break;
+ }
+ case SSI_IF: {
+ const char *expr = NULL;
+
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "expr")) {
+ expr = l[i+1];
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+
+ if (!expr) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: ",
+ l[1], "expr missing");
+ break;
+ }
+
+ if ((!p->if_is_false) &&
+ ((p->if_is_false_level == 0) ||
+ (p->if_level < p->if_is_false_level))) {
+ switch (ssi_eval_expr(srv, con, p, expr)) {
+ case -1:
+ case 0:
+ p->if_is_false = 1;
+ p->if_is_false_level = p->if_level;
+ break;
+ case 1:
+ p->if_is_false = 0;
+ break;
+ }
+ }
+
+ p->if_level++;
+
+ break;
+ }
+ case SSI_ELSE:
+ p->if_level--;
+
+ if (p->if_is_false) {
+ if ((p->if_level == p->if_is_false_level) &&
+ (p->if_is_false_endif == 0)) {
+ p->if_is_false = 0;
+ }
+ } else {
+ p->if_is_false = 1;
+
+ p->if_is_false_level = p->if_level;
+ }
+ p->if_level++;
+
+ break;
+ case SSI_ELIF: {
+ const char *expr = NULL;
+ for (i = 2; i < n; i += 2) {
+ if (0 == strcmp(l[i], "expr")) {
+ expr = l[i+1];
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: unknown attribute for ",
+ l[1], l[i]);
+ }
+ }
+
+ if (!expr) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "ssi: ",
+ l[1], "expr missing");
+ break;
+ }
+
+ p->if_level--;
+
+ if (p->if_level == p->if_is_false_level) {
+ if ((p->if_is_false) &&
+ (p->if_is_false_endif == 0)) {
+ switch (ssi_eval_expr(srv, con, p, expr)) {
+ case -1:
+ case 0:
+ p->if_is_false = 1;
+ p->if_is_false_level = p->if_level;
+ break;
+ case 1:
+ p->if_is_false = 0;
+ break;
+ }
+ } else {
+ p->if_is_false = 1;
+ p->if_is_false_level = p->if_level;
+ p->if_is_false_endif = 1;
+ }
+ }
+
+ p->if_level++;
+
+ break;
+ }
+ case SSI_ENDIF:
+ p->if_level--;
+
+ if (p->if_level == p->if_is_false_level) {
+ p->if_is_false = 0;
+ p->if_is_false_endif = 0;
+ }
+
+ break;
+ case SSI_COMMENT:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "ssi: unknown ssi-command:",
+ l[1]);
+ break;
+ }
+
+ return 0;
+
+}
+
+static int mod_ssi_parse_ssi_stmt_value(const char * const s, const int len) {
+ int n;
+ const int c = (s[0] == '"' ? '"' : s[0] == '\'' ? '\'' : 0);
+ if (0 != c) {
+ for (n = 1; n < len; ++n) {
+ if (s[n] == c) return n+1;
+ if (s[n] == '\\') {
+ if (n+1 == len) return 0; /* invalid */
+ ++n;
+ }
+ }
+ return 0; /* invalid */
+ } else {
+ for (n = 0; n < len; ++n) {
+ if (isspace(s[n])) return n;
+ if (s[n] == '\\') {
+ if (n+1 == len) return 0; /* invalid */
+ ++n;
+ }
+ }
+ return n;
+ }
+}
+
+static int mod_ssi_parse_ssi_stmt_offlen(int o[10], const char * const s, const int len) {
+
+ /**
+ * <!--#element attribute=value attribute=value ... -->
+ */
+
+ /* s must begin "<!--#" and must end with "-->" */
+ int n = 5;
+ o[0] = n;
+ for (; light_isalpha(s[n]); ++n) ; /*(n = 5 to begin after "<!--#")*/
+ o[1] = n - o[0];
+ if (0 == o[1]) return -1; /* empty token */
+
+ if (n+3 == len) return 2; /* token only; no params */
+ if (!isspace(s[n])) return -1;
+ do { ++n; } while (isspace(s[n])); /* string ends "-->", so n < len */
+ if (n+3 == len) return 2; /* token only; no params */
+
+ o[2] = n;
+ for (; light_isalpha(s[n]); ++n) ;
+ o[3] = n - o[2];
+ if (0 == o[3] || s[n++] != '=') return -1;
+
+ o[4] = n;
+ o[5] = mod_ssi_parse_ssi_stmt_value(s+n, len-n-3);
+ if (0 == o[5]) return -1; /* empty or invalid token */
+ n += o[5];
+
+ if (n+3 == len) return 6; /* token and one param */
+ if (!isspace(s[n])) return -1;
+ do { ++n; } while (isspace(s[n])); /* string ends "-->", so n < len */
+ if (n+3 == len) return 6; /* token and one param */
+
+ o[6] = n;
+ for (; light_isalpha(s[n]); ++n) ;
+ o[7] = n - o[6];
+ if (0 == o[7] || s[n++] != '=') return -1;
+
+ o[8] = n;
+ o[9] = mod_ssi_parse_ssi_stmt_value(s+n, len-n-3);
+ if (0 == o[9]) return -1; /* empty or invalid token */
+ n += o[9];
+
+ if (n+3 == len) return 10; /* token and two params */
+ if (!isspace(s[n])) return -1;
+ do { ++n; } while (isspace(s[n])); /* string ends "-->", so n < len */
+ if (n+3 == len) return 10; /* token and two params */
+ return -1;
+}
+
+static void mod_ssi_parse_ssi_stmt(server *srv, connection *con, handler_ctx *p, char *s, int len, struct stat *st) {
+
+ /**
+ * <!--#element attribute=value attribute=value ... -->
+ */
+
+ int o[10];
+ int m;
+ const int n = mod_ssi_parse_ssi_stmt_offlen(o, s, len);
+ char *l[6] = { s, NULL, NULL, NULL, NULL, NULL };
+ if (-1 == n) {
+ /* ignore <!--#comment ... --> */
+ if (len >= 16
+ && 0 == memcmp(s+5, "comment", sizeof("comment")-1)
+ && (s[12] == ' ' || s[12] == '\t'))
+ return;
+ /* XXX: perhaps emit error comment instead of invalid <!--#...--> code to client */
+ chunkqueue_append_mem(con->write_queue, s, len); /* append stmt as-is */
+ return;
+ }
+
+ #if 0
+ /* dup s and then modify s */
+ /*(l[0] is no longer used; was previously used in only one place for error reporting)*/
+ l[0] = malloc((size_t)(len+1));
+ memcpy(l[0], s, (size_t)len);
+ (l[0])[len] = '\0';
+ #endif
+
+ /* modify s in-place to split string into arg tokens */
+ for (m = 0; m < n; m += 2) {
+ char *ptr = s+o[m];
+ switch (*ptr) {
+ case '"':
+ case '\'': (++ptr)[o[m+1]-2] = '\0'; break;
+ default: ptr[o[m+1]] = '\0'; break;
+ }
+ l[1+(m>>1)] = ptr;
+ if (m == 4 || m == 8) {
+ /* XXX: removing '\\' escapes from param value would be
+ * the right thing to do, but would potentially change
+ * current behavior, e.g. <!--#exec cmd=... --> */
+ }
+ }
+
+ process_ssi_stmt(srv, con, p, (const char **)l, 1+(n>>1), st);
+
+ #if 0
+ free(l[0]);
+ #endif
+}
+
+static int mod_ssi_stmt_len(const char *s, const int len) {
+ /* s must begin "<!--#" */
+ int n, sq = 0, dq = 0, bs = 0;
+ for (n = 5; n < len; ++n) { /*(n = 5 to begin after "<!--#")*/
+ switch (s[n]) {
+ default:
+ break;
+ case '-':
+ if (!sq && !dq && n+2 < len && s[n+1] == '-' && s[n+2] == '>') return n+3; /* found end of stmt */
+ break;
+ case '"':
+ if (!sq && (!dq || !bs)) dq = !dq;
+ break;
+ case '\'':
+ if (!dq && (!sq || !bs)) sq = !sq;
+ break;
+ case '\\':
+ if (sq || dq) bs = !bs;
+ break;
+ }
+ }
+ return 0; /* incomplete directive "<!--#...-->" */
+}
+
+static void mod_ssi_read_fd(server *srv, connection *con, handler_ctx *p, struct stat *st, int fd) {
+ ssize_t rd;
+ size_t offset, pretag;
+ size_t bufsz = 8192;
+ char *buf = malloc(bufsz); /* allocate to reduce chance of stack exhaustion upon deep recursion */
+ force_assert(buf);
+
+ offset = 0;
+ pretag = 0;
+ while (0 < (rd = read(fd, buf+offset, bufsz-offset))) {
+ char *s;
+ size_t prelen = 0, len;
+ offset += (size_t)rd;
+ for (; (s = memchr(buf+prelen, '<', offset-prelen)); ++prelen) {
+ prelen = s - buf;
+ if (prelen + 5 <= offset) { /*("<!--#" is 5 chars)*/
+ if (0 != memcmp(s+1, CONST_STR_LEN("!--#"))) continue; /* loop to loop for next '<' */
+
+ if (prelen - pretag && !p->if_is_false) {
+ chunkqueue_append_mem(con->write_queue, buf+pretag, prelen-pretag);
+ }
+
+ len = mod_ssi_stmt_len(buf+prelen, offset-prelen);
+ if (len) { /* num of chars to be consumed */
+ mod_ssi_parse_ssi_stmt(srv, con, p, buf+prelen, len, st);
+ prelen += (len - 1); /* offset to '>' at end of SSI directive; incremented at top of loop */
+ pretag = prelen + 1;
+ if (pretag == offset) {
+ offset = pretag = 0;
+ break;
+ }
+ } else if (0 == prelen && offset == bufsz) { /*(full buf)*/
+ /* SSI statement is way too long
+ * NOTE: skipping this buf will expose *the rest* of this SSI statement */
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("<!-- [an error occurred: directive too long] "));
+ /* check if buf ends with "-" or "--" which might be part of "-->"
+ * (buf contains at least 5 chars for "<!--#") */
+ if (buf[offset-2] == '-' && buf[offset-1] == '-') {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("--"));
+ } else if (buf[offset-1] == '-') {
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("-"));
+ }
+ offset = pretag = 0;
+ break;
+ } else { /* incomplete directive "<!--#...-->" */
+ memmove(buf, buf+prelen, (offset -= prelen));
+ pretag = 0;
+ break;
+ }
+ } else if (prelen + 1 == offset || 0 == memcmp(s+1, "!--", offset - prelen - 1)) {
+ if (prelen - pretag && !p->if_is_false) {
+ chunkqueue_append_mem(con->write_queue, buf+pretag, prelen-pretag);
+ }
+ memcpy(buf, buf+prelen, (offset -= prelen));
+ pretag = 0;
+ break;
+ }
+ /* loop to look for next '<' */
+ }
+ if (offset == bufsz) {
+ if (!p->if_is_false) {
+ chunkqueue_append_mem(con->write_queue, buf+pretag, offset-pretag);
+ }
+ offset = pretag = 0;
+ }
+ }
+
+ if (0 != rd) {
+ log_error_write(srv, __FILE__, __LINE__, "SsB", "read(): ", strerror(errno), con->physical.path);
+ }
+
+ if (offset - pretag) {
+ /* copy remaining data in buf */
+ if (!p->if_is_false) {
+ chunkqueue_append_mem(con->write_queue, buf+pretag, offset-pretag);
+ }
+ }
+
+ free(buf);
+}
+
+
+/* don't want to block when open()ing a fifo */
+#if defined(O_NONBLOCK)
+# define FIFO_NONBLOCK O_NONBLOCK
+#else
+# define FIFO_NONBLOCK 0
+#endif
+
+static int mod_ssi_process_file(server *srv, connection *con, handler_ctx *p, struct stat *st) {
+ int fd = open(con->physical.path->ptr, O_RDONLY | FIFO_NONBLOCK);
+ if (-1 == fd) {
+ log_error_write(srv, __FILE__, __LINE__, "SsB", "open(): ",
+ strerror(errno), con->physical.path);
+ return -1;
+ }
+
+ if (0 != fstat(fd, st)) {
+ log_error_write(srv, __FILE__, __LINE__, "SsB", "fstat(): ",
+ strerror(errno), con->physical.path);
+ close(fd);
+ return -1;
+ }
+
+ mod_ssi_read_fd(srv, con, p, st, fd);
+
+ close(fd);
+ return 0;
+}
+
+
+static int mod_ssi_handle_request(server *srv, connection *con, handler_ctx *p) {
+ struct stat st;
+
+ /* get a stream to the file */
+
+ array_reset_data_strings(p->ssi_vars);
+ array_reset_data_strings(p->ssi_cgi_env);
+ buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z"));
+ build_ssi_cgi_vars(srv, con, p);
+
+ /* Reset the modified time of included files */
+ include_file_last_mtime = 0;
+
+ if (mod_ssi_process_file(srv, con, p, &st)) return -1;
+
+ con->file_started = 1;
+ con->file_finished = 1;
+
+ if (buffer_string_is_empty(p->conf.content_type)) {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type));
+ }
+
+ if (p->conf.conditional_requests) {
+ /* Generate "ETag" & "Last-Modified" headers */
+ buffer *mtime = NULL;
+
+ /* use most recently modified include file for ETag and Last-Modified */
+ if (st.st_mtime < include_file_last_mtime)
+ st.st_mtime = include_file_last_mtime;
+
+ etag_create(con->physical.etag, &st, con->etag_flags);
+ etag_mutate(con->physical.etag, con->physical.etag);
+ http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+
+ mtime = strftime_cache_get(srv, st.st_mtime);
+ http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
+ /* ok, the client already has our content,
+ * no need to send it again */
+
+ chunkqueue_reset(con->write_queue);
+ }
+ }
+
+ /* Reset the modified time of included files */
+ include_file_last_mtime = 0;
+
+ /* reset physical.path */
+ buffer_reset(con->physical.path);
+
+ return 0;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(ssi_extension);
+ PATCH(content_type);
+ PATCH(conditional_requests);
+ PATCH(ssi_exec);
+ PATCH(ssi_recursion_max);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
+ PATCH(ssi_extension);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.content-type"))) {
+ PATCH(content_type);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.conditional-requests"))) {
+ PATCH(conditional_requests);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.exec"))) {
+ PATCH(ssi_exec);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.recursion-max"))) {
+ PATCH(ssi_recursion_max);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_ssi_physical_path) {
+ plugin_data *p = p_d;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_ssi_patch_connection(srv, con, p);
+
+ if (array_match_value_suffix(p->conf.ssi_extension, con->physical.path)) {
+ con->plugin_ctx[p->id] = handler_ctx_init(p);
+ con->mode = p->id;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+SUBREQUEST_FUNC(mod_ssi_handle_subrequest) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (con->mode != p->id) return HANDLER_GO_ON; /* not my job */
+ /*
+ * NOTE: if mod_ssi modified to use fdevents, HANDLER_WAIT_FOR_EVENT,
+ * instead of blocking to completion, then hctx->timefmt, hctx->ssi_vars,
+ * and hctx->ssi_cgi_env should be allocated and cleaned up per request.
+ */
+
+ /* handle ssi-request */
+
+ if (mod_ssi_handle_request(srv, con, hctx)) {
+ /* on error */
+ con->http_status = 500;
+ con->mode = DIRECT;
+ }
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_ssi_connection_reset(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (hctx) {
+ handler_ctx_free(hctx);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_ssi_plugin_init(plugin *p);
+int mod_ssi_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("ssi");
+
+ p->init = mod_ssi_init;
+ p->handle_subrequest_start = mod_ssi_physical_path;
+ p->handle_subrequest = mod_ssi_handle_subrequest;
+ p->connection_reset = mod_ssi_connection_reset;
+ p->set_defaults = mod_ssi_set_defaults;
+ p->cleanup = mod_ssi_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi.h b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi.h
new file mode 100644
index 000000000..b4722b29f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi.h
@@ -0,0 +1,53 @@
+#ifndef _MOD_SSI_H_
+#define _MOD_SSI_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+#include "array.h"
+
+#include "plugin.h"
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *ssi_extension;
+ buffer *content_type;
+ unsigned short conditional_requests;
+ unsigned short ssi_exec;
+ unsigned short ssi_recursion_max;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *timefmt;
+
+ buffer *stat_fn;
+
+ array *ssi_vars;
+ array *ssi_cgi_env;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+typedef struct {
+ buffer *timefmt;
+ int sizefmt;
+
+ buffer *stat_fn;
+
+ array *ssi_vars;
+ array *ssi_cgi_env;
+
+ int if_level, if_is_false_level, if_is_false, if_is_false_endif;
+ unsigned short ssi_recursion_depth;
+
+ plugin_config conf;
+} handler_ctx;
+
+int ssi_eval_expr(server *srv, connection *con, handler_ctx *p, const char *expr);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.c b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.c
new file mode 100644
index 000000000..04e388988
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.c
@@ -0,0 +1,330 @@
+#include "first.h"
+
+#include "buffer.h"
+#include "log.h"
+#include "mod_ssi.h"
+#include "mod_ssi_expr.h"
+#include "mod_ssi_exprparser.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ const char *input;
+ size_t offset;
+ size_t size;
+
+ int line_pos;
+
+ int in_key;
+ int in_brace;
+ int in_cond;
+} ssi_tokenizer_t;
+
+ssi_val_t *ssi_val_init(void) {
+ ssi_val_t *s;
+
+ s = calloc(1, sizeof(*s));
+
+ return s;
+}
+
+void ssi_val_free(ssi_val_t *s) {
+ if (s->str) buffer_free(s->str);
+
+ free(s);
+}
+
+int ssi_val_tobool(ssi_val_t *B) {
+ if (B->type == SSI_TYPE_STRING) {
+ return !buffer_string_is_empty(B->str);
+ } else {
+ return B->bo;
+ }
+}
+
+static int ssi_expr_tokenizer(server *srv, connection *con, handler_ctx *p,
+ ssi_tokenizer_t *t, int *token_id, buffer *token) {
+ int tid = 0;
+ size_t i;
+
+ UNUSED(con);
+
+ for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
+ char c = t->input[t->offset];
+ data_string *ds;
+
+ switch (c) {
+ case '=':
+ tid = TK_EQ;
+
+ t->offset++;
+ t->line_pos++;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(=)"));
+
+ break;
+ case '>':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ t->line_pos += 2;
+
+ tid = TK_GE;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(>=)"));
+ } else {
+ t->offset += 1;
+ t->line_pos += 1;
+
+ tid = TK_GT;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(>)"));
+ }
+
+ break;
+ case '<':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ t->line_pos += 2;
+
+ tid = TK_LE;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(<=)"));
+ } else {
+ t->offset += 1;
+ t->line_pos += 1;
+
+ tid = TK_LT;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(<)"));
+ }
+
+ break;
+
+ case '!':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ t->line_pos += 2;
+
+ tid = TK_NE;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(!=)"));
+ } else {
+ t->offset += 1;
+ t->line_pos += 1;
+
+ tid = TK_NOT;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(!)"));
+ }
+
+ break;
+ case '&':
+ if (t->input[t->offset + 1] == '&') {
+ t->offset += 2;
+ t->line_pos += 2;
+
+ tid = TK_AND;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(&&)"));
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
+ "missing second &");
+ return -1;
+ }
+
+ break;
+ case '|':
+ if (t->input[t->offset + 1] == '|') {
+ t->offset += 2;
+ t->line_pos += 2;
+
+ tid = TK_OR;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(||)"));
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
+ "missing second |");
+ return -1;
+ }
+
+ break;
+ case '\t':
+ case ' ':
+ t->offset++;
+ t->line_pos++;
+ break;
+
+ case '\'':
+ /* search for the terminating " */
+ for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
+
+ if (t->input[t->offset + i]) {
+ tid = TK_VALUE;
+
+ buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
+
+ t->offset += i + 1;
+ t->line_pos += i + 1;
+ } else {
+ /* ERROR */
+
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
+ "missing closing quote");
+
+ return -1;
+ }
+
+ break;
+ case '(':
+ t->offset++;
+ t->in_brace++;
+
+ tid = TK_LPARAN;
+
+ buffer_copy_string_len(token, CONST_STR_LEN("("));
+ break;
+ case ')':
+ t->offset++;
+ t->in_brace--;
+
+ tid = TK_RPARAN;
+
+ buffer_copy_string_len(token, CONST_STR_LEN(")"));
+ break;
+ case '$':
+ if (t->input[t->offset + 1] == '{') {
+ for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
+
+ if (t->input[t->offset + i] != '}') {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
+ "missing closing quote");
+
+ return -1;
+ }
+
+ buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
+ } else {
+ for (i = 1; isalpha(t->input[t->offset + i]) ||
+ t->input[t->offset + i] == '_' ||
+ ((i > 1) && isdigit(t->input[t->offset + i])); i++);
+
+ buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
+ }
+
+ tid = TK_VALUE;
+
+ if (NULL != (ds = (data_string *)array_get_element_klen(p->ssi_cgi_env, CONST_BUF_LEN(token)))) {
+ buffer_copy_buffer(token, ds->value);
+ } else if (NULL != (ds = (data_string *)array_get_element_klen(p->ssi_vars, CONST_BUF_LEN(token)))) {
+ buffer_copy_buffer(token, ds->value);
+ } else {
+ buffer_copy_string_len(token, CONST_STR_LEN(""));
+ }
+
+ t->offset += i;
+ t->line_pos += i;
+
+ break;
+ default:
+ for (i = 0; isgraph(t->input[t->offset + i]); i++) {
+ char d = t->input[t->offset + i];
+ switch(d) {
+ case ' ':
+ case '\t':
+ case ')':
+ case '(':
+ case '\'':
+ case '=':
+ case '!':
+ case '<':
+ case '>':
+ case '&':
+ case '|':
+ break;
+ }
+ }
+
+ tid = TK_VALUE;
+
+ buffer_copy_string_len(token, t->input + t->offset, i);
+
+ t->offset += i;
+ t->line_pos += i;
+
+ break;
+ }
+ }
+
+ if (tid) {
+ *token_id = tid;
+
+ return 1;
+ } else if (t->offset < t->size) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
+ "foobar");
+ }
+ return 0;
+}
+
+int ssi_eval_expr(server *srv, connection *con, handler_ctx *p, const char *expr) {
+ ssi_tokenizer_t t;
+ void *pParser;
+ int token_id;
+ buffer *token;
+ ssi_ctx_t context;
+ int ret;
+
+ t.input = expr;
+ t.offset = 0;
+ t.size = strlen(expr);
+ t.line_pos = 1;
+
+ t.in_key = 1;
+ t.in_brace = 0;
+ t.in_cond = 0;
+
+ context.ok = 1;
+ context.srv = srv;
+
+ /* default context */
+
+ pParser = ssiexprparserAlloc( malloc );
+ force_assert(pParser);
+ token = buffer_init();
+ while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
+ ssiexprparser(pParser, token_id, token, &context);
+
+ token = buffer_init();
+ }
+ ssiexprparser(pParser, 0, token, &context);
+ ssiexprparserFree(pParser, free );
+
+ buffer_free(token);
+
+ if (ret == -1) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "expr parser failed");
+ return -1;
+ }
+
+ if (context.ok == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t.line_pos,
+ "parser failed somehow near here");
+ return -1;
+ }
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "expr: ",
+ expr,
+ context.val.bo);
+#endif
+ return context.val.bo;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.h b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.h
new file mode 100644
index 000000000..17cd73ecc
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_expr.h
@@ -0,0 +1,32 @@
+#ifndef _MOD_SSI_EXPR_H_
+#define _MOD_SSI_EXPR_H_
+#include "first.h"
+
+#include "buffer.h"
+
+typedef struct {
+ enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
+
+ buffer *str;
+ int bo;
+} ssi_val_t;
+
+typedef struct {
+ int ok;
+
+ ssi_val_t val;
+
+ void *srv;
+} ssi_ctx_t;
+
+typedef enum { SSI_COND_UNSET, SSI_COND_LE, SSI_COND_GE, SSI_COND_EQ, SSI_COND_NE, SSI_COND_LT, SSI_COND_GT } ssi_expr_cond;
+
+void *ssiexprparserAlloc(void *(*mallocProc)(size_t));
+void ssiexprparserFree(void *p, void (*freeProc)(void*));
+void ssiexprparser(void *yyp, int yymajor, buffer *yyminor, ssi_ctx_t *ctx);
+
+int ssi_val_tobool(ssi_val_t *B);
+ssi_val_t *ssi_val_init(void);
+void ssi_val_free(ssi_val_t *s);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.c b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.c
new file mode 100644
index 000000000..fdf15de03
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.c
@@ -0,0 +1,962 @@
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+*/
+/* First off, code is include which follows the "include" declaration
+** in the input file. */
+#include "first.h"
+#include <stdio.h>
+#line 6 "../../src/mod_ssi_exprparser.y"
+
+#include "first.h"
+#include "mod_ssi_expr.h"
+#include "buffer.h"
+
+#include <string.h>
+
+#line 17 "./mod_ssi_exprparser.c"
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** ssiexprparserTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
+** This is typically a union of many types, one of
+** which is ssiexprparserTOKENTYPE. The entry in the union
+** for base tokens is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** ssiexprparserARG_SDECL A static variable declaration for the %extra_argument
+** ssiexprparserARG_PDECL A parameter declaration for the %extra_argument
+** ssiexprparserARG_STORE Code to store %extra_argument into yypParser
+** ssiexprparserARG_FETCH Code to extract %extra_argument from yypParser
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+*/
+/*  */
+#define YYCODETYPE unsigned char
+#define YYNOCODE 20
+#define YYACTIONTYPE unsigned char
+#define ssiexprparserTOKENTYPE buffer *
+typedef union {
+ ssiexprparserTOKENTYPE yy0;
+ int yy8;
+ buffer * yy19;
+ ssi_val_t * yy29;
+ int yy39;
+} YYMINORTYPE;
+#define YYSTACKDEPTH 100
+#define ssiexprparserARG_SDECL ssi_ctx_t *ctx;
+#define ssiexprparserARG_PDECL ,ssi_ctx_t *ctx
+#define ssiexprparserARG_FETCH ssi_ctx_t *ctx = yypParser->ctx
+#define ssiexprparserARG_STORE yypParser->ctx = ctx
+#define YYNSTATE 23
+#define YYNRULE 16
+#define YYERRORSYMBOL 13
+#define YYERRSYMDT yy39
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+/* Next are that tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
+**
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
+**
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
+**
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+** yy_action[ yy_shift_ofst[S] + X ]
+**
+** If the index value yy_shift_ofst[S]+X is out of range or if the value
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
+** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that yy_default[S] should be used instead.
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+*/
+static YYACTIONTYPE yy_action[] = {
+ /* 0 */ 5, 7, 17, 18, 22, 20, 21, 19, 2, 14,
+ /* 10 */ 1, 23, 40, 9, 11, 3, 16, 2, 14, 12,
+ /* 20 */ 4, 14, 5, 7, 6, 14, 7, 8, 14, 10,
+ /* 30 */ 14, 13, 37, 37, 15,
+};
+static YYCODETYPE yy_lookahead[] = {
+ /* 0 */ 1, 2, 3, 4, 5, 6, 7, 8, 14, 15,
+ /* 10 */ 16, 0, 18, 9, 10, 17, 12, 14, 15, 16,
+ /* 20 */ 14, 15, 1, 2, 14, 15, 2, 14, 15, 14,
+ /* 30 */ 15, 11, 19, 19, 12,
+};
+#define YY_SHIFT_USE_DFLT (-2)
+static signed char yy_shift_ofst[] = {
+ /* 0 */ 4, 11, -1, 4, 21, 4, 24, 4, -2, 4,
+ /* 10 */ -2, 4, 20, -2, 22, -2, -2, -2, -2, -2,
+ /* 20 */ -2, -2, -2,
+};
+#define YY_REDUCE_USE_DFLT (-7)
+static signed char yy_reduce_ofst[] = {
+ /* 0 */ -6, -7, -2, 6, -7, 10, -7, 13, -7, 15,
+ /* 10 */ -7, 3, -7, -7, -7, -7, -7, -7, -7, -7,
+ /* 20 */ -7, -7, -7,
+};
+static YYACTIONTYPE yy_default[] = {
+ /* 0 */ 39, 39, 25, 39, 24, 39, 26, 39, 27, 39,
+ /* 10 */ 28, 39, 39, 29, 30, 32, 31, 33, 34, 35,
+ /* 20 */ 36, 37, 38,
+};
+#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
+
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammer, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+*/
+struct yyStackEntry {
+ int stateno; /* The state-number */
+ int major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ int yyidx; /* Index of top element in stack */
+ int yyerrcnt; /* Shifts left before out of the error */
+ ssiexprparserARG_SDECL /* A place to hold %extra_argument */
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = NULL;
+static char *yyTracePrompt = NULL;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+#if 0
+void ssiexprparserTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *yyTokenName[] = {
+ "$", "AND", "OR", "EQ",
+ "NE", "GT", "GE", "LT",
+ "LE", "NOT", "LPARAN", "RPARAN",
+ "VALUE", "error", "expr", "value",
+ "exprline", "cond", "input",
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *yyRuleName[] = {
+ /* 0 */ "input ::= exprline",
+ /* 1 */ "exprline ::= expr cond expr",
+ /* 2 */ "exprline ::= expr",
+ /* 3 */ "expr ::= expr AND expr",
+ /* 4 */ "expr ::= expr OR expr",
+ /* 5 */ "expr ::= NOT expr",
+ /* 6 */ "expr ::= LPARAN exprline RPARAN",
+ /* 7 */ "expr ::= value",
+ /* 8 */ "value ::= VALUE",
+ /* 9 */ "value ::= value VALUE",
+ /* 10 */ "cond ::= EQ",
+ /* 11 */ "cond ::= NE",
+ /* 12 */ "cond ::= LE",
+ /* 13 */ "cond ::= GE",
+ /* 14 */ "cond ::= LT",
+ /* 15 */ "cond ::= GT",
+};
+#endif /* NDEBUG */
+
+/*
+** This function returns the symbolic name associated with a token
+** value.
+*/
+#if 0
+const char *ssiexprparserTokenName(int tokenType){
+#ifndef NDEBUG
+ if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
+ return yyTokenName[tokenType];
+ }else{
+ return "Unknown";
+ }
+#else
+ return "";
+#endif
+}
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to ssiexprparser and ssiexprparserFree.
+*/
+void *ssiexprparserAlloc(void *(*mallocProc)(size_t)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
+ if( pParser ){
+ pParser->yyidx = -1;
+ }
+ return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are not used
+ ** inside the C code.
+ */
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+#line 22 "../../src/mod_ssi_exprparser.y"
+{ buffer_free((yypminor->yy0)); }
+#line 353 "./mod_ssi_exprparser.c"
+ break;
+ default: break; /* If no destructor action specified: do nothing */
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos;
+
+ if( pParser->yyidx<0 ) return 0;
+ yytos = &pParser->yystack[pParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE && pParser->yyidx>=0 ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yymajor = yytos->major;
+ yy_destructor( yymajor, &yytos->minor);
+ pParser->yyidx--;
+ return yymajor;
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from ssiexprparserAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
+*/
+void ssiexprparserFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+ if( pParser==NULL ) return;
+ while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ int iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+
+ /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
+ i = yy_shift_ofst[stateno];
+ if( i==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ if( iLookAhead==YYNOCODE ){
+ return YY_NO_ACTION;
+ }
+ i += iLookAhead;
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+ int iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
+*/
+static int yy_find_reduce_action(
+ yyParser *pParser, /* The parser */
+ int iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yystack[pParser->yyidx].stateno;
+
+ i = yy_reduce_ofst[stateno];
+ if( i==YY_REDUCE_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ if( iLookAhead==YYNOCODE ){
+ return YY_NO_ACTION;
+ }
+ i += iLookAhead;
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+}
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yyidx++;
+ if( yypParser->yyidx>=YYSTACKDEPTH ){
+ ssiexprparserARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+ ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument var */
+ return;
+ }
+ yytos = &yypParser->yystack[yypParser->yyidx];
+ yytos->stateno = yyNewState;
+ yytos->major = yyMajor;
+ yytos->minor = *yypMinor;
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+ { 18, 1 },
+ { 16, 3 },
+ { 16, 1 },
+ { 14, 3 },
+ { 14, 3 },
+ { 14, 2 },
+ { 14, 3 },
+ { 14, 1 },
+ { 15, 1 },
+ { 15, 2 },
+ { 17, 1 },
+ { 17, 1 },
+ { 17, 1 },
+ { 17, 1 },
+ { 17, 1 },
+ { 17, 1 },
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ ssiexprparserARG_FETCH;
+ yymsp = &yypParser->yystack[yypParser->yyidx];
+#ifndef NDEBUG
+ if( yyTraceFILE ) {
+ if (yyruleno>=0
+ && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
+ } else {
+ return; /*(should not happen)*/
+ }
+ }
+#endif /* NDEBUG */
+
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+ case 0:
+#line 29 "../../src/mod_ssi_exprparser.y"
+{
+ ctx->val.bo = ssi_val_tobool(yymsp[0].minor.yy29);
+ ctx->val.type = SSI_TYPE_BOOL;
+
+ ssi_val_free(yymsp[0].minor.yy29);
+}
+#line 594 "./mod_ssi_exprparser.c"
+ break;
+ case 1:
+#line 36 "../../src/mod_ssi_exprparser.y"
+{
+ int cmp;
+
+ if (yymsp[-2].minor.yy29->type == SSI_TYPE_STRING &&
+ yymsp[0].minor.yy29->type == SSI_TYPE_STRING) {
+ cmp = strcmp(yymsp[-2].minor.yy29->str->ptr, yymsp[0].minor.yy29->str->ptr);
+ } else {
+ cmp = ssi_val_tobool(yymsp[-2].minor.yy29) - ssi_val_tobool(yymsp[0].minor.yy29);
+ }
+
+ yygotominor.yy29 = yymsp[-2].minor.yy29;
+
+ switch(yymsp[-1].minor.yy8) {
+ case SSI_COND_EQ: yygotominor.yy29->bo = (cmp == 0) ? 1 : 0; break;
+ case SSI_COND_NE: yygotominor.yy29->bo = (cmp != 0) ? 1 : 0; break;
+ case SSI_COND_GE: yygotominor.yy29->bo = (cmp >= 0) ? 1 : 0; break;
+ case SSI_COND_GT: yygotominor.yy29->bo = (cmp > 0) ? 1 : 0; break;
+ case SSI_COND_LE: yygotominor.yy29->bo = (cmp <= 0) ? 1 : 0; break;
+ case SSI_COND_LT: yygotominor.yy29->bo = (cmp < 0) ? 1 : 0; break;
+ }
+
+ yygotominor.yy29->type = SSI_TYPE_BOOL;
+
+ ssi_val_free(yymsp[0].minor.yy29);
+}
+#line 623 "./mod_ssi_exprparser.c"
+ break;
+ case 2:
+#line 61 "../../src/mod_ssi_exprparser.y"
+{
+ yygotominor.yy29 = yymsp[0].minor.yy29;
+}
+#line 630 "./mod_ssi_exprparser.c"
+ break;
+ case 3:
+#line 64 "../../src/mod_ssi_exprparser.y"
+{
+ int e;
+
+ e = ssi_val_tobool(yymsp[-2].minor.yy29) && ssi_val_tobool(yymsp[0].minor.yy29);
+
+ yygotominor.yy29 = yymsp[-2].minor.yy29;
+ yygotominor.yy29->bo = e;
+ yygotominor.yy29->type = SSI_TYPE_BOOL;
+ ssi_val_free(yymsp[0].minor.yy29);
+}
+#line 644 "./mod_ssi_exprparser.c"
+ yy_destructor(1,&yymsp[-1].minor);
+ break;
+ case 4:
+#line 75 "../../src/mod_ssi_exprparser.y"
+{
+ int e;
+
+ e = ssi_val_tobool(yymsp[-2].minor.yy29) || ssi_val_tobool(yymsp[0].minor.yy29);
+
+ yygotominor.yy29 = yymsp[-2].minor.yy29;
+ yygotominor.yy29->bo = e;
+ yygotominor.yy29->type = SSI_TYPE_BOOL;
+ ssi_val_free(yymsp[0].minor.yy29);
+}
+#line 659 "./mod_ssi_exprparser.c"
+ yy_destructor(2,&yymsp[-1].minor);
+ break;
+ case 5:
+#line 86 "../../src/mod_ssi_exprparser.y"
+{
+ int e;
+
+ e = !ssi_val_tobool(yymsp[0].minor.yy29);
+
+ yygotominor.yy29 = yymsp[0].minor.yy29;
+ yygotominor.yy29->bo = e;
+ yygotominor.yy29->type = SSI_TYPE_BOOL;
+}
+#line 673 "./mod_ssi_exprparser.c"
+ yy_destructor(9,&yymsp[-1].minor);
+ break;
+ case 6:
+#line 95 "../../src/mod_ssi_exprparser.y"
+{
+ yygotominor.yy29 = yymsp[-1].minor.yy29;
+}
+#line 681 "./mod_ssi_exprparser.c"
+ yy_destructor(10,&yymsp[-2].minor);
+ yy_destructor(11,&yymsp[0].minor);
+ break;
+ case 7:
+#line 99 "../../src/mod_ssi_exprparser.y"
+{
+ yygotominor.yy29 = ssi_val_init();
+ yygotominor.yy29->str = yymsp[0].minor.yy19;
+ yygotominor.yy29->type = SSI_TYPE_STRING;
+}
+#line 692 "./mod_ssi_exprparser.c"
+ break;
+ case 8:
+#line 105 "../../src/mod_ssi_exprparser.y"
+{
+ yygotominor.yy19 = yymsp[0].minor.yy0;
+}
+#line 699 "./mod_ssi_exprparser.c"
+ break;
+ case 9:
+#line 109 "../../src/mod_ssi_exprparser.y"
+{
+ yygotominor.yy19 = yymsp[-1].minor.yy19;
+ buffer_append_string_buffer(yygotominor.yy19, yymsp[0].minor.yy0);
+ buffer_free(yymsp[0].minor.yy0);
+}
+#line 708 "./mod_ssi_exprparser.c"
+ break;
+ case 10:
+#line 115 "../../src/mod_ssi_exprparser.y"
+{ yygotominor.yy8 = SSI_COND_EQ; }
+#line 713 "./mod_ssi_exprparser.c"
+ yy_destructor(3,&yymsp[0].minor);
+ break;
+ case 11:
+#line 116 "../../src/mod_ssi_exprparser.y"
+{ yygotominor.yy8 = SSI_COND_NE; }
+#line 719 "./mod_ssi_exprparser.c"
+ yy_destructor(4,&yymsp[0].minor);
+ break;
+ case 12:
+#line 117 "../../src/mod_ssi_exprparser.y"
+{ yygotominor.yy8 = SSI_COND_LE; }
+#line 725 "./mod_ssi_exprparser.c"
+ yy_destructor(8,&yymsp[0].minor);
+ break;
+ case 13:
+#line 118 "../../src/mod_ssi_exprparser.y"
+{ yygotominor.yy8 = SSI_COND_GE; }
+#line 731 "./mod_ssi_exprparser.c"
+ yy_destructor(6,&yymsp[0].minor);
+ break;
+ case 14:
+#line 119 "../../src/mod_ssi_exprparser.y"
+{ yygotominor.yy8 = SSI_COND_LT; }
+#line 737 "./mod_ssi_exprparser.c"
+ yy_destructor(7,&yymsp[0].minor);
+ break;
+ case 15:
+#line 120 "../../src/mod_ssi_exprparser.y"
+{ yygotominor.yy8 = SSI_COND_GT; }
+#line 743 "./mod_ssi_exprparser.c"
+ yy_destructor(5,&yymsp[0].minor);
+ break;
+ };
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ yypParser->yyidx -= yysize;
+ yyact = yy_find_reduce_action(yypParser,yygoto);
+ if( yyact < YYNSTATE ){
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ ssiexprparserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+#line 14 "../../src/mod_ssi_exprparser.y"
+
+ ctx->ok = 0;
+
+#line 777 "./mod_ssi_exprparser.c"
+ ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
+){
+ ssiexprparserARG_FETCH;
+ UNUSED(yymajor);
+ UNUSED(yyminor);
+#define TOKEN (yyminor.yy0)
+ ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ ssiexprparserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+ ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "ssiexprparserAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void ssiexprparser(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ ssiexprparserTOKENTYPE yyminor /* The value for the token */
+ ssiexprparserARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ int yyact; /* The parser action. */
+ int yyendofinput; /* True if we are at the end of input */
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+ yyParser *yypParser; /* The parser */
+
+ /* (re)initialize the parser, if necessary */
+ yypParser = (yyParser*)yyp;
+ if( yypParser->yyidx<0 ){
+ if( yymajor==0 ) return;
+ yypParser->yyidx = 0;
+ yypParser->yyerrcnt = -1;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+ }
+ yyminorunion.yy0 = yyminor;
+ yyendofinput = (yymajor==0);
+ ssiexprparserARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,yymajor);
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yypParser->yyerrcnt--;
+ if( yyendofinput && yypParser->yyidx>=0 ){
+ yymajor = 0;
+ }else{
+ yymajor = YYNOCODE;
+ }
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
+ }else if( yyact == YY_ERROR_ACTION ){
+ int yymx;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yymx = yypParser->yystack[yypParser->yyidx].major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while(
+ yypParser->yyidx >= 0 &&
+ yymx != YYERRORSYMBOL &&
+ (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yyidx < 0 || yymajor==0 ){
+ yy_destructor(yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ }
+ }
+ yypParser->yyerrcnt = 3;
+ yyerrorhit = 1;
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
+ }
+ yypParser->yyerrcnt = 3;
+ yy_destructor(yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+ }
+ yymajor = YYNOCODE;
+#endif
+ }else{
+ yy_accept(yypParser);
+ yymajor = YYNOCODE;
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ return;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.h b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.h
new file mode 100644
index 000000000..eb55ea5ff
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.h
@@ -0,0 +1,12 @@
+#define TK_AND 1
+#define TK_OR 2
+#define TK_EQ 3
+#define TK_NE 4
+#define TK_GT 5
+#define TK_GE 6
+#define TK_LT 7
+#define TK_LE 8
+#define TK_NOT 9
+#define TK_LPARAN 10
+#define TK_RPARAN 11
+#define TK_VALUE 12
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.y b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.y
new file mode 100644
index 000000000..0b18edc14
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_ssi_exprparser.y
@@ -0,0 +1,120 @@
+%token_prefix TK_
+%token_type {buffer *}
+%extra_argument {ssi_ctx_t *ctx}
+%name ssiexprparser
+
+%include {
+#include "first.h"
+#include "mod_ssi_expr.h"
+#include "buffer.h"
+
+#include <string.h>
+}
+
+%parse_failure {
+ ctx->ok = 0;
+}
+
+%type expr { ssi_val_t * }
+%type value { buffer * }
+%type exprline { ssi_val_t * }
+%type cond { int }
+%token_destructor { buffer_free($$); }
+
+%left AND.
+%left OR.
+%nonassoc EQ NE GT GE LT LE.
+%right NOT.
+
+input ::= exprline(B). {
+ ctx->val.bo = ssi_val_tobool(B);
+ ctx->val.type = SSI_TYPE_BOOL;
+
+ ssi_val_free(B);
+}
+
+exprline(A) ::= expr(B) cond(C) expr(D). {
+ int cmp;
+
+ if (B->type == SSI_TYPE_STRING &&
+ D->type == SSI_TYPE_STRING) {
+ cmp = strcmp(B->str->ptr, D->str->ptr);
+ } else {
+ cmp = ssi_val_tobool(B) - ssi_val_tobool(D);
+ }
+
+ A = B;
+
+ switch(C) {
+ case SSI_COND_EQ: A->bo = (cmp == 0) ? 1 : 0; break;
+ case SSI_COND_NE: A->bo = (cmp != 0) ? 1 : 0; break;
+ case SSI_COND_GE: A->bo = (cmp >= 0) ? 1 : 0; break;
+ case SSI_COND_GT: A->bo = (cmp > 0) ? 1 : 0; break;
+ case SSI_COND_LE: A->bo = (cmp <= 0) ? 1 : 0; break;
+ case SSI_COND_LT: A->bo = (cmp < 0) ? 1 : 0; break;
+ }
+
+ A->type = SSI_TYPE_BOOL;
+
+ ssi_val_free(D);
+}
+exprline(A) ::= expr(B). {
+ A = B;
+}
+expr(A) ::= expr(B) AND expr(C). {
+ int e;
+
+ e = ssi_val_tobool(B) && ssi_val_tobool(C);
+
+ A = B;
+ A->bo = e;
+ A->type = SSI_TYPE_BOOL;
+ ssi_val_free(C);
+}
+
+expr(A) ::= expr(B) OR expr(C). {
+ int e;
+
+ e = ssi_val_tobool(B) || ssi_val_tobool(C);
+
+ A = B;
+ A->bo = e;
+ A->type = SSI_TYPE_BOOL;
+ ssi_val_free(C);
+}
+
+expr(A) ::= NOT expr(B). {
+ int e;
+
+ e = !ssi_val_tobool(B);
+
+ A = B;
+ A->bo = e;
+ A->type = SSI_TYPE_BOOL;
+}
+expr(A) ::= LPARAN exprline(B) RPARAN. {
+ A = B;
+}
+
+expr(A) ::= value(B). {
+ A = ssi_val_init();
+ A->str = B;
+ A->type = SSI_TYPE_STRING;
+}
+
+value(A) ::= VALUE(B). {
+ A = B;
+}
+
+value(A) ::= value(B) VALUE(C). {
+ A = B;
+ buffer_append_string_buffer(A, C);
+ buffer_free(C);
+}
+
+cond(A) ::= EQ. { A = SSI_COND_EQ; }
+cond(A) ::= NE. { A = SSI_COND_NE; }
+cond(A) ::= LE. { A = SSI_COND_LE; }
+cond(A) ::= GE. { A = SSI_COND_GE; }
+cond(A) ::= LT. { A = SSI_COND_LT; }
+cond(A) ::= GT. { A = SSI_COND_GT; }
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_staticfile.c b/data/lighttpd/lighttpd-1.4.53/src/mod_staticfile.c
new file mode 100644
index 000000000..bf783a21f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_staticfile.c
@@ -0,0 +1,221 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "etag.h"
+#include "http_chunk.h"
+#include "response.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * this is a staticfile for a lighttpd plugin
+ *
+ */
+
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *exclude_ext;
+ unsigned short etags_used;
+ unsigned short disable_pathinfo;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_staticfile_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_staticfile_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->exclude_ext);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "static-file.etags", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "static-file.disable-pathinfo", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->exclude_ext = array_init();
+ s->etags_used = 1;
+ s->disable_pathinfo = 0;
+
+ cv[0].destination = s->exclude_ext;
+ cv[1].destination = &(s->etags_used);
+ cv[2].destination = &(s->disable_pathinfo);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->exclude_ext)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for static-file.exclude-extensions; expected list of \"ext\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(exclude_ext);
+ PATCH(etags_used);
+ PATCH(disable_pathinfo);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
+ PATCH(exclude_ext);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.etags"))) {
+ PATCH(etags_used);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.disable-pathinfo"))) {
+ PATCH(disable_pathinfo);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_staticfile_subrequest) {
+ plugin_data *p = p_d;
+
+ /* someone else has done a decision for us */
+ if (con->http_status != 0) return HANDLER_GO_ON;
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ /* someone else has handled this request */
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ /* we only handle GET, POST and HEAD */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_POST:
+ case HTTP_METHOD_HEAD:
+ break;
+ default:
+ return HANDLER_GO_ON;
+ }
+
+ mod_staticfile_patch_connection(srv, con, p);
+
+ if (p->conf.disable_pathinfo && !buffer_string_is_empty(con->request.pathinfo)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, pathinfo forbidden");
+ }
+ return HANDLER_GO_ON;
+ }
+
+ /* ignore certain extensions */
+ if (array_match_value_suffix(p->conf.exclude_ext, con->physical.path)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, extension forbidden");
+ }
+ return HANDLER_GO_ON;
+ }
+
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
+ }
+
+ if (!p->conf.etags_used) con->etag_flags = 0;
+ http_response_send_file(srv, con, con->physical.path);
+
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_staticfile_plugin_init(plugin *p);
+int mod_staticfile_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("staticfile");
+
+ p->init = mod_staticfile_init;
+ p->handle_subrequest_start = mod_staticfile_subrequest;
+ p->set_defaults = mod_staticfile_set_defaults;
+ p->cleanup = mod_staticfile_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_status.c b/data/lighttpd/lighttpd-1.4.53/src/mod_status.c
new file mode 100644
index 000000000..70e3d3a01
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_status.c
@@ -0,0 +1,977 @@
+#include "first.h"
+
+#include "base.h"
+#include "connections.h"
+#include "fdevent.h"
+#include "http_header.h"
+#include "log.h"
+
+#include "plugin.h"
+
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+
+typedef struct {
+ buffer *config_url;
+ buffer *status_url;
+ buffer *statistics_url;
+
+ int sort;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ double traffic_out;
+ double requests;
+
+ double mod_5s_traffic_out[5];
+ double mod_5s_requests[5];
+ size_t mod_5s_ndx;
+
+ double rel_traffic_out;
+ double rel_requests;
+
+ double abs_traffic_out;
+ double abs_requests;
+
+ double bytes_written;
+
+ buffer *module_list;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_status_init) {
+ plugin_data *p;
+ size_t i;
+
+ p = calloc(1, sizeof(*p));
+
+ p->traffic_out = p->requests = 0;
+ p->rel_traffic_out = p->rel_requests = 0;
+ p->abs_traffic_out = p->abs_requests = 0;
+ p->bytes_written = 0;
+ p->module_list = buffer_init();
+
+ for (i = 0; i < 5; i++) {
+ p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
+ }
+
+ return p;
+}
+
+FREE_FUNC(mod_status_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ buffer_free(p->module_list);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+
+ buffer_free(s->status_url);
+ buffer_free(s->statistics_url);
+ buffer_free(s->config_url);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_status_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ config_values_t cv[] = {
+ { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
+ { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->config_url = buffer_init();
+ s->status_url = buffer_init();
+ s->sort = 1;
+ s->statistics_url = buffer_init();
+
+ cv[0].destination = s->status_url;
+ cv[1].destination = s->config_url;
+ cv[2].destination = &(s->sort);
+ cv[3].destination = s->statistics_url;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+
+static int mod_status_row_append(buffer *b, const char *key, const char *value) {
+ buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" <td><b>"));
+ buffer_append_string(b, key);
+ buffer_append_string_len(b, CONST_STR_LEN("</b></td>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" <td>"));
+ buffer_append_string(b, value);
+ buffer_append_string_len(b, CONST_STR_LEN("</td>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n"));
+
+ return 0;
+}
+
+static int mod_status_header_append(buffer *b, const char *key) {
+ buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" <th colspan=\"2\">"));
+ buffer_append_string(b, key);
+ buffer_append_string_len(b, CONST_STR_LEN("</th>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n"));
+
+ return 0;
+}
+
+static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
+ plugin_data *p = p_d;
+
+ if (p->conf.sort) {
+ buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">"));
+ buffer_append_string(b, key);
+ buffer_append_string_len(b, CONST_STR_LEN("<span class=\"sortarrow\">:</span></a></th>\n"));
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\">"));
+ buffer_append_string(b, key);
+ buffer_append_string_len(b, CONST_STR_LEN("</th>\n"));
+ }
+
+ return 0;
+}
+
+static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
+ *multiplier = ' ';
+
+ if (*avg > size) { *avg /= size; *multiplier = 'k'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'M'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'G'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'T'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'P'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'E'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'Z'; }
+ if (*avg > size) { *avg /= size; *multiplier = 'Y'; }
+
+ return 0;
+}
+
+static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *b = chunkqueue_append_buffer_open(con->write_queue);
+ size_t j;
+ double avg;
+ char multiplier = '\0';
+ char buf[32];
+ time_t ts;
+
+ int days, hours, mins, seconds;
+
+ /*(CON_STATE_CLOSE must be last state in enum connection_state_t)*/
+ int cstates[CON_STATE_CLOSE+3];
+ memset(cstates, 0, sizeof(cstates));
+
+ buffer_copy_string_len(b, CONST_STR_LEN(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+ " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
+ " <head>\n"
+ " <title>Status</title>\n"
+
+ " <style type=\"text/css\">\n"
+ " table.status { border: black solid thin; }\n"
+ " td { white-space: nowrap; }\n"
+ " td.int { background-color: #f0f0f0; text-align: right }\n"
+ " td.string { background-color: #f0f0f0; text-align: left }\n"
+ " th.status { background-color: black; color: white; font-weight: bold; }\n"
+ " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
+ " span.sortarrow { color: white; text-decoration: none; }\n"
+ " </style>\n"));
+
+ if (!buffer_string_is_empty(con->uri.query) && 0 == memcmp(con->uri.query->ptr, CONST_STR_LEN("refresh="))) {
+ /* Note: Refresh is an historical, but non-standard HTTP header
+ * References (meta http-equiv="refresh" use is deprecated):
+ * https://www.w3.org/TR/WCAG10-HTML-TECHS/#meta-element
+ * https://www.w3.org/TR/WCAG10-CORE-TECHS/#auto-page-refresh
+ * https://www.w3.org/QA/Tips/reback
+ */
+ const long refresh = strtol(con->uri.query->ptr+sizeof("refresh=")-1, NULL, 10);
+ if (refresh > 0) {
+ buffer_append_string_len(b, CONST_STR_LEN("<meta http-equiv=\"refresh\" content=\""));
+ buffer_append_int(b, refresh < 604800 ? refresh : 604800);
+ buffer_append_string_len(b, CONST_STR_LEN("\">\n"));
+ }
+ }
+
+ if (p->conf.sort) {
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "<script type=\"text/javascript\">\n"
+ "// <!--\n"
+ "var sort_column;\n"
+ "var prev_span = null;\n"
+
+ "function get_inner_text(el) {\n"
+ " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
+ " return el;\n"
+ " if(el.innerText)\n"
+ " return el.innerText;\n"
+ " else {\n"
+ " var str = \"\";\n"
+ " var cs = el.childNodes;\n"
+ " var l = cs.length;\n"
+ " for (i=0;i<l;i++) {\n"
+ " if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n"
+ " else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n"
+ " }\n"
+ " }\n"
+ " return str;\n"
+ "}\n"
+
+ "function sortfn(a,b) {\n"
+ " var at = get_inner_text(a.cells[sort_column]);\n"
+ " var bt = get_inner_text(b.cells[sort_column]);\n"
+ " if (a.cells[sort_column].className == 'int') {\n"
+ " return parseInt(at)-parseInt(bt);\n"
+ " } else {\n"
+ " aa = at.toLowerCase();\n"
+ " bb = bt.toLowerCase();\n"
+ " if (aa==bb) return 0;\n"
+ " else if (aa<bb) return -1;\n"
+ " else return 1;\n"
+ " }\n"
+ "}\n"
+
+ "function resort(lnk) {\n"
+ " var span = lnk.childNodes[1];\n"
+ " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n"
+ " var rows = new Array();\n"
+ " for (j=1;j<table.rows.length;j++)\n"
+ " rows[j-1] = table.rows[j];\n"
+ " sort_column = lnk.parentNode.cellIndex;\n"
+ " rows.sort(sortfn);\n"
+
+ " if (prev_span != null) prev_span.innerHTML = '';\n"
+ " if (span.getAttribute('sortdir')=='down') {\n"
+ " span.innerHTML = '&uarr;';\n"
+ " span.setAttribute('sortdir','up');\n"
+ " rows.reverse();\n"
+ " } else {\n"
+ " span.innerHTML = '&darr;';\n"
+ " span.setAttribute('sortdir','down');\n"
+ " }\n"
+ " for (i=0;i<rows.length;i++)\n"
+ " table.tBodies[0].appendChild(rows[i]);\n"
+ " prev_span = span;\n"
+ "}\n"
+ "// -->\n"
+ "</script>\n"));
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ " </head>\n"
+ " <body>\n"));
+
+
+
+ /* connection listing */
+ buffer_append_string_len(b, CONST_STR_LEN("<h1>Server-Status ("));
+ buffer_append_string_buffer(b, con->conf.server_tag);
+ buffer_append_string_len(b, CONST_STR_LEN(")</h1>"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Hostname</td><td class=\"string\">"));
+ buffer_append_string_buffer(b, con->uri.authority);
+ buffer_append_string_len(b, CONST_STR_LEN(" ("));
+ buffer_append_string_buffer(b, con->server_name);
+ buffer_append_string_len(b, CONST_STR_LEN(")</td></tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Uptime</td><td class=\"string\">"));
+
+ ts = srv->cur_ts - srv->startup_ts;
+
+ days = ts / (60 * 60 * 24);
+ ts %= (60 * 60 * 24);
+
+ hours = ts / (60 * 60);
+ ts %= (60 * 60);
+
+ mins = ts / (60);
+ ts %= (60);
+
+ seconds = ts;
+
+ if (days) {
+ buffer_append_int(b, days);
+ buffer_append_string_len(b, CONST_STR_LEN(" days "));
+ }
+
+ if (hours) {
+ buffer_append_int(b, hours);
+ buffer_append_string_len(b, CONST_STR_LEN(" hours "));
+ }
+
+ if (mins) {
+ buffer_append_int(b, mins);
+ buffer_append_string_len(b, CONST_STR_LEN(" min "));
+ }
+
+ buffer_append_int(b, seconds);
+ buffer_append_string_len(b, CONST_STR_LEN(" s"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Started at</td><td class=\"string\">"));
+
+ ts = srv->startup_ts;
+
+ strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
+ avg = p->abs_requests;
+
+ mod_status_get_multiplier(&avg, &multiplier, 1000);
+
+ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("req</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
+ avg = p->abs_traffic_out;
+
+ mod_status_get_multiplier(&avg, &multiplier, 1024);
+
+ snprintf(buf, sizeof(buf), "%.2f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("byte</td></tr>\n"));
+
+
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (since start)</th></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
+ avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
+
+ mod_status_get_multiplier(&avg, &multiplier, 1000);
+
+ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
+ avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
+
+ mod_status_get_multiplier(&avg, &multiplier, 1024);
+
+ snprintf(buf, sizeof(buf), "%.2f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));
+
+
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"));
+ for (j = 0, avg = 0; j < 5; j++) {
+ avg += p->mod_5s_requests[j];
+ }
+
+ avg /= 5;
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
+
+ mod_status_get_multiplier(&avg, &multiplier, 1000);
+
+ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+
+ buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
+
+ for (j = 0, avg = 0; j < 5; j++) {
+ avg += p->mod_5s_traffic_out[j];
+ }
+
+ avg /= 5;
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
+
+ mod_status_get_multiplier(&avg, &multiplier, 1024);
+
+ snprintf(buf, sizeof(buf), "%.2f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+ if (multiplier) buffer_append_string_len(b, &multiplier, 1);
+ buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</table>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<hr />\n<pre>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<b>"));
+ buffer_append_int(b, srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN(" connections</b>\n"));
+
+ for (j = 0; j < srv->conns->used; j++) {
+ connection *c = srv->conns->ptr[j];
+ const char *state;
+
+ if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri)) {
+ state = "k";
+ ++cstates[CON_STATE_CLOSE+2];
+ } else {
+ state = connection_get_short_state(c->state);
+ ++cstates[(c->state <= CON_STATE_CLOSE ? c->state : CON_STATE_CLOSE+1)];
+ }
+
+ buffer_append_string_len(b, state, 1);
+
+ if (((j + 1) % 50) == 0) {
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("\n\n<table>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td style=\"text-align:right\">"));
+ buffer_append_int(b, cstates[CON_STATE_CLOSE+2]);
+ buffer_append_string_len(b, CONST_STR_LEN("<td>&nbsp;&nbsp;k = keep-alive</td></tr>\n"));
+ for (j = 0; j < CON_STATE_CLOSE+2; ++j) {
+ /*(skip "unknown" state if there are none; there should not be any unknown)*/
+ if (0 == cstates[j] && j == CON_STATE_CLOSE+1) continue;
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td style=\"text-align:right\">"));
+ buffer_append_int(b, cstates[j]);
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td>&nbsp;&nbsp;"));
+ buffer_append_string_len(b, connection_get_short_state(j), 1);
+ buffer_append_string_len(b, CONST_STR_LEN(" = "));
+ buffer_append_string(b, connection_get_state(j));
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("</table>"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("\n</pre><hr />\n<h2>Connections</h2>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr>"));
+ mod_status_header_append_sort(b, p_d, "Client IP");
+ mod_status_header_append_sort(b, p_d, "Read");
+ mod_status_header_append_sort(b, p_d, "Written");
+ mod_status_header_append_sort(b, p_d, "State");
+ mod_status_header_append_sort(b, p_d, "Time");
+ mod_status_header_append_sort(b, p_d, "Host");
+ mod_status_header_append_sort(b, p_d, "URI");
+ mod_status_header_append_sort(b, p_d, "File");
+ buffer_append_string_len(b, CONST_STR_LEN("</tr>\n"));
+
+ for (j = 0; j < srv->conns->used; j++) {
+ connection *c = srv->conns->ptr[j];
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td class=\"string\">"));
+
+ buffer_append_string_buffer(b, c->dst_addr_buf);
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+ if (c->request.content_length) {
+ buffer_append_int(b, c->request_content_queue->bytes_in);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_int(b, c->request.content_length);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("0/0"));
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+ buffer_append_int(b, c->write_queue->bytes_out);
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_int(b, c->write_queue->bytes_out + chunkqueue_length(c->write_queue));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+ if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri)) {
+ buffer_append_string_len(b, CONST_STR_LEN("keep-alive"));
+ } else {
+ buffer_append_string(b, connection_get_state(c->state));
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+ buffer_append_int(b, srv->cur_ts - c->request_start);
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+ if (buffer_string_is_empty(c->server_name)) {
+ buffer_append_string_buffer(b, c->uri.authority);
+ }
+ else {
+ buffer_append_string_buffer(b, c->server_name);
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+ if (!buffer_string_is_empty(c->uri.path)) {
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
+ }
+
+ if (!buffer_string_is_empty(c->uri.query)) {
+ buffer_append_string_len(b, CONST_STR_LEN("?"));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.query), ENCODING_HTML);
+ }
+
+ if (!buffer_string_is_empty(c->request.orig_uri)) {
+ buffer_append_string_len(b, CONST_STR_LEN(" ("));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->request.orig_uri), ENCODING_HTML);
+ buffer_append_string_len(b, CONST_STR_LEN(")"));
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+ buffer_append_string_buffer(b, c->physical.path);
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+ }
+
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "</table>\n"));
+
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ " </body>\n"
+ "</html>\n"
+ ));
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+
+ return 0;
+}
+
+
+static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *b = chunkqueue_append_buffer_open(con->write_queue);
+ double avg;
+ time_t ts;
+ char buf[32];
+ unsigned int k;
+ unsigned int l;
+
+ /* output total number of requests */
+ buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: "));
+ avg = p->abs_requests;
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output total traffic out in kbytes */
+ buffer_append_string_len(b, CONST_STR_LEN("Total kBytes: "));
+ avg = p->abs_traffic_out / 1024;
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output uptime */
+ buffer_append_string_len(b, CONST_STR_LEN("Uptime: "));
+ ts = srv->cur_ts - srv->startup_ts;
+ buffer_append_int(b, ts);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output busy servers */
+ buffer_append_string_len(b, CONST_STR_LEN("BusyServers: "));
+ buffer_append_int(b, srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
+ buffer_append_int(b, srv->conns->size - srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output scoreboard */
+ buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: "));
+ for (k = 0; k < srv->conns->used; k++) {
+ connection *c = srv->conns->ptr[k];
+ const char *state =
+ (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.orig_uri))
+ ? "k"
+ : connection_get_short_state(c->state);
+ buffer_append_string_len(b, state, 1);
+ }
+ for (l = 0; l < srv->conns->size - srv->conns->used; l++) {
+ buffer_append_string_len(b, CONST_STR_LEN("_"));
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ /* set text/plain output */
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
+
+ return 0;
+}
+
+
+static handler_t mod_status_handle_server_status_json(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *b = chunkqueue_append_buffer_open(con->write_queue);
+ double avg;
+ time_t ts;
+ char buf[32];
+ size_t j;
+ unsigned int jsonp = 0;
+
+ if (buffer_string_length(con->uri.query) >= sizeof("jsonp=")-1
+ && 0 == memcmp(con->uri.query->ptr, CONST_STR_LEN("jsonp="))) {
+ /* not a full parse of query string for multiple parameters,
+ * not URL-decoding param and not XML-encoding (XSS protection),
+ * so simply ensure that json function name isalnum() or '_' */
+ const char *f = con->uri.query->ptr + sizeof("jsonp=")-1;
+ int len = 0;
+ while (light_isalnum(f[len]) || f[len] == '_') ++len;
+ if (0 != len && light_isalpha(f[0]) && f[len] == '\0') {
+ buffer_append_string_len(b, f, len);
+ buffer_append_string_len(b, CONST_STR_LEN("("));
+ jsonp = 1;
+ }
+ }
+
+ /* output total number of requests */
+ buffer_append_string_len(b, CONST_STR_LEN("{\n\t\"RequestsTotal\": "));
+ avg = p->abs_requests;
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN(",\n"));
+
+ /* output total traffic out in kbytes */
+ buffer_append_string_len(b, CONST_STR_LEN("\t\"TrafficTotal\": "));
+ avg = p->abs_traffic_out / 1024;
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN(",\n"));
+
+ /* output uptime */
+ buffer_append_string_len(b, CONST_STR_LEN("\t\"Uptime\": "));
+ ts = srv->cur_ts - srv->startup_ts;
+ buffer_append_int(b, ts);
+ buffer_append_string_len(b, CONST_STR_LEN(",\n"));
+
+ /* output busy servers */
+ buffer_append_string_len(b, CONST_STR_LEN("\t\"BusyServers\": "));
+ buffer_append_int(b, srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN(",\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("\t\"IdleServers\": "));
+ buffer_append_int(b, srv->conns->size - srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN(",\n"));
+
+ for (j = 0, avg = 0; j < 5; j++) {
+ avg += p->mod_5s_requests[j];
+ }
+
+ avg /= 5;
+
+ buffer_append_string_len(b, CONST_STR_LEN("\t\"RequestAverage5s\":"));
+ buffer_append_int(b, avg);
+ buffer_append_string_len(b, CONST_STR_LEN(",\n"));
+
+ for (j = 0, avg = 0; j < 5; j++) {
+ avg += p->mod_5s_traffic_out[j];
+ }
+
+ avg /= 5;
+
+ buffer_append_string_len(b, CONST_STR_LEN("\t\"TrafficAverage5s\":"));
+ buffer_append_int(b, avg / 1024); /* kbps */
+ buffer_append_string_len(b, CONST_STR_LEN("\n}"));
+
+ if (jsonp) buffer_append_string_len(b, CONST_STR_LEN(");"));
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ /* set text/plain output */
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/javascript"));
+
+ return 0;
+}
+
+
+static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
+ buffer *b;
+ size_t i;
+ array *st = srv->status;
+ UNUSED(p_d);
+
+ if (0 == st->used) {
+ /* we have nothing to send */
+ con->http_status = 204;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+ b = chunkqueue_append_buffer_open(con->write_queue);
+ for (i = 0; i < st->used; i++) {
+ size_t ndx = st->sorted[i];
+
+ buffer_append_string_buffer(b, st->data[ndx]->key);
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
+ buffer_append_int(b, ((data_integer *)(st->data[ndx]))->value);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
+
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+
+static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
+
+ if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
+ mod_status_handle_server_status_text(srv, con, p_d);
+ } else if (buffer_string_length(con->uri.query) >= sizeof("json")-1
+ && 0 == memcmp(con->uri.query->ptr, CONST_STR_LEN("json"))) {
+ mod_status_handle_server_status_json(srv, con, p_d);
+ } else {
+ mod_status_handle_server_status_html(srv, con, p_d);
+ }
+
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+
+static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *b = chunkqueue_append_buffer_open(con->write_queue);
+ buffer *m = p->module_list;
+ size_t i;
+
+ buffer_copy_string_len(b, CONST_STR_LEN(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+ " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
+ " <head>\n"
+ " <title>Status</title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <h1>"));
+ buffer_append_string_buffer(b, con->conf.server_tag);
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "</h1>\n"
+ " <table summary=\"status\" border=\"1\">\n"));
+
+ mod_status_header_append(b, "Server-Features");
+#ifdef HAVE_PCRE_H
+ mod_status_row_append(b, "RegEx Conditionals", "enabled");
+#else
+ mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
+#endif
+ mod_status_header_append(b, "Network Engine");
+
+ mod_status_row_append(b, "fd-Event-Handler", srv->srvconf.event_handler->ptr);
+
+ mod_status_header_append(b, "Config-File-Settings");
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ plugin **ps = srv->plugins.ptr;
+
+ plugin *pl = ps[i];
+
+ if (i == 0) {
+ buffer_copy_buffer(m, pl->name);
+ } else {
+ buffer_append_string_len(m, CONST_STR_LEN("<br />"));
+ buffer_append_string_buffer(m, pl->name);
+ }
+ }
+
+ mod_status_row_append(b, "Loaded Modules", m->ptr);
+
+ buffer_append_string_len(b, CONST_STR_LEN(" </table>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ " </body>\n"
+ "</html>\n"
+ ));
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(status_url);
+ PATCH(config_url);
+ PATCH(sort);
+ PATCH(statistics_url);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
+ PATCH(status_url);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
+ PATCH(config_url);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
+ PATCH(sort);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
+ PATCH(statistics_url);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ mod_status_patch_connection(srv, con, p);
+
+ if (!buffer_string_is_empty(p->conf.status_url) &&
+ buffer_is_equal(p->conf.status_url, con->uri.path)) {
+ return mod_status_handle_server_status(srv, con, p_d);
+ } else if (!buffer_string_is_empty(p->conf.config_url) &&
+ buffer_is_equal(p->conf.config_url, con->uri.path)) {
+ return mod_status_handle_server_config(srv, con, p_d);
+ } else if (!buffer_string_is_empty(p->conf.statistics_url) &&
+ buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
+ return mod_status_handle_server_statistics(srv, con, p_d);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+TRIGGER_FUNC(mod_status_trigger) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ /* check all connections */
+ for (i = 0; i < srv->conns->used; i++) {
+ connection *c = srv->conns->ptr[i];
+
+ p->bytes_written += c->bytes_written_cur_second;
+ }
+
+ /* a sliding average */
+ p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
+ p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
+
+ p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
+
+ p->abs_traffic_out += p->bytes_written;
+ p->rel_traffic_out += p->bytes_written;
+
+ p->bytes_written = 0;
+
+ /* reset storage - second */
+ p->traffic_out = 0;
+ p->requests = 0;
+
+ return HANDLER_GO_ON;
+}
+
+REQUESTDONE_FUNC(mod_status_account) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ p->requests++;
+ p->rel_requests++;
+ p->abs_requests++;
+
+ p->bytes_written += con->bytes_written_cur_second;
+
+ return HANDLER_GO_ON;
+}
+
+int mod_status_plugin_init(plugin *p);
+int mod_status_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("status");
+
+ p->init = mod_status_init;
+ p->cleanup = mod_status_free;
+ p->set_defaults= mod_status_set_defaults;
+
+ p->handle_uri_clean = mod_status_handler;
+ p->handle_trigger = mod_status_trigger;
+ p->handle_request_done = mod_status_account;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_trigger_b4_dl.c b/data/lighttpd/lighttpd-1.4.53/src/mod_trigger_b4_dl.c
new file mode 100644
index 000000000..6a43b25f8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_trigger_b4_dl.c
@@ -0,0 +1,607 @@
+#include "first.h"
+
+#include "base.h"
+#include "fdevent.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HAVE_GDBM_H)
+# include <gdbm.h>
+#endif
+
+#if defined(HAVE_PCRE_H)
+# include <pcre.h>
+#endif
+
+#if defined(USE_MEMCACHED)
+# include <libmemcached/memcached.h>
+#endif
+
+/**
+ * this is a trigger_b4_dl for a lighttpd plugin
+ *
+ */
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ buffer *db_filename;
+
+ buffer *trigger_url;
+ buffer *download_url;
+ buffer *deny_url;
+
+ array *mc_hosts;
+ buffer *mc_namespace;
+#if defined(HAVE_PCRE_H)
+ pcre *trigger_regex;
+ pcre *download_regex;
+#endif
+#if defined(HAVE_GDBM_H)
+ GDBM_FILE db;
+#endif
+
+#if defined(USE_MEMCACHED)
+ memcached_st *memc;
+#endif
+
+ unsigned short trigger_timeout;
+ unsigned short debug;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_trigger_b4_dl_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_trigger_b4_dl_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->db_filename);
+ buffer_free(s->download_url);
+ buffer_free(s->trigger_url);
+ buffer_free(s->deny_url);
+
+ buffer_free(s->mc_namespace);
+ array_free(s->mc_hosts);
+
+#if defined(HAVE_PCRE_H)
+ if (s->trigger_regex) pcre_free(s->trigger_regex);
+ if (s->download_regex) pcre_free(s->download_regex);
+#endif
+#if defined(HAVE_GDBM_H)
+ if (s->db) gdbm_close(s->db);
+#endif
+#if defined(USE_MEMCACHED)
+ if (s->memc) memcached_free(s->memc);
+#endif
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+
+ config_values_t cv[] = {
+ { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "trigger-before-download.deny-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "trigger-before-download.trigger-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "trigger-before-download.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "trigger-before-download.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+#if defined(HAVE_PCRE_H)
+ const char *errptr;
+ int erroff;
+#endif
+
+ s = calloc(1, sizeof(plugin_config));
+ s->db_filename = buffer_init();
+ s->download_url = buffer_init();
+ s->trigger_url = buffer_init();
+ s->deny_url = buffer_init();
+ s->mc_hosts = array_init();
+ s->mc_namespace = buffer_init();
+
+ cv[0].destination = s->db_filename;
+ cv[1].destination = s->trigger_url;
+ cv[2].destination = s->download_url;
+ cv[3].destination = s->deny_url;
+ cv[4].destination = &(s->trigger_timeout);
+ cv[5].destination = s->mc_hosts;
+ cv[6].destination = s->mc_namespace;
+ cv[7].destination = &(s->debug);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+#if defined(HAVE_GDBM_H)
+ if (!buffer_string_is_empty(s->db_filename)) {
+ if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "gdbm-open failed");
+ return HANDLER_ERROR;
+ }
+ fdevent_setfd_cloexec(gdbm_fdesc(s->db));
+ }
+#endif
+#if defined(HAVE_PCRE_H)
+ if (!buffer_string_is_empty(s->download_url)) {
+ if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
+ 0, &errptr, &erroff, NULL))) {
+
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "compiling regex for download-url failed:",
+ s->download_url, "pos:", erroff);
+ return HANDLER_ERROR;
+ }
+ }
+
+ if (!buffer_string_is_empty(s->trigger_url)) {
+ if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
+ 0, &errptr, &erroff, NULL))) {
+
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "compiling regex for trigger-url failed:",
+ s->trigger_url, "pos:", erroff);
+
+ return HANDLER_ERROR;
+ }
+ }
+#endif
+
+ if (!array_is_vlist(s->mc_hosts)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for trigger-before-download.memcache-hosts; expected list of \"host\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->mc_hosts->used) {
+#if defined(USE_MEMCACHED)
+ buffer *option_string = buffer_init();
+ size_t k;
+
+ {
+ data_string *ds = (data_string *)s->mc_hosts->data[0];
+
+ buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER="));
+ buffer_append_string_buffer(option_string, ds->value);
+ }
+
+ for (k = 1; k < s->mc_hosts->used; k++) {
+ data_string *ds = (data_string *)s->mc_hosts->data[k];
+
+ buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
+ buffer_append_string_buffer(option_string, ds->value);
+ }
+
+ s->memc = memcached(CONST_BUF_LEN(option_string));
+
+ if (NULL == s->memc) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "configuring memcached failed for option string:",
+ option_string);
+ }
+ buffer_free(option_string);
+
+ if (NULL == s->memc) return HANDLER_ERROR;
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
+ return HANDLER_ERROR;
+#endif
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#if defined(HAVE_PCRE_H)
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+#if defined(HAVE_GDBM)
+ PATCH(db);
+#endif
+#if defined(HAVE_PCRE_H)
+ PATCH(download_regex);
+ PATCH(trigger_regex);
+#endif
+ PATCH(trigger_timeout);
+ PATCH(deny_url);
+ PATCH(mc_namespace);
+ PATCH(debug);
+#if defined(USE_MEMCACHED)
+ PATCH(memc);
+#endif
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
+#if defined(HAVE_PCRE_H)
+ PATCH(download_regex);
+#endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
+# if defined(HAVE_PCRE_H)
+ PATCH(trigger_regex);
+# endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
+#if defined(HAVE_GDBM_H)
+ PATCH(db);
+#endif
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
+ PATCH(trigger_timeout);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
+ PATCH(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
+ PATCH(deny_url);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
+ PATCH(mc_namespace);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
+#if defined(USE_MEMCACHED)
+ PATCH(memc);
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+#endif
+
+URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
+#if defined(HAVE_PCRE_H)
+ plugin_data *p = p_d;
+ const char *remote_ip;
+ buffer *vb;
+
+ int n;
+# define N 10
+ int ovec[N * 3];
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_trigger_b4_dl_patch_connection(srv, con, p);
+
+ if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
+
+# if !defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)
+ return HANDLER_GO_ON;
+# elif defined(HAVE_GDBM_H) && defined(USE_MEMCACHED)
+ if (!p->conf.db && !p->conf.memc) return HANDLER_GO_ON;
+ if (p->conf.db && p->conf.memc) {
+ /* can't decide which one */
+
+ return HANDLER_GO_ON;
+ }
+# elif defined(HAVE_GDBM_H)
+ if (!p->conf.db) return HANDLER_GO_ON;
+# else
+ if (!p->conf.memc) return HANDLER_GO_ON;
+# endif
+
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_X_FORWARDED_FOR, CONST_STR_LEN("X-Forwarded-For")))) {
+ /* X-Forwarded-For contains the ip behind the proxy */
+
+ remote_ip = vb->ptr;
+
+ /* memcache can't handle spaces */
+ } else {
+ remote_ip = con->dst_addr_buf->ptr;
+ }
+
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
+ }
+
+ /* check if URL is a trigger -> insert IP into DB */
+ if ((n = pcre_exec(p->conf.trigger_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching:", n);
+
+ return HANDLER_ERROR;
+ }
+ } else {
+# if defined(HAVE_GDBM_H)
+ if (p->conf.db) {
+ /* the trigger matched */
+ datum key, val;
+
+ key.dptr = (char *)remote_ip;
+ key.dsize = strlen(remote_ip);
+
+ val.dptr = (char *)&(srv->cur_ts);
+ val.dsize = sizeof(srv->cur_ts);
+
+ if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "insert failed");
+ }
+ }
+# endif
+# if defined(USE_MEMCACHED)
+ if (p->conf.memc) {
+ size_t i, len;
+ buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
+ buffer_append_string(p->tmp_buf, remote_ip);
+
+ len = buffer_string_length(p->tmp_buf);
+ for (i = 0; i < len; i++) {
+ if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
+ }
+
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
+ }
+
+ if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
+ CONST_BUF_LEN(p->tmp_buf),
+ (const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
+ p->conf.trigger_timeout, 0)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "insert failed");
+ }
+ }
+# endif
+ }
+
+ /* check if URL is a download -> check IP in DB, update timestamp */
+ if ((n = pcre_exec(p->conf.download_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching: ", n);
+ return HANDLER_ERROR;
+ }
+ } else {
+ /* the download uri matched */
+# if defined(HAVE_GDBM_H)
+ if (p->conf.db) {
+ datum key, val;
+ time_t last_hit;
+
+ key.dptr = (char *)remote_ip;
+ key.dsize = strlen(remote_ip);
+
+ val = gdbm_fetch(p->conf.db, key);
+
+ if (val.dptr == NULL) {
+ /* not found, redirect */
+
+ http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
+ con->http_status = 307;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+ memcpy(&last_hit, val.dptr, sizeof(time_t));
+
+ free(val.dptr);
+
+ if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
+ /* found, but timeout, redirect */
+
+ http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
+ con->http_status = 307;
+ con->file_finished = 1;
+
+ if (p->conf.db) {
+ if (0 != gdbm_delete(p->conf.db, key)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "delete failed");
+ }
+ }
+
+ return HANDLER_FINISHED;
+ }
+
+ val.dptr = (char *)&(srv->cur_ts);
+ val.dsize = sizeof(srv->cur_ts);
+
+ if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "insert failed");
+ }
+ }
+# endif
+
+# if defined(USE_MEMCACHED)
+ if (p->conf.memc) {
+ size_t i, len;
+
+ buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
+ buffer_append_string(p->tmp_buf, remote_ip);
+
+ len = buffer_string_length(p->tmp_buf);
+ for (i = 0; i < len; i++) {
+ if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
+ }
+
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
+ }
+
+ /**
+ *
+ * memcached is do expiration for us, as long as we can fetch it every thing is ok
+ * and the timestamp is updated
+ *
+ */
+ if (MEMCACHED_SUCCESS != memcached_exist(p->conf.memc, CONST_BUF_LEN(p->tmp_buf))) {
+ http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
+
+ con->http_status = 307;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+ /* set a new timeout */
+ if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
+ CONST_BUF_LEN(p->tmp_buf),
+ (const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
+ p->conf.trigger_timeout, 0)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "insert failed");
+ }
+ }
+# endif
+ }
+
+#else
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(p_d);
+#endif
+
+ return HANDLER_GO_ON;
+}
+
+#if defined(HAVE_GDBM_H)
+TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ /* check DB each minute */
+ if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
+
+ /* cleanup */
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ datum key, val, okey;
+
+ if (!s->db) continue;
+
+ okey.dptr = NULL;
+
+ /* according to the manual this loop + delete does delete all entries on its way
+ *
+ * we don't care as the next round will remove them. We don't have to perfect here.
+ */
+ for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
+ time_t last_hit;
+ if (okey.dptr) {
+ free(okey.dptr);
+ okey.dptr = NULL;
+ }
+
+ val = gdbm_fetch(s->db, key);
+
+ memcpy(&last_hit, val.dptr, sizeof(time_t));
+
+ free(val.dptr);
+
+ if (srv->cur_ts - last_hit > s->trigger_timeout) {
+ gdbm_delete(s->db, key);
+ }
+
+ okey = key;
+ }
+ if (okey.dptr) free(okey.dptr);
+
+ /* reorg once a day */
+ if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
+ }
+ return HANDLER_GO_ON;
+}
+#endif
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_trigger_b4_dl_plugin_init(plugin *p);
+int mod_trigger_b4_dl_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("trigger_b4_dl");
+
+ p->init = mod_trigger_b4_dl_init;
+ p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
+ p->set_defaults = mod_trigger_b4_dl_set_defaults;
+#if defined(HAVE_GDBM_H)
+ p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
+#endif
+ p->cleanup = mod_trigger_b4_dl_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_uploadprogress.c b/data/lighttpd/lighttpd-1.4.53/src/mod_uploadprogress.c
new file mode 100644
index 000000000..3dbd61e1b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_uploadprogress.c
@@ -0,0 +1,413 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * this is a uploadprogress for a lighttpd plugin
+ *
+ */
+
+typedef struct {
+ buffer *con_id;
+ connection *con;
+} connection_map_entry;
+
+typedef struct {
+ connection_map_entry **ptr;
+
+ size_t used;
+ size_t size;
+} connection_map;
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ buffer *progress_url;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ connection_map *con_map;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/**
+ *
+ * connection maps
+ *
+ */
+
+/* init the plugin data */
+static connection_map *connection_map_init() {
+ connection_map *cm;
+
+ cm = calloc(1, sizeof(*cm));
+
+ return cm;
+}
+
+static void connection_map_free(connection_map *cm) {
+ size_t i;
+ for (i = 0; i < cm->size; i++) {
+ connection_map_entry *cme = cm->ptr[i];
+
+ if (!cme) break;
+
+ if (cme->con_id) {
+ buffer_free(cme->con_id);
+ }
+ free(cme);
+ }
+
+ free(cm);
+}
+
+static int connection_map_insert(connection_map *cm, connection *con, const char *con_id, size_t idlen) {
+ connection_map_entry *cme;
+ size_t i;
+
+ if (cm->size == 0) {
+ cm->size = 16;
+ cm->ptr = malloc(cm->size * sizeof(*(cm->ptr)));
+ for (i = 0; i < cm->size; i++) {
+ cm->ptr[i] = NULL;
+ }
+ } else if (cm->used == cm->size) {
+ cm->size += 16;
+ cm->ptr = realloc(cm->ptr, cm->size * sizeof(*(cm->ptr)));
+ for (i = cm->used; i < cm->size; i++) {
+ cm->ptr[i] = NULL;
+ }
+ }
+
+ if (cm->ptr[cm->used]) {
+ /* is already alloced, just reuse it */
+ cme = cm->ptr[cm->used];
+ } else {
+ cme = malloc(sizeof(*cme));
+ cme->con_id = buffer_init();
+ }
+ buffer_copy_string_len(cme->con_id, con_id, idlen);
+ cme->con = con;
+
+ cm->ptr[cm->used++] = cme;
+
+ return 0;
+}
+
+static connection *connection_map_get_connection(connection_map *cm, const char *con_id, size_t idlen) {
+ size_t i;
+
+ for (i = 0; i < cm->used; i++) {
+ connection_map_entry *cme = cm->ptr[i];
+
+ if (buffer_is_equal_string(cme->con_id, con_id, idlen)) {
+ /* found connection */
+
+ return cme->con;
+ }
+ }
+ return NULL;
+}
+
+static int connection_map_remove_connection(connection_map *cm, connection *con) {
+ size_t i;
+
+ for (i = 0; i < cm->used; i++) {
+ connection_map_entry *cme = cm->ptr[i];
+
+ if (cme->con == con) {
+ /* found connection */
+
+ buffer_clear(cme->con_id);
+ cme->con = NULL;
+
+ cm->used--;
+
+ /* swap positions with the last entry */
+ if (cm->used) {
+ cm->ptr[i] = cm->ptr[cm->used];
+ cm->ptr[cm->used] = cme;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_uploadprogress_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->con_map = connection_map_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_uploadprogress_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 (NULL == s) continue;
+
+ buffer_free(s->progress_url);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ connection_map_free(p->con_map);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "upload-progress.progress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->progress_url = buffer_init();
+
+ cv[0].destination = s->progress_url;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_uploadprogress_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(progress_url);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("upload-progress.progress-url"))) {
+ PATCH(progress_url);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+/**
+ *
+ * the idea:
+ *
+ * for the first request we check if it is a post-request
+ *
+ * if no, move out, don't care about them
+ *
+ * if yes, take the connection structure and register it locally
+ * in the progress-struct together with an session-id (md5 ... )
+ *
+ * if the connections closes, cleanup the entry in the progress-struct
+ *
+ * a second request can now get the info about the size of the upload,
+ * the received bytes
+ *
+ */
+
+URIHANDLER_FUNC(mod_uploadprogress_uri_handler) {
+ plugin_data *p = p_d;
+ size_t len;
+ char *id;
+ buffer *b;
+ connection *post_con = NULL;
+ int pathinfo = 0;
+
+ if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON;
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_POST: break;
+ default: return HANDLER_GO_ON;
+ }
+
+ mod_uploadprogress_patch_connection(srv, con, p);
+ if (buffer_string_is_empty(p->conf.progress_url)) return HANDLER_GO_ON;
+
+ if (con->request.http_method == HTTP_METHOD_GET) {
+ if (!buffer_is_equal(con->uri.path, p->conf.progress_url)) {
+ return HANDLER_GO_ON;
+ }
+ }
+
+ if (NULL != (b = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-Progress-ID")))) {
+ id = b->ptr;
+ } else if (!buffer_string_is_empty(con->uri.query)
+ && (id = strstr(con->uri.query->ptr, "X-Progress-ID="))) {
+ /* perhaps the POST request is using the query-string to pass the X-Progress-ID */
+ id += sizeof("X-Progress-ID=")-1;
+ } else {
+ /*(path-info is not known at this point in request)*/
+ id = con->uri.path->ptr;
+ len = buffer_string_length(con->uri.path);
+ if (len >= 33 && id[len-33] == '/') {
+ id += len - 32;
+ pathinfo = 1;
+ } else {
+ return HANDLER_GO_ON;
+ }
+ }
+
+ /* the request has to contain a 32byte ID */
+ for (len = 0; light_isxdigit(id[len]); ++len) ;
+ if (len != 32) {
+ if (!pathinfo) { /*(reduce false positive noise in error log)*/
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "invalid progress-id; non-xdigit or len != 32:", id);
+ }
+ return HANDLER_GO_ON;
+ }
+
+ /* check if this is a POST request */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_POST:
+
+ connection_map_insert(p->con_map, con, id, len);
+
+ return HANDLER_GO_ON;
+ case HTTP_METHOD_GET:
+ buffer_reset(con->physical.path);
+
+ con->file_started = 1;
+ con->file_finished = 1;
+
+ con->http_status = 200;
+ con->mode = DIRECT;
+
+ /* get the connection */
+ if (NULL == (post_con = connection_map_get_connection(p->con_map, id, len))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "ID not known:", id);
+
+ chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("not in progress"));
+
+ return HANDLER_FINISHED;
+ }
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml"));
+
+ /* just an attempt the force the IE/proxies to NOT cache the request ... doesn't help :( */
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache"));
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT"));
+ http_header_response_set(con, HTTP_HEADER_CACHE_CONTROL, CONST_STR_LEN("Cache-Control"), CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0"));
+
+ /* prepare XML */
+ b = srv->tmp_buf;
+ buffer_copy_string_len(b, CONST_STR_LEN(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"
+ "<upload>"
+ "<size>"));
+ buffer_append_int(b, post_con->request.content_length);
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "</size>"
+ "<received>"));
+ buffer_append_int(b, post_con->request_content_queue->bytes_in);
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "</received>"
+ "</upload>"));
+ chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
+ return HANDLER_FINISHED;
+ default:
+ break;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+REQUESTDONE_FUNC(mod_uploadprogress_request_done) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (con->request.http_method != HTTP_METHOD_POST) return HANDLER_GO_ON;
+ if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ if (connection_map_remove_connection(p->con_map, con)) {
+ /* removed */
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_uploadprogress_plugin_init(plugin *p);
+int mod_uploadprogress_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("uploadprogress");
+
+ p->init = mod_uploadprogress_init;
+ p->handle_uri_clean = mod_uploadprogress_uri_handler;
+ p->connection_reset = mod_uploadprogress_request_done;
+ p->set_defaults = mod_uploadprogress_set_defaults;
+ p->cleanup = mod_uploadprogress_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_userdir.c b/data/lighttpd/lighttpd-1.4.53/src/mod_userdir.c
new file mode 100644
index 000000000..6389d9fab
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_userdir.c
@@ -0,0 +1,349 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "response.h"
+
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+/* plugin config for all request/connections */
+typedef struct {
+ array *exclude_user;
+ array *include_user;
+ buffer *path;
+ buffer *basepath;
+ unsigned short letterhomes;
+ unsigned short active;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *username;
+ buffer *temp_path;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_userdir_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->username = buffer_init();
+ p->temp_path = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_userdir_free) {
+ plugin_data *p = p_d;
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ array_free(s->include_user);
+ array_free(s->exclude_user);
+ buffer_free(s->path);
+ buffer_free(s->basepath);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->username);
+ buffer_free(p->temp_path);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ config_values_t cv[] = {
+ { "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "userdir.letterhomes", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "userdir.active", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->exclude_user = array_init();
+ s->include_user = array_init();
+ s->path = buffer_init();
+ s->basepath = buffer_init();
+ s->letterhomes = 0;
+ /* enabled by default for backward compatibility; if userdir.path isn't set userdir is disabled too,
+ * but you can't disable it by setting it to an empty string. */
+ s->active = 1;
+
+ cv[0].destination = s->path;
+ cv[1].destination = s->exclude_user;
+ cv[2].destination = s->include_user;
+ cv[3].destination = s->basepath;
+ cv[4].destination = &(s->letterhomes);
+ cv[5].destination = &(s->active);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->exclude_user)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for userdir.exclude-user; expected list of \"suffix\"");
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_vlist(s->include_user)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for userdir.include-user; expected list of \"suffix\"");
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(path);
+ PATCH(exclude_user);
+ PATCH(include_user);
+ PATCH(basepath);
+ PATCH(letterhomes);
+ PATCH(active);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
+ PATCH(path);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
+ PATCH(exclude_user);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
+ PATCH(include_user);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
+ PATCH(basepath);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.letterhomes"))) {
+ PATCH(letterhomes);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.active"))) {
+ PATCH(active);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_userdir_docroot_handler) {
+ plugin_data *p = p_d;
+ size_t k;
+ char *rel_url;
+#ifdef HAVE_PWD_H
+ struct passwd *pwd = NULL;
+#endif
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_userdir_patch_connection(srv, con, p);
+
+ /* enforce the userdir.path to be set in the config, ugly fix for #1587;
+ * should be replaced with a clean .enabled option in 1.5
+ */
+ if (!p->conf.active || buffer_is_empty(p->conf.path)) return HANDLER_GO_ON;
+
+ /* /~user/foo.html -> /home/user/public_html/foo.html */
+
+ if (con->uri.path->ptr[0] != '/' ||
+ con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
+
+ if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
+ /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
+ http_response_redirect_to_directory(srv, con);
+
+ return HANDLER_FINISHED;
+ }
+
+ /* /~/ is a empty username, catch it directly */
+ if (0 == rel_url - (con->uri.path->ptr + 2)) {
+ return HANDLER_GO_ON;
+ }
+
+ buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
+
+ if (buffer_string_is_empty(p->conf.basepath)
+#ifdef HAVE_PWD_H
+ && NULL == (pwd = getpwnam(p->username->ptr))
+#endif
+ ) {
+ /* user not found */
+ return HANDLER_GO_ON;
+ }
+
+
+ for (k = 0; k < p->conf.exclude_user->used; k++) {
+ data_string *ds = (data_string *)p->conf.exclude_user->data[k];
+
+ if (buffer_is_equal(ds->value, p->username)) {
+ /* user in exclude list */
+ return HANDLER_GO_ON;
+ }
+ }
+
+ if (p->conf.include_user->used) {
+ int found_user = 0;
+ for (k = 0; k < p->conf.include_user->used; k++) {
+ data_string *ds = (data_string *)p->conf.include_user->data[k];
+
+ if (buffer_is_equal(ds->value, p->username)) {
+ /* user in include list */
+ found_user = 1;
+ break;
+ }
+ }
+
+ if (!found_user) return HANDLER_GO_ON;
+ }
+
+ /* we build the physical path */
+ buffer_clear(p->temp_path);
+
+ if (buffer_string_is_empty(p->conf.basepath)) {
+#ifdef HAVE_PWD_H
+ buffer_copy_string(p->temp_path, pwd->pw_dir);
+#endif
+ } else {
+ char *cp = p->username->ptr;
+ /* check if the username is valid
+ * a request for /~../ should lead to a directory traversal
+ * limiting to [-_a-z0-9.] should fix it */
+ if (cp[0] == '.' && (cp[1] == '\0' || (cp[1] == '.' && cp[2] == '\0'))) {
+ return HANDLER_GO_ON;
+ }
+
+ for (; *cp; cp++) {
+ char c = *cp;
+ if (!(light_isalnum(c) || c == '-' || c == '_' || c == '.')) {
+ return HANDLER_GO_ON;
+ }
+ }
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(p->username);
+ }
+
+ buffer_copy_buffer(p->temp_path, p->conf.basepath);
+ if (p->conf.letterhomes) {
+ if (p->username->ptr[0] == '.') return HANDLER_GO_ON;
+ buffer_append_path_len(p->temp_path, p->username->ptr, 1);
+ }
+ buffer_append_path_len(p->temp_path, CONST_BUF_LEN(p->username));
+ }
+ buffer_append_path_len(p->temp_path, CONST_BUF_LEN(p->conf.path));
+
+ if (buffer_string_is_empty(p->conf.basepath)) {
+ struct stat st;
+ int ret;
+
+ ret = stat(p->temp_path->ptr, &st);
+ if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
+ return HANDLER_GO_ON;
+ }
+ }
+
+ buffer_copy_buffer(con->physical.basedir, p->temp_path);
+
+ /* the physical rel_path is basically the same as uri.path;
+ * but it is converted to lowercase in case of force_lowercase_filenames and some special handling
+ * for trailing '.', ' ' and '/' on windows
+ * we assume that no docroot/physical handler changed this
+ * (docroot should only set the docroot/server name, phyiscal should only change the phyiscal.path;
+ * the exception mod_secdownload doesn't work with userdir anyway)
+ */
+ buffer_append_slash(p->temp_path);
+ /* if no second '/' is found, we assume that it was stripped from the uri.path for the special handling
+ * on windows.
+ * we do not care about the trailing slash here on windows, as we already ensured it is a directory
+ *
+ * TODO: what to do with trailing dots in usernames on windows? they may result in the same directory
+ * as a username without them.
+ */
+ if (NULL != (rel_url = strchr(con->physical.rel_path->ptr + 2, '/'))) {
+ buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
+ }
+ buffer_copy_buffer(con->physical.path, p->temp_path);
+
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_userdir_plugin_init(plugin *p);
+int mod_userdir_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("userdir");
+
+ p->init = mod_userdir_init;
+ p->handle_physical = mod_userdir_docroot_handler;
+ p->set_defaults = mod_userdir_set_defaults;
+ p->cleanup = mod_userdir_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_usertrack.c b/data/lighttpd/lighttpd-1.4.53/src/mod_usertrack.c
new file mode 100644
index 000000000..701bb1e5b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_usertrack.c
@@ -0,0 +1,285 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "rand.h"
+#include "http_header.h"
+
+#include "plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "md5.h"
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ buffer *cookie_name;
+ buffer *cookie_attrs;
+ buffer *cookie_domain;
+ unsigned int cookie_max_age;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_usertrack_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_usertrack_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->cookie_name);
+ buffer_free(s->cookie_attrs);
+ buffer_free(s->cookie_domain);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "usertrack.cookie-max-age", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "usertrack.cookie-attrs", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->cookie_name = buffer_init();
+ s->cookie_attrs = buffer_init();
+ s->cookie_domain = buffer_init();
+ s->cookie_max_age = 0;
+
+ cv[0].destination = s->cookie_name;
+ cv[1].destination = &(s->cookie_max_age);
+ cv[2].destination = s->cookie_domain;
+ cv[3].destination = s->cookie_attrs;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (buffer_string_is_empty(s->cookie_name)) {
+ buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
+ } else {
+ size_t j, len = buffer_string_length(s->cookie_name);
+ for (j = 0; j < len; j++) {
+ char c = s->cookie_name->ptr[j] | 32;
+ if (c < 'a' || c > 'z') {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid character in usertrack.cookie-name:",
+ s->cookie_name);
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ if (!buffer_string_is_empty(s->cookie_domain)) {
+ size_t j, len = buffer_string_length(s->cookie_domain);
+ for (j = 0; j < len; j++) {
+ char c = s->cookie_domain->ptr[j];
+ if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid character in usertrack.cookie-domain:",
+ s->cookie_domain);
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(cookie_name);
+ PATCH(cookie_attrs);
+ PATCH(cookie_domain);
+ PATCH(cookie_max_age);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
+ PATCH(cookie_name);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-attrs"))) {
+ PATCH(cookie_attrs);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
+ PATCH(cookie_max_age);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
+ PATCH(cookie_domain);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_usertrack_uri_handler) {
+ plugin_data *p = p_d;
+ buffer *cookie;
+ buffer *b;
+ unsigned char h[16];
+ li_MD5_CTX Md5Ctx;
+ char hh[LI_ITOSTRING_LENGTH];
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_usertrack_patch_connection(srv, con, p);
+
+ if (NULL != (b = http_header_request_get(con, HTTP_HEADER_COOKIE, CONST_STR_LEN("Cookie")))) {
+ char *g;
+ /* we have a cookie, does it contain a valid name ? */
+
+ /* parse the cookie
+ *
+ * check for cookiename + (WS | '=')
+ *
+ */
+
+ if (NULL != (g = strstr(b->ptr, p->conf.cookie_name->ptr))) {
+ char *nc;
+
+ /* skip WS */
+ for (nc = g + buffer_string_length(p->conf.cookie_name); *nc == ' ' || *nc == '\t'; nc++);
+
+ if (*nc == '=') {
+ /* ok, found the key of our own cookie */
+
+ if (strlen(nc) > 32) {
+ /* i'm lazy */
+ return HANDLER_GO_ON;
+ }
+ }
+ }
+ }
+
+ /* set a cookie */
+ cookie = srv->tmp_buf;
+ buffer_copy_buffer(cookie, p->conf.cookie_name);
+ buffer_append_string_len(cookie, CONST_STR_LEN("="));
+
+
+ /* taken from mod_auth.c */
+
+ /* generate shared-secret */
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(con->uri.path));
+ li_MD5_Update(&Md5Ctx, CONST_STR_LEN("+"));
+
+ li_itostrn(hh, sizeof(hh), srv->cur_ts);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+ li_itostrn(hh, sizeof(hh), li_rand_pseudo());
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+
+ li_MD5_Final(h, &Md5Ctx);
+
+ buffer_append_string_encoded_hex_lc(cookie, (char *)h, 16);
+
+ /* usertrack.cookie-attrs, if set, replaces all other attrs */
+ if (!buffer_string_is_empty(p->conf.cookie_attrs)) {
+ buffer_append_string_buffer(cookie, p->conf.cookie_attrs);
+ http_header_response_insert(con, HTTP_HEADER_SET_COOKIE, CONST_STR_LEN("Set-Cookie"), CONST_BUF_LEN(cookie));
+ return HANDLER_GO_ON;
+ }
+
+ buffer_append_string_len(cookie, CONST_STR_LEN("; Path=/"));
+ buffer_append_string_len(cookie, CONST_STR_LEN("; Version=1"));
+
+ if (!buffer_string_is_empty(p->conf.cookie_domain)) {
+ buffer_append_string_len(cookie, CONST_STR_LEN("; Domain="));
+ buffer_append_string_encoded(cookie, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
+ }
+
+ if (p->conf.cookie_max_age) {
+ buffer_append_string_len(cookie, CONST_STR_LEN("; max-age="));
+ buffer_append_int(cookie, p->conf.cookie_max_age);
+ }
+
+ http_header_response_insert(con, HTTP_HEADER_SET_COOKIE, CONST_STR_LEN("Set-Cookie"), CONST_BUF_LEN(cookie));
+
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_usertrack_plugin_init(plugin *p);
+int mod_usertrack_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("usertrack");
+
+ p->init = mod_usertrack_init;
+ p->handle_uri_clean = mod_usertrack_uri_handler;
+ p->set_defaults = mod_usertrack_set_defaults;
+ p->cleanup = mod_usertrack_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb.c b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb.c
new file mode 100644
index 000000000..ca75183d2
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb.c
@@ -0,0 +1,239 @@
+#include "first.h"
+
+#include "base.h"
+#include "plugin.h"
+#include "http_vhostdb.h"
+#include "log.h"
+#include "stat_cache.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * vhostdb framework
+ */
+
+typedef struct {
+ buffer *vhostdb_backend_conf;
+
+ /* generated */
+ const http_vhostdb_backend_t *vhostdb_backend;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+
+ buffer *tmp_buf;
+} plugin_data;
+
+INIT_FUNC(mod_vhostdb_init) {
+ plugin_data *p = calloc(1, sizeof(*p));
+ p->tmp_buf = buffer_init();
+ return p;
+}
+
+FREE_FUNC(mod_vhostdb_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ buffer_free(s->vhostdb_backend_conf);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p->tmp_buf);
+ free(p);
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_vhostdb_set_defaults) {
+ plugin_data *p = p_d;
+ config_values_t cv[] = {
+ { "vhostdb.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+ s->vhostdb_backend_conf = buffer_init();
+
+ cv[0].destination = s->vhostdb_backend_conf;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->vhostdb_backend_conf)) {
+ s->vhostdb_backend =
+ http_vhostdb_backend_get(s->vhostdb_backend_conf);
+ if (NULL == s->vhostdb_backend) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "vhostdb.backend not supported:",
+ s->vhostdb_backend_conf);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_vhostdb_patch_connection(server *srv, connection *con, plugin_data *p) {
+ plugin_config *s = p->config_storage[0];
+ PATCH(vhostdb_backend);
+
+ /* skip the first, the global context */
+ for (size_t 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 (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("vhostdb.backend"))) {
+ PATCH(vhostdb_backend);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+typedef struct {
+ buffer *server_name;
+ buffer *document_root;
+} vhostdb_entry;
+
+static vhostdb_entry * vhostdb_entry_init (void)
+{
+ vhostdb_entry *ve = calloc(1, sizeof(*ve));
+ ve->server_name = buffer_init();
+ ve->document_root = buffer_init();
+ return ve;
+}
+
+static void vhostdb_entry_free (vhostdb_entry *ve)
+{
+ buffer_free(ve->server_name);
+ buffer_free(ve->document_root);
+ free(ve);
+}
+
+CONNECTION_FUNC(mod_vhostdb_handle_connection_close) {
+ plugin_data *p = p_d;
+ vhostdb_entry *ve;
+
+ if ((ve = con->plugin_ctx[p->id])) {
+ con->plugin_ctx[p->id] = NULL;
+ vhostdb_entry_free(ve);
+ }
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_vhostdb_error_500 (connection *con)
+{
+ con->http_status = 500; /* Internal Server Error */
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_vhostdb_found (connection *con, vhostdb_entry *ve)
+{
+ /* fix virtual server and docroot */
+ buffer_copy_buffer(con->server_name, ve->server_name);
+ buffer_copy_buffer(con->physical.doc_root, ve->document_root);
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_vhostdb_handle_docroot) {
+ plugin_data *p = p_d;
+ vhostdb_entry *ve;
+ const http_vhostdb_backend_t *backend;
+ buffer *b;
+ stat_cache_entry *sce;
+
+ /* no host specified? */
+ if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
+
+ /* XXX: future: implement larger, managed cache
+ * of database responses (positive and negative) */
+
+ /* check if cached this connection */
+ ve = con->plugin_ctx[p->id];
+ if (ve && buffer_is_equal(ve->server_name, con->uri.authority)) {
+ return mod_vhostdb_found(con, ve); /* HANDLER_GO_ON */
+ }
+
+ mod_vhostdb_patch_connection(srv, con, p);
+ if (!p->conf.vhostdb_backend) return HANDLER_GO_ON;
+
+ b = p->tmp_buf;
+ backend = p->conf.vhostdb_backend;
+ if (0 != backend->query(srv, con, backend->p_d, b)) {
+ return mod_vhostdb_error_500(con); /* HANDLER_FINISHED */
+ }
+
+ if (buffer_string_is_empty(b)) {
+ /* no such virtual host */
+ return HANDLER_GO_ON;
+ }
+
+ /* sanity check that really is a directory */
+ buffer_append_slash(b);
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), b);
+ return mod_vhostdb_error_500(con); /* HANDLER_FINISHED */
+ }
+ if (!S_ISDIR(sce->st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", b);
+ return mod_vhostdb_error_500(con); /* HANDLER_FINISHED */
+ }
+
+ /* cache the data */
+ if (!ve) con->plugin_ctx[p->id] = ve = vhostdb_entry_init();
+ buffer_copy_buffer(ve->server_name, con->uri.authority);
+ buffer_copy_buffer(ve->document_root, b);
+
+ return mod_vhostdb_found(con, ve); /* HANDLER_GO_ON */
+}
+
+int mod_vhostdb_plugin_init(plugin *p);
+int mod_vhostdb_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("vhostdb");
+ p->init = mod_vhostdb_init;
+ p->cleanup = mod_vhostdb_free;
+ p->set_defaults = mod_vhostdb_set_defaults;
+ p->handle_docroot = mod_vhostdb_handle_docroot;
+ p->connection_reset = mod_vhostdb_handle_connection_close;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_dbi.c b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_dbi.c
new file mode 100644
index 000000000..0c78e12ab
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_dbi.c
@@ -0,0 +1,331 @@
+#include "first.h"
+
+#include <dbi/dbi.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "base.h"
+#include "http_vhostdb.h"
+#include "fdevent.h"
+#include "log.h"
+#include "plugin.h"
+
+/*
+ * virtual host plugin using DBI for domain to directory lookups
+ *
+ * e.g.
+ * vhostdb.dbi = ( "sql" => "SELECT docroot FROM vhosts WHERE host='?'"
+ * "dbtype" => "sqlite3",
+ * "dbname" => "mydb.sqlite",
+ * "sqlite_dbdir" => "/path/to/sqlite/dbs/" )
+ */
+
+typedef struct {
+ dbi_conn dbconn;
+ dbi_inst dbinst;
+ buffer *sqlquery;
+ server *srv;
+ short reconnect_count;
+} vhostdb_config;
+
+typedef struct {
+ void *vdata;
+ array *options;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+/* used to reconnect to the database when we get disconnected */
+static void mod_vhostdb_dbi_error_callback (dbi_conn dbconn, void *vdata)
+{
+ vhostdb_config *dbconf = (vhostdb_config *)vdata;
+ const char *errormsg = NULL;
+ /*assert(dbconf->dbconn == dbconn);*/
+
+ while (++dbconf->reconnect_count <= 3) { /* retry */
+ if (0 == dbi_conn_connect(dbconn)) {
+ fdevent_setfd_cloexec(dbi_conn_get_socket(dbconn));
+ return;
+ }
+ }
+
+ dbi_conn_error(dbconn, &errormsg);
+ log_error_write(dbconf->srv, __FILE__, __LINE__, "ss",
+ "dbi_conn_connect():", errormsg);
+}
+
+static void mod_vhostdb_dbconf_free (void *vdata)
+{
+ vhostdb_config *dbconf = (vhostdb_config *)vdata;
+ if (!dbconf) return;
+ dbi_conn_close(dbconf->dbconn);
+ dbi_shutdown_r(dbconf->dbinst);
+ free(dbconf);
+}
+
+static int mod_vhostdb_dbconf_setup (server *srv, array *opts, void **vdata)
+{
+ buffer *sqlquery = NULL;
+ const buffer *dbtype=NULL, *dbname=NULL;
+
+ for (size_t i = 0; i < opts->used; ++i) {
+ const data_string *ds = (data_string *)opts->data[i];
+ if (ds->type == TYPE_STRING) {
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("sql"))) {
+ sqlquery = ds->value;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("dbname"))) {
+ dbname = ds->value;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("dbtype"))) {
+ dbtype = ds->value;
+ }
+ }
+ }
+
+ /* required:
+ * - sql (sql query)
+ * - dbtype
+ * - dbname
+ *
+ * optional:
+ * - username, some databases don't require this (sqlite)
+ * - password, default: empty
+ * - socket, default: database type default
+ * - hostname, if set overrides socket
+ * - port, default: database default
+ * - encoding, default: database default
+ */
+
+ if (!buffer_string_is_empty(sqlquery)
+ && !buffer_is_empty(dbname) && !buffer_is_empty(dbtype)) {
+ /* create/initialise database */
+ vhostdb_config *dbconf;
+ dbi_inst dbinst = NULL;
+ dbi_conn dbconn;
+ if (dbi_initialize_r(NULL, &dbinst) < 1) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "dbi_initialize_r() failed. "
+ "Do you have the DBD for this db type installed?");
+ return -1;
+ }
+ dbconn = dbi_conn_new_r(dbtype->ptr, dbinst);
+ if (NULL == dbconn) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "dbi_conn_new_r() failed. "
+ "Do you have the DBD for this db type installed?");
+ dbi_shutdown_r(dbinst);
+ return -1;
+ }
+
+ /* set options */
+ for (size_t j = 0; j < opts->used; ++j) {
+ data_unset *du = opts->data[j];
+ const buffer *opt = du->key;
+ if (!buffer_string_is_empty(opt)) {
+ if (du->type == TYPE_INTEGER) {
+ data_integer *di = (data_integer *)du;
+ dbi_conn_set_option_numeric(dbconn, opt->ptr, di->value);
+ } else if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+ if (ds->value != sqlquery && ds->value != dbtype) {
+ dbi_conn_set_option(dbconn, opt->ptr, ds->value->ptr);
+ }
+ }
+ }
+ }
+
+ dbconf = (vhostdb_config *)calloc(1, sizeof(*dbconf));
+ dbconf->dbinst = dbinst;
+ dbconf->dbconn = dbconn;
+ dbconf->sqlquery = sqlquery;
+ dbconf->srv = srv;
+ dbconf->reconnect_count = 0;
+ *vdata = dbconf;
+
+ /* used to automatically reconnect to the database */
+ dbi_conn_error_handler(dbconn, mod_vhostdb_dbi_error_callback, dbconf);
+
+ /* connect to database */
+ mod_vhostdb_dbi_error_callback(dbconn, dbconf);
+ if (dbconf->reconnect_count >= 3) return -1;
+ }
+
+ return 0;
+}
+
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p);
+
+static int mod_vhostdb_dbi_query(server *srv, connection *con, void *p_d, buffer *docroot)
+{
+ plugin_data *p = (plugin_data *)p_d;
+ vhostdb_config *dbconf;
+ dbi_result result;
+ unsigned long long nrows;
+ int retry_count = 0;
+
+ /*(reuse buffer for sql query before generating docroot result)*/
+ buffer *sqlquery = docroot;
+ buffer_clear(sqlquery); /*(also resets docroot (alias))*/
+
+ mod_vhostdb_patch_connection(srv, con, p);
+ if (NULL == p->conf.vdata) return 0; /*(after resetting docroot)*/
+ dbconf = (vhostdb_config *)p->conf.vdata;
+
+ for (char *b = dbconf->sqlquery->ptr, *d; *b; b = d+1) {
+ if (NULL != (d = strchr(b, '?'))) {
+ /* escape the uri.authority */
+ char *esc = NULL;
+ size_t len = dbi_conn_escape_string_copy(dbconf->dbconn, con->uri.authority->ptr, &esc);
+ buffer_append_string_len(sqlquery, b, (size_t)(d - b));
+ buffer_append_string_len(sqlquery, esc, len);
+ free(esc);
+ if (0 == len) return -1;
+ } else {
+ d = dbconf->sqlquery->ptr + buffer_string_length(dbconf->sqlquery);
+ buffer_append_string_len(sqlquery, b, (size_t)(d - b));
+ break;
+ }
+ }
+
+ /* reset our reconnect-attempt counter, this is a new query. */
+ dbconf->reconnect_count = 0;
+
+ do {
+ result = dbi_conn_query(dbconf->dbconn, sqlquery->ptr);
+ } while (!result && ++retry_count < 2);
+
+ buffer_clear(docroot); /*(reset buffer to store result)*/
+
+ if (!result) {
+ const char *errmsg;
+ dbi_conn_error(dbconf->dbconn, &errmsg);
+ log_error_write(srv, __FILE__, __LINE__, "s", errmsg);
+ return -1;
+ }
+
+ nrows = dbi_result_get_numrows(result);
+ if (nrows && nrows != DBI_ROW_ERROR && dbi_result_next_row(result)) {
+ buffer_copy_string(docroot, dbi_result_get_string_idx(result, 1));
+ } /* else no such virtual host */
+
+ dbi_result_free(result);
+ return 0;
+}
+
+
+
+
+INIT_FUNC(mod_vhostdb_init) {
+ static http_vhostdb_backend_t http_vhostdb_backend_dbi =
+ { "dbi", mod_vhostdb_dbi_query, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_vhostdb_backend_dbi */
+ http_vhostdb_backend_dbi.p_d = p;
+ http_vhostdb_backend_set(&http_vhostdb_backend_dbi);
+
+ return p;
+}
+
+FREE_FUNC(mod_vhostdb_cleanup) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (!s) continue;
+ mod_vhostdb_dbconf_free(s->vdata);
+ array_free(s->options);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_vhostdb_set_defaults) {
+ plugin_data *p = p_d;
+
+ config_values_t cv[] = {
+ { "vhostdb.dbi", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+
+ s->options = array_init();
+ cv[0].destination = s->options;
+
+ p->config_storage[i] = s;
+
+ if (config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvany(s->options)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for vhostdb.dbi; expected list of \"option\" => \"value\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->options->used
+ && 0 != mod_vhostdb_dbconf_setup(srv, s->options, &s->vdata)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p)
+{
+ plugin_config *s = p->config_storage[0];
+ PATCH(vdata);
+
+ /* skip the first, the global context */
+ for (size_t 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 (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("vhostdb.dbi"))) {
+ PATCH(vdata);
+ }
+ }
+ }
+}
+#undef PATCH
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_vhostdb_dbi_plugin_init (plugin *p);
+int mod_vhostdb_dbi_plugin_init (plugin *p)
+{
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("vhostdb_dbi");
+
+ p->init = mod_vhostdb_init;
+ p->cleanup = mod_vhostdb_cleanup;
+ p->set_defaults = mod_vhostdb_set_defaults;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_ldap.c b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_ldap.c
new file mode 100644
index 000000000..e81c4933d
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_ldap.c
@@ -0,0 +1,556 @@
+#include "first.h"
+
+#include <ldap.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "base.h"
+#include "http_vhostdb.h"
+#include "log.h"
+#include "plugin.h"
+
+/*
+ * virtual host plugin using LDAP for domain to directory lookups
+ */
+
+typedef struct {
+ LDAP *ldap;
+ buffer *filter;
+ server *srv;
+
+ const char *attr;
+ const char *host;
+ const char *basedn;
+ const char *binddn;
+ const char *bindpw;
+ const char *cafile;
+ unsigned short starttls;
+} vhostdb_config;
+
+typedef struct {
+ void *vdata;
+ array *options;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static void mod_vhostdb_dbconf_free (void *vdata)
+{
+ vhostdb_config *dbconf = (vhostdb_config *)vdata;
+ if (!dbconf) return;
+ if (NULL != dbconf->ldap) ldap_unbind_ext_s(dbconf->ldap, NULL, NULL);
+ free(dbconf);
+}
+
+/*(copied from mod_authn_ldap.c)*/
+static void mod_vhostdb_dbconf_add_scheme (server *srv, buffer *host)
+{
+ if (!buffer_string_is_empty(host)) {
+ /* reformat hostname(s) as LDAP URIs (scheme://host:port) */
+ static const char *schemes[] = {
+ "ldap://", "ldaps://", "ldapi://", "cldap://"
+ };
+ char *b, *e = host->ptr;
+ buffer_clear(srv->tmp_buf);
+ while (*(b = e)) {
+ unsigned int j;
+ while (*b==' '||*b=='\t'||*b=='\r'||*b=='\n'||*b==',') ++b;
+ if (*b == '\0') break;
+ e = b;
+ while (*e!=' '&&*e!='\t'&&*e!='\r'&&*e!='\n'&&*e!=','&&*e!='\0')
+ ++e;
+ if (!buffer_string_is_empty(srv->tmp_buf))
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(","));
+ for (j = 0; j < sizeof(schemes)/sizeof(char *); ++j) {
+ if (0 == strncasecmp(b, schemes[j], strlen(schemes[j]))) {
+ break;
+ }
+ }
+ if (j == sizeof(schemes)/sizeof(char *))
+ buffer_append_string_len(srv->tmp_buf,
+ CONST_STR_LEN("ldap://"));
+ buffer_append_string_len(srv->tmp_buf, b, (size_t)(e - b));
+ }
+ buffer_copy_buffer(host, srv->tmp_buf);
+ }
+}
+
+static int mod_vhostdb_dbconf_setup (server *srv, array *opts, void **vdata)
+{
+ buffer *filter = NULL;
+ const char *attr = "documentRoot";
+ const char *basedn=NULL,*binddn=NULL,*bindpw=NULL,*host=NULL,*cafile=NULL;
+ unsigned short starttls = 0;
+
+ for (size_t i = 0; i < opts->used; ++i) {
+ const data_string *ds = (data_string *)opts->data[i];
+ if (ds->type == TYPE_STRING) {
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("filter"))) {
+ filter = ds->value;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("attr"))) {
+ if (!buffer_string_is_empty(ds->value)) attr = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("host"))) {
+ mod_vhostdb_dbconf_add_scheme(srv, ds->value);
+ host = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("base-dn"))) {
+ if (!buffer_string_is_empty(ds->value)) basedn = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("bind-dn"))) {
+ if (!buffer_string_is_empty(ds->value)) binddn = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("bind-pw"))) {
+ bindpw = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("ca-file"))) {
+ if (!buffer_string_is_empty(ds->value)) cafile = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("starttls"))) {
+ starttls = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
+ }
+ }
+ }
+
+ /* required:
+ * - host
+ * - filter (LDAP query)
+ * - base-dn
+ *
+ * optional:
+ * - attr (LDAP attribute with docroot; default "documentRoot")
+ * - bind-dn
+ * - bind-pw
+ * - ca-file
+ * - starttls
+ */
+
+ if (!buffer_string_is_empty(filter) && NULL != host && NULL != basedn) {
+ vhostdb_config *dbconf;
+
+ if (NULL == strchr(filter->ptr, '?')) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ldap: filter is missing a replace-operator '?'");
+ return -1;
+ }
+
+ /* openldap sets FD_CLOEXEC on database socket descriptors
+ * (still race between creation of socket and fcntl FD_CLOEXEC)
+ * (YMMV with other LDAP client libraries) */
+
+ dbconf = (vhostdb_config *)calloc(1, sizeof(*dbconf));
+ dbconf->ldap = NULL;
+ dbconf->filter = filter;
+ dbconf->attr = attr;
+ dbconf->host = host;
+ dbconf->basedn = basedn;
+ dbconf->binddn = binddn;
+ dbconf->bindpw = bindpw;
+ dbconf->cafile = cafile;
+ dbconf->starttls = starttls;
+ *vdata = dbconf;
+ }
+ return 0;
+}
+
+/*
+ * Note: a large portion of the LDAP code is copied verbatim from mod_authn_ldap
+ * with only changes being use of vhostdb_config instead of plugin_config struct
+ * and (const char *) strings in vhostdb_config instead of (buffer *).
+ */
+
+static void mod_authn_ldap_err(server *srv, const char *file, unsigned long line, const char *fn, int err)
+{
+ log_error_write(srv,file,line,"sSss","ldap:",fn,":",ldap_err2string(err));
+}
+
+static void mod_authn_ldap_opt_err(server *srv, const char *file, unsigned long line, const char *fn, LDAP *ld)
+{
+ int err;
+ ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
+ mod_authn_ldap_err(srv, file, line, fn, err);
+}
+
+static void mod_authn_append_ldap_filter_escape(buffer * const filter, const buffer * const raw) {
+ /* [RFC4515] 3. String Search Filter Definition
+ *
+ * [...]
+ *
+ * The <valueencoding> rule ensures that the entire filter string is a
+ * valid UTF-8 string and provides that the octets that represent the
+ * ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII
+ * 0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a
+ * backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits
+ * representing the value of the encoded octet.
+ *
+ * [...]
+ *
+ * As indicated by the <valueencoding> rule, implementations MUST escape
+ * all octets greater than 0x7F that are not part of a valid UTF-8
+ * encoding sequence when they generate a string representation of a
+ * search filter. Implementations SHOULD accept as input strings that
+ * are not valid UTF-8 strings. This is necessary because RFC 2254 did
+ * not clearly define the term "string representation" (and in
+ * particular did not mention that the string representation of an LDAP
+ * search filter is a string of UTF-8-encoded Unicode characters).
+ *
+ *
+ * https://www.ldap.com/ldap-filters
+ * Although not required, you may escape any other characters that you want
+ * in the assertion value (or substring component) of a filter. This may be
+ * accomplished by prefixing the hexadecimal representation of each byte of
+ * the UTF-8 encoding of the character to escape with a backslash character.
+ */
+ const char * const b = raw->ptr;
+ const size_t rlen = buffer_string_length(raw);
+ for (size_t i = 0; i < rlen; ++i) {
+ size_t len = i;
+ char *f;
+ do {
+ /* encode all UTF-8 chars with high bit set
+ * (instead of validating UTF-8 and escaping only invalid UTF-8) */
+ if (((unsigned char *)b)[len] > 0x7f)
+ break;
+ switch (b[len]) {
+ default:
+ continue;
+ case '\0': case '(': case ')': case '*': case '\\':
+ break;
+ }
+ break;
+ } while (++len < rlen);
+ len -= i;
+
+ if (len) {
+ buffer_append_string_len(filter, b+i, len);
+ if ((i += len) == rlen) break;
+ }
+
+ /* escape * ( ) \ NUL ('\0') (and all UTF-8 chars with high bit set) */
+ buffer_string_prepare_append(filter, 3);
+ f = filter->ptr + buffer_string_length(filter);
+ f[0] = '\\';
+ f[1] = "0123456789abcdef"[(((unsigned char *)b)[i] >> 4) & 0xf];
+ f[2] = "0123456789abcdef"[(((unsigned char *)b)[i] ) & 0xf];
+ buffer_commit(filter, 3);
+ }
+}
+
+static LDAP * mod_authn_ldap_host_init(server *srv, vhostdb_config *s) {
+ LDAP *ld;
+ int ret;
+
+ ret = ldap_initialize(&ld, s->host);
+ if (LDAP_SUCCESS != ret) {
+ log_error_write(srv, __FILE__, __LINE__, "sss", "ldap:",
+ "ldap_initialize():", strerror(errno));
+ return NULL;
+ }
+
+ ret = LDAP_VERSION3;
+ ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ret);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv, __FILE__, __LINE__, "ldap_set_options()", ret);
+ ldap_destroy(ld);
+ return NULL;
+ }
+
+ if (s->starttls) {
+ /* if no CA file is given, it is ok, as we will use encryption
+ * if the server requires a CAfile it will tell us */
+ if (s->cafile) {
+ ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, s->cafile);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv, __FILE__, __LINE__,
+ "ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE)",
+ ret);
+ ldap_destroy(ld);
+ return NULL;
+ }
+ }
+
+ ret = ldap_start_tls_s(ld, NULL, NULL);
+ if (LDAP_OPT_SUCCESS != ret) {
+ mod_authn_ldap_err(srv,__FILE__,__LINE__,"ldap_start_tls_s()",ret);
+ ldap_destroy(ld);
+ return NULL;
+ }
+ }
+
+ return ld;
+}
+
+static int mod_authn_ldap_bind(server *srv, LDAP *ld, const char *dn, const char *pw) {
+ struct berval creds;
+ int ret;
+
+ if (NULL != pw) {
+ *((const char **)&creds.bv_val) = pw; /*(cast away const)*/
+ creds.bv_len = strlen(pw);
+ } else {
+ creds.bv_val = NULL;
+ creds.bv_len = 0;
+ }
+
+ /* RFE: add functionality: LDAP_SASL_EXTERNAL (or GSS-SPNEGO, etc.) */
+
+ ret = ldap_sasl_bind_s(ld,dn,LDAP_SASL_SIMPLE,&creds,NULL,NULL,NULL);
+ if (ret != LDAP_SUCCESS) {
+ mod_authn_ldap_err(srv, __FILE__, __LINE__, "ldap_sasl_bind_s()", ret);
+ }
+
+ return ret;
+}
+
+static int mod_authn_ldap_rebind_proc (LDAP *ld, LDAP_CONST char *url, ber_tag_t ldap_request, ber_int_t msgid, void *params) {
+ vhostdb_config *s = (vhostdb_config *)params;
+ UNUSED(url);
+ UNUSED(ldap_request);
+ UNUSED(msgid);
+ return mod_authn_ldap_bind(s->srv, ld, s->binddn, s->bindpw);
+}
+
+static LDAPMessage * mod_authn_ldap_search(server *srv, vhostdb_config *s, char *base, char *filter) {
+ LDAPMessage *lm = NULL;
+ char *attrs[] = { LDAP_NO_ATTRS, NULL };
+ int ret;
+
+ /*
+ * 1. connect anonymously (if not already connected)
+ * (ldap connection is kept open unless connection-level error occurs)
+ * 2. issue search using filter
+ */
+
+ if (s->ldap != NULL) {
+ ret = ldap_search_ext_s(s->ldap, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, 0, NULL, NULL, NULL, 0, &lm);
+ if (LDAP_SUCCESS == ret) {
+ return lm;
+ } else if (LDAP_SERVER_DOWN != ret) {
+ /* try again (or initial request);
+ * ldap lib sometimes fails for the first call but reconnects */
+ ret = ldap_search_ext_s(s->ldap, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, 0, NULL, NULL, NULL, 0, &lm);
+ if (LDAP_SUCCESS == ret) {
+ return lm;
+ }
+ }
+
+ ldap_unbind_ext_s(s->ldap, NULL, NULL);
+ }
+
+ s->ldap = mod_authn_ldap_host_init(srv, s);
+ if (NULL == s->ldap) {
+ return NULL;
+ }
+
+ ldap_set_rebind_proc(s->ldap, mod_authn_ldap_rebind_proc, s);
+ ret = mod_authn_ldap_bind(srv, s->ldap, s->binddn, s->bindpw);
+ if (LDAP_SUCCESS != ret) {
+ ldap_destroy(s->ldap);
+ s->ldap = NULL;
+ return NULL;
+ }
+
+ ret = ldap_search_ext_s(s->ldap, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, 0, NULL, NULL, NULL, 0, &lm);
+ if (LDAP_SUCCESS != ret) {
+ log_error_write(srv, __FILE__, __LINE__, "sSss",
+ "ldap:", ldap_err2string(ret), "; filter:", filter);
+ ldap_unbind_ext_s(s->ldap, NULL, NULL);
+ s->ldap = NULL;
+ return NULL;
+ }
+
+ return lm;
+}
+
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p);
+
+static int mod_vhostdb_ldap_query(server *srv, connection *con, void *p_d, buffer *docroot)
+{
+ plugin_data *p = (plugin_data *)p_d;
+ vhostdb_config *dbconf;
+ LDAP *ld;
+ LDAPMessage *lm, *first;
+ struct berval **vals;
+ int count;
+ char *basedn;
+ buffer *template;
+
+ /*(reuse buffer for ldap query before generating docroot result)*/
+ buffer *filter = docroot;
+ buffer_clear(filter); /*(also resets docroot (alias))*/
+
+ mod_vhostdb_patch_connection(srv, con, p);
+ if (NULL == p->conf.vdata) return 0; /*(after resetting docroot)*/
+ dbconf = (vhostdb_config *)p->conf.vdata;
+ dbconf->srv = srv;
+
+ template = dbconf->filter;
+ for (char *b = template->ptr, *d; *b; b = d+1) {
+ if (NULL != (d = strchr(b, '?'))) {
+ buffer_append_string_len(filter, b, (size_t)(d - b));
+ mod_authn_append_ldap_filter_escape(filter, con->uri.authority);
+ } else {
+ d = template->ptr + buffer_string_length(template);
+ buffer_append_string_len(filter, b, (size_t)(d - b));
+ break;
+ }
+ }
+
+ /* (cast away const for poor LDAP ldap_search_ext_s() prototype) */
+ *(const char **)&basedn = dbconf->basedn;
+
+ /* ldap_search (synchronous; blocking) */
+ lm = mod_authn_ldap_search(srv, dbconf, basedn, filter->ptr);
+ if (NULL == lm) {
+ return -1;
+ }
+
+ /*(must be after mod_authn_ldap_search(); might reconnect)*/
+ ld = dbconf->ldap;
+
+ count = ldap_count_entries(ld, lm);
+ if (count > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb",
+ "ldap:", "more than one record returned. "
+ "you might have to refine the filter:", filter);
+ }
+
+ buffer_clear(docroot); /*(reset buffer to store result)*/
+
+ if (0 == count) { /*(no entries found)*/
+ ldap_msgfree(lm);
+ return 0;
+ }
+
+ if (NULL == (first = ldap_first_entry(ld, lm))) {
+ mod_authn_ldap_opt_err(srv,__FILE__,__LINE__,"ldap_first_entry()",ld);
+ ldap_msgfree(lm);
+ return -1;
+ }
+
+ if (NULL != (vals = ldap_get_values_len(ld, first, dbconf->attr))) {
+ buffer_copy_string_len(docroot, vals[0]->bv_val, vals[0]->bv_len);
+ ldap_value_free_len(vals);
+ }
+
+ ldap_msgfree(lm);
+ return 0;
+}
+
+
+
+
+INIT_FUNC(mod_vhostdb_init) {
+ static http_vhostdb_backend_t http_vhostdb_backend_ldap =
+ { "ldap", mod_vhostdb_ldap_query, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_vhostdb_backend_ldap */
+ http_vhostdb_backend_ldap.p_d = p;
+ http_vhostdb_backend_set(&http_vhostdb_backend_ldap);
+
+ return p;
+}
+
+FREE_FUNC(mod_vhostdb_cleanup) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (!s) continue;
+ mod_vhostdb_dbconf_free(s->vdata);
+ array_free(s->options);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_vhostdb_set_defaults) {
+ plugin_data *p = p_d;
+
+ config_values_t cv[] = {
+ { "vhostdb.ldap", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+
+ s->options = array_init();
+ cv[0].destination = s->options;
+
+ p->config_storage[i] = s;
+
+ if (config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->options)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for vhostdb.ldap; expected list of \"option\" => \"value\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->options->used
+ && 0 != mod_vhostdb_dbconf_setup(srv, s->options, &s->vdata)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p)
+{
+ plugin_config *s = p->config_storage[0];
+ PATCH(vdata);
+
+ /* skip the first, the global context */
+ for (size_t 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 (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key,CONST_STR_LEN("vhostdb.ldap"))) {
+ PATCH(vdata);
+ }
+ }
+ }
+}
+#undef PATCH
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_vhostdb_ldap_plugin_init (plugin *p);
+int mod_vhostdb_ldap_plugin_init (plugin *p)
+{
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("vhostdb_ldap");
+
+ p->init = mod_vhostdb_init;
+ p->cleanup = mod_vhostdb_cleanup;
+ p->set_defaults = mod_vhostdb_set_defaults;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_mysql.c b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_mysql.c
new file mode 100644
index 000000000..5905bc81a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_mysql.c
@@ -0,0 +1,295 @@
+#include "first.h"
+
+#include <mysql.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "base.h"
+#include "http_vhostdb.h"
+#include "fdevent.h"
+#include "log.h"
+#include "plugin.h"
+
+/*
+ * virtual host plugin using MySQL for domain to directory lookups
+ */
+
+typedef struct {
+ MYSQL *dbconn;
+ buffer *sqlquery;
+} vhostdb_config;
+
+typedef struct {
+ void *vdata;
+ array *options;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static void mod_vhostdb_dbconf_free (void *vdata)
+{
+ vhostdb_config *dbconf = (vhostdb_config *)vdata;
+ if (!dbconf) return;
+ mysql_close(dbconf->dbconn);
+ free(dbconf);
+}
+
+static int mod_vhostdb_dbconf_setup (server *srv, array *opts, void **vdata)
+{
+ buffer *sqlquery = NULL;
+ const char *dbname=NULL, *user=NULL, *pass=NULL, *host=NULL, *sock=NULL;
+ unsigned int port = 0;
+
+ for (size_t i = 0; i < opts->used; ++i) {
+ const data_string *ds = (data_string *)opts->data[i];
+ if (ds->type == TYPE_STRING && !buffer_string_is_empty(ds->value)) {
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("sql"))) {
+ sqlquery = ds->value;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("dbname"))) {
+ dbname = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("user"))) {
+ user = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("password"))) {
+ pass = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("host"))) {
+ host = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("port"))) {
+ port = strtoul(ds->value->ptr, NULL, 10);
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("sock"))) {
+ sock = ds->value->ptr;
+ }
+ }
+ }
+
+ /* required:
+ * - sql (sql query)
+ * - dbname
+ * - user
+ *
+ * optional:
+ * - password, default: empty
+ * - socket, default: mysql default
+ * - hostname, if set overrides socket
+ * - port, default: 3306
+ */
+
+ if (!buffer_string_is_empty(sqlquery)
+ && dbname && *dbname && user && *user) {
+ vhostdb_config *dbconf;
+ MYSQL *dbconn = mysql_init(NULL);
+ if (NULL == dbconn) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "mysql_init() failed, exiting...");
+ return -1;
+ }
+
+ #if MYSQL_VERSION_ID >= 50013
+ /* in mysql versions above 5.0.3 the reconnect flag is off by default */
+ {
+ char reconnect = 1;
+ mysql_options(dbconn, MYSQL_OPT_RECONNECT, &reconnect);
+ }
+ #endif
+
+ /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
+ #if MYSQL_VERSION_ID < 40100
+ #ifndef CLIENT_MULTI_STATEMENTS
+ #define CLIENT_MULTI_STATEMENTS 0
+ #endif
+ #endif
+ if (!mysql_real_connect(dbconn, host, user, pass, dbname, port, sock,
+ CLIENT_MULTI_STATEMENTS)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ mysql_error(dbconn));
+ mysql_close(dbconn);
+ return -1;
+ }
+
+ fdevent_setfd_cloexec(dbconn->net.fd);
+
+ dbconf = (vhostdb_config *)calloc(1, sizeof(*dbconf));
+ dbconf->dbconn = dbconn;
+ dbconf->sqlquery = sqlquery;
+ *vdata = dbconf;
+ }
+
+ return 0;
+}
+
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p);
+
+static int mod_vhostdb_mysql_query(server *srv, connection *con, void *p_d, buffer *docroot)
+{
+ plugin_data *p = (plugin_data *)p_d;
+ vhostdb_config *dbconf;
+ unsigned cols;
+ MYSQL_ROW row;
+ MYSQL_RES *result;
+
+ /*(reuse buffer for sql query before generating docroot result)*/
+ buffer *sqlquery = docroot;
+ buffer_clear(sqlquery); /*(also resets docroot (alias))*/
+
+ mod_vhostdb_patch_connection(srv, con, p);
+ if (NULL == p->conf.vdata) return 0; /*(after resetting docroot)*/
+ dbconf = (vhostdb_config *)p->conf.vdata;
+
+ for (char *b = dbconf->sqlquery->ptr, *d; *b; b = d+1) {
+ if (NULL != (d = strchr(b, '?'))) {
+ /* escape the uri.authority */
+ unsigned long len;
+ buffer_append_string_len(sqlquery, b, (size_t)(d - b));
+ buffer_string_prepare_append(sqlquery, buffer_string_length(con->uri.authority) * 2);
+ len = mysql_real_escape_string(dbconf->dbconn,
+ sqlquery->ptr + buffer_string_length(sqlquery),
+ CONST_BUF_LEN(con->uri.authority));
+ if ((unsigned long)~0 == len) return -1;
+ buffer_commit(sqlquery, len);
+ } else {
+ d = dbconf->sqlquery->ptr + buffer_string_length(dbconf->sqlquery);
+ buffer_append_string_len(sqlquery, b, (size_t)(d - b));
+ break;
+ }
+ }
+
+ if (mysql_real_query(dbconf->dbconn, CONST_BUF_LEN(sqlquery))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ mysql_error(dbconf->dbconn));
+ buffer_clear(docroot); /*(reset buffer; no result)*/
+ return -1;
+ }
+
+ buffer_clear(docroot); /*(reset buffer to store result)*/
+
+ result = mysql_store_result(dbconf->dbconn);
+ cols = mysql_num_fields(result);
+ row = mysql_fetch_row(result);
+ if (row && cols >= 1) {
+ buffer_copy_string(docroot, row[0]);
+ } /* else no such virtual host */
+
+ mysql_free_result(result);
+ #if MYSQL_VERSION_ID >= 40100
+ while (0 == mysql_next_result(dbconf->dbconn)) ;
+ #endif
+ return 0;
+}
+
+
+
+
+INIT_FUNC(mod_vhostdb_init) {
+ static http_vhostdb_backend_t http_vhostdb_backend_mysql =
+ { "mysql", mod_vhostdb_mysql_query, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_vhostdb_backend_mysql */
+ http_vhostdb_backend_mysql.p_d = p;
+ http_vhostdb_backend_set(&http_vhostdb_backend_mysql);
+
+ return p;
+}
+
+FREE_FUNC(mod_vhostdb_cleanup) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (!s) continue;
+ mod_vhostdb_dbconf_free(s->vdata);
+ array_free(s->options);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_vhostdb_set_defaults) {
+ plugin_data *p = p_d;
+
+ config_values_t cv[] = {
+ { "vhostdb.mysql", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+
+ s->options = array_init();
+ cv[0].destination = s->options;
+
+ p->config_storage[i] = s;
+
+ if (config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->options)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for vhostdb.mysql; expected list of \"option\" => \"value\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->options->used
+ && 0 != mod_vhostdb_dbconf_setup(srv, s->options, &s->vdata)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p)
+{
+ plugin_config *s = p->config_storage[0];
+ PATCH(vdata);
+
+ /* skip the first, the global context */
+ for (size_t 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 (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key,CONST_STR_LEN("vhostdb.mysql"))){
+ PATCH(vdata);
+ }
+ }
+ }
+}
+#undef PATCH
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_vhostdb_mysql_plugin_init (plugin *p);
+int mod_vhostdb_mysql_plugin_init (plugin *p)
+{
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("vhostdb_mysql");
+
+ p->init = mod_vhostdb_init;
+ p->cleanup = mod_vhostdb_cleanup;
+ p->set_defaults = mod_vhostdb_set_defaults;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_pgsql.c b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_pgsql.c
new file mode 100644
index 000000000..a87f43599
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_vhostdb_pgsql.c
@@ -0,0 +1,272 @@
+#include "first.h"
+
+#include <libpq-fe.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "base.h"
+#include "http_vhostdb.h"
+#include "log.h"
+#include "plugin.h"
+
+/*
+ * virtual host plugin using Postgres for domain to directory lookups
+ */
+
+typedef struct {
+ PGconn *dbconn;
+ buffer *sqlquery;
+} vhostdb_config;
+
+typedef struct {
+ void *vdata;
+ array *options;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+static void mod_vhostdb_dbconf_free (void *vdata)
+{
+ vhostdb_config *dbconf = (vhostdb_config *)vdata;
+ if (!dbconf) return;
+ PQfinish(dbconf->dbconn);
+ free(dbconf);
+}
+
+static int mod_vhostdb_dbconf_setup (server *srv, array *opts, void **vdata)
+{
+ buffer *sqlquery = NULL;
+ const char *dbname=NULL, *user=NULL, *pass=NULL, *host=NULL, *port=NULL;
+
+ for (size_t i = 0; i < opts->used; ++i) {
+ const data_string *ds = (data_string *)opts->data[i];
+ if (ds->type == TYPE_STRING) {
+ if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("sql"))) {
+ sqlquery = ds->value;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("dbname"))) {
+ dbname = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("user"))) {
+ user = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("password"))) {
+ pass = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("host"))) {
+ host = ds->value->ptr;
+ } else if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("port"))) {
+ port = ds->value->ptr;
+ }
+ }
+ }
+
+ /* required:
+ * - sql (sql query)
+ * - dbname
+ * - user (unless dbname is a pgsql conninfo URI)
+ *
+ * optional:
+ * - password, default: empty
+ * - hostname
+ * - port, default: 5432
+ */
+
+ if (!buffer_string_is_empty(sqlquery) && NULL != dbname) {
+ vhostdb_config *dbconf;
+ PGconn *dbconn = PQsetdbLogin(host,port,NULL,NULL,dbname,user,pass);
+ if (NULL == dbconn) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "PGsetdbLogin() failed, exiting...");
+ return -1;
+ }
+
+ if (CONNECTION_OK != PQstatus(dbconn)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Failed to login to database, exiting...");
+ PQfinish(dbconn);
+ return -1;
+ }
+
+ /* Postgres sets FD_CLOEXEC on database socket descriptors */
+
+ dbconf = (vhostdb_config *)calloc(1, sizeof(*dbconf));
+ dbconf->dbconn = dbconn;
+ dbconf->sqlquery = sqlquery;
+ *vdata = dbconf;
+ }
+
+ return 0;
+}
+
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p);
+
+static int mod_vhostdb_pgsql_query(server *srv, connection *con, void *p_d, buffer *docroot)
+{
+ plugin_data *p = (plugin_data *)p_d;
+ vhostdb_config *dbconf;
+ PGresult *res;
+ int cols, rows;
+
+ /*(reuse buffer for sql query before generating docroot result)*/
+ buffer *sqlquery = docroot;
+ buffer_clear(sqlquery); /*(also resets docroot (alias))*/
+
+ mod_vhostdb_patch_connection(srv, con, p);
+ if (NULL == p->conf.vdata) return 0; /*(after resetting docroot)*/
+ dbconf = (vhostdb_config *)p->conf.vdata;
+
+ for (char *b = dbconf->sqlquery->ptr, *d; *b; b = d+1) {
+ if (NULL != (d = strchr(b, '?'))) {
+ /* escape the uri.authority */
+ size_t len;
+ int err;
+ buffer_append_string_len(sqlquery, b, (size_t)(d - b));
+ buffer_string_prepare_append(sqlquery, buffer_string_length(con->uri.authority) * 2);
+ len = PQescapeStringConn(dbconf->dbconn,
+ sqlquery->ptr + buffer_string_length(sqlquery),
+ CONST_BUF_LEN(con->uri.authority), &err);
+ buffer_commit(sqlquery, len);
+ if (0 != err) return -1;
+ } else {
+ d = dbconf->sqlquery->ptr + buffer_string_length(dbconf->sqlquery);
+ buffer_append_string_len(sqlquery, b, (size_t)(d - b));
+ break;
+ }
+ }
+
+ res = PQexec(dbconf->dbconn, sqlquery->ptr);
+
+ buffer_clear(docroot); /*(reset buffer to store result)*/
+
+ if (PGRES_TUPLES_OK != PQresultStatus(res)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ PQerrorMessage(dbconf->dbconn));
+ PQclear(res);
+ return -1;
+ }
+
+ cols = PQnfields(res);
+ rows = PQntuples(res);
+ if (rows == 1 && cols >= 1) {
+ buffer_copy_string(docroot, PQgetvalue(res, 0, 0));
+ } /* else no such virtual host */
+
+ PQclear(res);
+ return 0;
+}
+
+
+
+
+INIT_FUNC(mod_vhostdb_init) {
+ static http_vhostdb_backend_t http_vhostdb_backend_pgsql =
+ { "pgsql", mod_vhostdb_pgsql_query, NULL };
+ plugin_data *p = calloc(1, sizeof(*p));
+
+ /* register http_vhostdb_backend_pgsql */
+ http_vhostdb_backend_pgsql.p_d = p;
+ http_vhostdb_backend_set(&http_vhostdb_backend_pgsql);
+
+ return p;
+}
+
+FREE_FUNC(mod_vhostdb_cleanup) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+ if (!s) continue;
+ mod_vhostdb_dbconf_free(s->vdata);
+ array_free(s->options);
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ free(p);
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_vhostdb_set_defaults) {
+ plugin_data *p = p_d;
+
+ config_values_t cv[] = {
+ { "vhostdb.pgsql", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ data_config const *config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+
+ s->options = array_init();
+ cv[0].destination = s->options;
+
+ p->config_storage[i] = s;
+
+ if (config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!array_is_kvstring(s->options)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for vhostdb.pgsql; expected list of \"option\" => \"value\"");
+ return HANDLER_ERROR;
+ }
+
+ if (s->options->used
+ && 0 != mod_vhostdb_dbconf_setup(srv, s->options, &s->vdata)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static void mod_vhostdb_patch_connection (server *srv, connection *con, plugin_data *p)
+{
+ plugin_config *s = p->config_storage[0];
+ PATCH(vdata);
+
+ /* skip the first, the global context */
+ for (size_t 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 (size_t j = 0; j < dc->value->used; ++j) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key,CONST_STR_LEN("vhostdb.pgsql"))){
+ PATCH(vdata);
+ }
+ }
+ }
+}
+#undef PATCH
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_vhostdb_pgsql_plugin_init (plugin *p);
+int mod_vhostdb_pgsql_plugin_init (plugin *p)
+{
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("vhostdb_pgsql");
+
+ p->init = mod_vhostdb_init;
+ p->cleanup = mod_vhostdb_cleanup;
+ p->set_defaults = mod_vhostdb_set_defaults;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_webdav.c b/data/lighttpd/lighttpd-1.4.53/src/mod_webdav.c
new file mode 100644
index 000000000..67153e3c4
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_webdav.c
@@ -0,0 +1,2820 @@
+#include "first.h"
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "fdevent.h"
+#include "http_header.h"
+#include "response.h"
+#include "connections.h"
+
+#include "plugin.h"
+
+#include "stat_cache.h"
+
+#include "sys-mmap.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+#include <dirent.h>
+
+#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H)
+#define USE_PROPPATCH
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+#include <sqlite3.h>
+#endif
+
+#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) \
+ && defined(HAVE_UUID) && defined(HAVE_UUID_UUID_H)
+#define USE_LOCKS
+#include <uuid/uuid.h>
+#endif
+
+/**
+ * this is a webdav for a lighttpd plugin
+ *
+ * at least a very basic one.
+ * - for now it is read-only and we only support PROPFIND
+ *
+ */
+
+#define WEBDAV_FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
+#define WEBDAV_DIR_MODE S_IRWXU | S_IRWXG | S_IRWXO
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ unsigned short enabled;
+ unsigned short is_readonly;
+ unsigned short log_xml;
+
+ buffer *sqlite_db_name;
+#ifdef USE_PROPPATCH
+ sqlite3 *sql;
+ sqlite3_stmt *stmt_update_prop;
+ sqlite3_stmt *stmt_delete_prop;
+ sqlite3_stmt *stmt_select_prop;
+ sqlite3_stmt *stmt_select_propnames;
+
+ sqlite3_stmt *stmt_delete_uri;
+ sqlite3_stmt *stmt_move_uri;
+ sqlite3_stmt *stmt_copy_uri;
+
+ sqlite3_stmt *stmt_remove_lock;
+ sqlite3_stmt *stmt_create_lock;
+ sqlite3_stmt *stmt_read_lock;
+ sqlite3_stmt *stmt_read_lock_by_uri;
+ sqlite3_stmt *stmt_refresh_lock;
+#endif
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+ request_uri uri;
+ physical physical;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+typedef struct {
+ plugin_config conf;
+} handler_ctx;
+
+/* init the plugin data */
+INIT_FUNC(mod_webdav_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ p->uri.scheme = buffer_init();
+ p->uri.path = buffer_init();
+ p->uri.authority = buffer_init();
+
+ p->physical.path = buffer_init();
+ p->physical.rel_path = buffer_init();
+ p->physical.doc_root = buffer_init();
+ p->physical.basedir = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_webdav_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (NULL == s) continue;
+
+ buffer_free(s->sqlite_db_name);
+#ifdef USE_PROPPATCH
+ if (s->sql) {
+ sqlite3_finalize(s->stmt_delete_prop);
+ sqlite3_finalize(s->stmt_delete_uri);
+ sqlite3_finalize(s->stmt_copy_uri);
+ sqlite3_finalize(s->stmt_move_uri);
+ sqlite3_finalize(s->stmt_update_prop);
+ sqlite3_finalize(s->stmt_select_prop);
+ sqlite3_finalize(s->stmt_select_propnames);
+
+ sqlite3_finalize(s->stmt_read_lock);
+ sqlite3_finalize(s->stmt_read_lock_by_uri);
+ sqlite3_finalize(s->stmt_create_lock);
+ sqlite3_finalize(s->stmt_remove_lock);
+ sqlite3_finalize(s->stmt_refresh_lock);
+ sqlite3_close(s->sql);
+ }
+#endif
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->uri.scheme);
+ buffer_free(p->uri.path);
+ buffer_free(p->uri.authority);
+
+ buffer_free(p->physical.path);
+ buffer_free(p->physical.rel_path);
+ buffer_free(p->physical.doc_root);
+ buffer_free(p->physical.basedir);
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "webdav.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "webdav.is-readonly", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "webdav.sqlite-db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "webdav.log-xml", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ data_config const* config = (data_config const*)srv->config_context->data[i];
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->sqlite_db_name = buffer_init();
+
+ cv[0].destination = &(s->enabled);
+ cv[1].destination = &(s->is_readonly);
+ cv[2].destination = s->sqlite_db_name;
+ cv[3].destination = &(s->log_xml);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ if (!buffer_string_is_empty(s->sqlite_db_name)) {
+#ifdef USE_PROPPATCH
+ const char *next_stmt;
+ char *err;
+
+ if (SQLITE_OK != sqlite3_open(s->sqlite_db_name->ptr, &(s->sql))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "sqlite3_open failed for",
+ s->sqlite_db_name,
+ sqlite3_errmsg(s->sql));
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_exec(s->sql,
+ "CREATE TABLE IF NOT EXISTS properties ("
+ " resource TEXT NOT NULL,"
+ " prop TEXT NOT NULL,"
+ " ns TEXT NOT NULL,"
+ " value TEXT NOT NULL,"
+ " PRIMARY KEY(resource, prop, ns))",
+ NULL, NULL, &err)) {
+
+ if (0 != strcmp(err, "table properties already exists")) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
+ sqlite3_free(err);
+
+ return HANDLER_ERROR;
+ }
+ sqlite3_free(err);
+ }
+
+ if (SQLITE_OK != sqlite3_exec(s->sql,
+ "CREATE TABLE IF NOT EXISTS locks ("
+ " locktoken TEXT NOT NULL,"
+ " resource TEXT NOT NULL,"
+ " lockscope TEXT NOT NULL,"
+ " locktype TEXT NOT NULL,"
+ " owner TEXT NOT NULL,"
+ " depth INT NOT NULL,"
+ " timeout TIMESTAMP NOT NULL,"
+ " PRIMARY KEY(locktoken))",
+ NULL, NULL, &err)) {
+
+ if (0 != strcmp(err, "table locks already exists")) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
+ sqlite3_free(err);
+
+ return HANDLER_ERROR;
+ }
+ sqlite3_free(err);
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
+ &(s->stmt_select_prop), &next_stmt)) {
+ /* prepare failed */
+
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
+ &(s->stmt_select_propnames), &next_stmt)) {
+ /* prepare failed */
+
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
+ return HANDLER_ERROR;
+ }
+
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
+ &(s->stmt_update_prop), &next_stmt)) {
+ /* prepare failed */
+
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
+ &(s->stmt_delete_prop), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
+ &(s->stmt_delete_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
+ &(s->stmt_copy_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("UPDATE OR REPLACE properties SET resource = ? WHERE resource = ?"),
+ &(s->stmt_move_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ /* LOCKS */
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
+ &(s->stmt_create_lock), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
+ &(s->stmt_remove_lock), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout-CURRENT_TIME FROM locks WHERE locktoken = ?"),
+ &(s->stmt_read_lock), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout-CURRENT_TIME FROM locks WHERE resource = ?"),
+ &(s->stmt_read_lock_by_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
+ &(s->stmt_refresh_lock), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
+ return HANDLER_ERROR;
+#endif
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH_OPTION(x) \
+ p->conf.x = s->x;
+static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH_OPTION(enabled);
+ PATCH_OPTION(is_readonly);
+ PATCH_OPTION(log_xml);
+
+#ifdef USE_PROPPATCH
+ PATCH_OPTION(sql);
+ PATCH_OPTION(stmt_update_prop);
+ PATCH_OPTION(stmt_delete_prop);
+ PATCH_OPTION(stmt_select_prop);
+ PATCH_OPTION(stmt_select_propnames);
+
+ PATCH_OPTION(stmt_delete_uri);
+ PATCH_OPTION(stmt_move_uri);
+ PATCH_OPTION(stmt_copy_uri);
+
+ PATCH_OPTION(stmt_remove_lock);
+ PATCH_OPTION(stmt_refresh_lock);
+ PATCH_OPTION(stmt_create_lock);
+ PATCH_OPTION(stmt_read_lock);
+ PATCH_OPTION(stmt_read_lock_by_uri);
+#endif
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
+ PATCH_OPTION(enabled);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
+ PATCH_OPTION(is_readonly);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
+ PATCH_OPTION(log_xml);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
+#ifdef USE_PROPPATCH
+ PATCH_OPTION(sql);
+ PATCH_OPTION(stmt_update_prop);
+ PATCH_OPTION(stmt_delete_prop);
+ PATCH_OPTION(stmt_select_prop);
+ PATCH_OPTION(stmt_select_propnames);
+
+ PATCH_OPTION(stmt_delete_uri);
+ PATCH_OPTION(stmt_move_uri);
+ PATCH_OPTION(stmt_copy_uri);
+
+ PATCH_OPTION(stmt_remove_lock);
+ PATCH_OPTION(stmt_refresh_lock);
+ PATCH_OPTION(stmt_create_lock);
+ PATCH_OPTION(stmt_read_lock);
+ PATCH_OPTION(stmt_read_lock_by_uri);
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+
+URIHANDLER_FUNC(mod_webdav_uri_handler) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+
+ mod_webdav_patch_connection(srv, con, p);
+
+ if (!p->conf.enabled) return HANDLER_GO_ON;
+
+ switch (con->request.http_method) {
+ case HTTP_METHOD_OPTIONS:
+ /* we fake a little bit but it makes MS W2k happy and it let's us mount the volume */
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("DAV"), CONST_STR_LEN("1,2"));
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("MS-Author-Via"), CONST_STR_LEN("DAV"));
+
+ if (p->conf.is_readonly) {
+ http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
+ } else {
+ http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+static int webdav_gen_prop_tag(server *srv, connection *con,
+ char *prop_name,
+ char *prop_ns,
+ char *value,
+ buffer *b) {
+
+ UNUSED(srv);
+ UNUSED(con);
+
+ if (value) {
+ buffer_append_string_len(b,CONST_STR_LEN("<"));
+ buffer_append_string(b, prop_name);
+ buffer_append_string_len(b, CONST_STR_LEN(" xmlns=\""));
+ buffer_append_string(b, prop_ns);
+ buffer_append_string_len(b, CONST_STR_LEN("\">"));
+
+ buffer_append_string(b, value);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</"));
+ buffer_append_string(b, prop_name);
+ buffer_append_string_len(b, CONST_STR_LEN(">"));
+ } else {
+ buffer_append_string_len(b,CONST_STR_LEN("<"));
+ buffer_append_string(b, prop_name);
+ buffer_append_string_len(b, CONST_STR_LEN(" xmlns=\""));
+ buffer_append_string(b, prop_ns);
+ buffer_append_string_len(b, CONST_STR_LEN("\"/>"));
+ }
+
+ return 0;
+}
+
+
+static int webdav_gen_response_status_tag(server *srv, connection *con, physical *dst, int status, buffer *b) {
+ UNUSED(srv);
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:response xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:href>\n"));
+ buffer_append_string_buffer(b, dst->rel_path);
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>\n"));
+
+ if (con->request.http_version == HTTP_VERSION_1_1) {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
+ } else {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
+ }
+ http_status_append(b, status);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:status>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
+
+ return 0;
+}
+
+static int webdav_delete_file(server *srv, connection *con, handler_ctx *hctx, physical *dst, buffer *b) {
+ int status = 0;
+
+ /* try to unlink it */
+ if (-1 == unlink(dst->path->ptr)) {
+ switch(errno) {
+ case EACCES:
+ case EPERM:
+ /* 403 */
+ status = 403;
+ break;
+ default:
+ status = 501;
+ break;
+ }
+ webdav_gen_response_status_tag(srv, con, dst, status, b);
+ } else {
+#ifdef USE_PROPPATCH
+ sqlite3_stmt *stmt = hctx->conf.stmt_delete_uri;
+
+ if (!stmt) {
+ status = 403;
+ webdav_gen_response_status_tag(srv, con, dst, status, b);
+ } else {
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(dst->rel_path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+ }
+ }
+#else
+ UNUSED(hctx);
+#endif
+ }
+
+ return (status != 0);
+}
+
+static int webdav_delete_dir(server *srv, connection *con, handler_ctx *hctx, physical *dst, buffer *b) {
+ DIR *dir;
+ int have_multi_status = 0;
+ physical d;
+
+ d.path = buffer_init();
+ d.rel_path = buffer_init();
+
+ if (NULL != (dir = opendir(dst->path->ptr))) {
+ struct dirent *de;
+
+ while(NULL != (de = readdir(dir))) {
+ struct stat st;
+ size_t nlen;
+
+ if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+ (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
+ continue;
+ /* ignore the parent dir */
+ }
+
+ nlen = strlen(de->d_name);
+ buffer_copy_buffer(d.path, dst->path);
+ buffer_append_path_len(d.path, de->d_name, nlen);
+
+ buffer_copy_buffer(d.rel_path, dst->rel_path);
+ buffer_append_path_len(d.rel_path, de->d_name, nlen);
+
+ /* stat and unlink afterwards */
+ if (-1 == stat(d.path->ptr, &st)) {
+ /* don't about it yet, rmdir will fail too */
+ } else if (S_ISDIR(st.st_mode)) {
+ have_multi_status = webdav_delete_dir(srv, con, hctx, &d, b);
+
+ /* try to unlink it */
+ if (-1 == rmdir(d.path->ptr)) {
+ int status;
+ switch(errno) {
+ case EACCES:
+ case EPERM:
+ /* 403 */
+ status = 403;
+ break;
+ default:
+ status = 501;
+ break;
+ }
+ have_multi_status = 1;
+
+ webdav_gen_response_status_tag(srv, con, &d, status, b);
+ } else {
+#ifdef USE_PROPPATCH
+ sqlite3_stmt *stmt = hctx->conf.stmt_delete_uri;
+
+ if (stmt) {
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(d.rel_path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+ }
+ }
+#endif
+ }
+ } else {
+ have_multi_status = webdav_delete_file(srv, con, hctx, &d, b);
+ }
+ }
+ closedir(dir);
+
+ buffer_free(d.path);
+ buffer_free(d.rel_path);
+ }
+
+ return have_multi_status;
+}
+
+/* don't want to block when open()ing a fifo */
+#if defined(O_NONBLOCK)
+# define FIFO_NONBLOCK O_NONBLOCK
+#else
+# define FIFO_NONBLOCK 0
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static int webdav_copy_file(server *srv, connection *con, handler_ctx *hctx, physical *src, physical *dst, int overwrite) {
+ char *data;
+ ssize_t rd, wr, offset;
+ int status = 0, ifd, ofd;
+ UNUSED(srv);
+ UNUSED(con);
+
+ if (-1 == (ifd = open(src->path->ptr, O_RDONLY | O_BINARY | FIFO_NONBLOCK))) {
+ return 403;
+ }
+
+ if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), WEBDAV_FILE_MODE))) {
+ /* opening the destination failed for some reason */
+ switch(errno) {
+ case EEXIST:
+ status = 412;
+ break;
+ case EISDIR:
+ status = 409;
+ break;
+ case ENOENT:
+ /* at least one part in the middle wasn't existing */
+ status = 409;
+ break;
+ default:
+ status = 403;
+ break;
+ }
+ close(ifd);
+ return status;
+ }
+
+ data = malloc(131072);
+ force_assert(data);
+
+ while (0 < (rd = read(ifd, data, 131072))) {
+ offset = 0;
+ do {
+ wr = write(ofd, data+offset, (size_t)(rd-offset));
+ } while (wr >= 0 ? (offset += wr) != rd : (errno == EINTR));
+ if (-1 == wr) {
+ status = (errno == ENOSPC) ? 507 : 403;
+ break;
+ }
+
+ }
+ if (0 != rd && 0 == status) status = 403;
+
+ free(data);
+ close(ifd);
+ if (0 != close(ofd)) {
+ if (0 == status) status = (errno == ENOSPC) ? 507 : 403;
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "close ", dst->path, "failed: ", strerror(errno));
+ }
+
+#ifdef USE_PROPPATCH
+ if (0 == status) {
+ /* copy worked fine, copy connected properties */
+ sqlite3_stmt *stmt = hctx->conf.stmt_copy_uri;
+
+ if (stmt) {
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(dst->rel_path),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+ CONST_BUF_LEN(src->rel_path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+ }
+ }
+ }
+#else
+ UNUSED(hctx);
+#endif
+ return status;
+}
+
+static int webdav_copy_dir(server *srv, connection *con, handler_ctx *hctx, physical *src, physical *dst, int overwrite) {
+ DIR *srcdir;
+ int status = 0;
+
+ if (NULL != (srcdir = opendir(src->path->ptr))) {
+ struct dirent *de;
+ physical s, d;
+
+ s.path = buffer_init();
+ s.rel_path = buffer_init();
+
+ d.path = buffer_init();
+ d.rel_path = buffer_init();
+
+ while (NULL != (de = readdir(srcdir))) {
+ struct stat st;
+ size_t nlen;
+
+ if ((de->d_name[0] == '.' && de->d_name[1] == '\0')
+ || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
+ continue;
+ }
+
+ nlen = strlen(de->d_name);
+ buffer_copy_buffer(s.path, src->path);
+ buffer_append_path_len(s.path, de->d_name, nlen);
+
+ buffer_copy_buffer(d.path, dst->path);
+ buffer_append_path_len(d.path, de->d_name, nlen);
+
+ buffer_copy_buffer(s.rel_path, src->rel_path);
+ buffer_append_path_len(s.rel_path, de->d_name, nlen);
+
+ buffer_copy_buffer(d.rel_path, dst->rel_path);
+ buffer_append_path_len(d.rel_path, de->d_name, nlen);
+
+ if (-1 == stat(s.path->ptr, &st)) {
+ /* why ? */
+ } else if (S_ISDIR(st.st_mode)) {
+ /* a directory */
+ if (-1 == mkdir(d.path->ptr, WEBDAV_DIR_MODE) &&
+ errno != EEXIST) {
+ /* WTH ? */
+ } else {
+#ifdef USE_PROPPATCH
+ sqlite3_stmt *stmt = hctx->conf.stmt_copy_uri;
+
+ if (0 != (status = webdav_copy_dir(srv, con, hctx, &s, &d, overwrite))) {
+ break;
+ }
+ /* directory is copied, copy the properties too */
+
+ if (stmt) {
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(dst->rel_path),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+ CONST_BUF_LEN(src->rel_path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ /* */
+ }
+ }
+#endif
+ }
+ } else if (S_ISREG(st.st_mode)) {
+ /* a plain file */
+ if (0 != (status = webdav_copy_file(srv, con, hctx, &s, &d, overwrite))) {
+ break;
+ }
+ }
+ }
+
+ buffer_free(s.path);
+ buffer_free(s.rel_path);
+ buffer_free(d.path);
+ buffer_free(d.rel_path);
+
+ closedir(srcdir);
+ }
+
+ return status;
+}
+
+#ifdef USE_LOCKS
+static void webdav_activelock(buffer *b,
+ const buffer *locktoken, const char *lockscope, const char *locktype, int depth, int timeout) {
+ buffer_append_string_len(b, CONST_STR_LEN("<D:activelock>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:lockscope>"));
+ buffer_append_string_len(b, CONST_STR_LEN("<D:"));
+ buffer_append_string(b, lockscope);
+ buffer_append_string_len(b, CONST_STR_LEN("/>"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:lockscope>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:locktype>"));
+ buffer_append_string_len(b, CONST_STR_LEN("<D:"));
+ buffer_append_string(b, locktype);
+ buffer_append_string_len(b, CONST_STR_LEN("/>"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:locktype>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:depth>"));
+ buffer_append_string(b, depth == 0 ? "0" : "infinity");
+ buffer_append_string_len(b, CONST_STR_LEN("</D:depth>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:timeout>"));
+ buffer_append_string_len(b, CONST_STR_LEN("Second-"));
+ buffer_append_int(b, timeout);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:timeout>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:owner>"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:owner>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:locktoken>"));
+ buffer_append_string_len(b, CONST_STR_LEN("<D:href>"));
+ buffer_append_string_buffer(b, locktoken);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:href>"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:locktoken>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</D:activelock>\n"));
+}
+
+static void webdav_get_live_property_lockdiscovery(server *srv, connection *con, handler_ctx *hctx, physical *dst, buffer *b) {
+
+ sqlite3_stmt *stmt = hctx->conf.stmt_read_lock_by_uri;
+ if (!stmt) { /*(should not happen)*/
+ buffer_append_string_len(b, CONST_STR_LEN("<D:lockdiscovery>\n</D:lockdiscovery>\n"));
+ return;
+ }
+ UNUSED(srv);
+ UNUSED(con);
+
+ /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
+ * FROM locks
+ * WHERE resource = ? */
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(dst->rel_path),
+ SQLITE_TRANSIENT);
+
+ buffer_append_string_len(b, CONST_STR_LEN("<D:lockdiscovery>\n"));
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ const char *lockscope = (const char *)sqlite3_column_text(stmt, 2);
+ const char *locktype = (const char *)sqlite3_column_text(stmt, 3);
+ const int depth = sqlite3_column_int(stmt, 5);
+ const int timeout = sqlite3_column_int(stmt, 6);
+ buffer locktoken = { NULL, 0, 0 };
+ locktoken.ptr = (char *)sqlite3_column_text(stmt, 0);
+ locktoken.used = sqlite3_column_bytes(stmt, 0);
+ if (locktoken.used) ++locktoken.used;
+ locktoken.size = locktoken.used;
+
+ if (timeout > 0) {
+ webdav_activelock(b, &locktoken, lockscope, locktype, depth, timeout);
+ }
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("</D:lockdiscovery>\n"));
+}
+#endif
+
+static int webdav_get_live_property(server *srv, connection *con, handler_ctx *hctx, physical *dst, char *prop_name, buffer *b) {
+ stat_cache_entry *sce = NULL;
+ int found = 0;
+
+ UNUSED(hctx);
+
+ if (HANDLER_ERROR != (stat_cache_get_entry(srv, con, dst->path, &sce))) {
+ char ctime_buf[] = "2005-08-18T07:27:16Z";
+ char mtime_buf[] = "Thu, 18 Aug 2005 07:27:16 GMT";
+
+ if (0 == strcmp(prop_name, "resourcetype")) {
+ if (S_ISDIR(sce->st.st_mode)) {
+ buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype><D:collection/></D:resourcetype>"));
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype/>"));
+ }
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getcontenttype")) {
+ if (S_ISDIR(sce->st.st_mode)) {
+ buffer_append_string_len(b, CONST_STR_LEN("<D:getcontenttype>httpd/unix-directory</D:getcontenttype>"));
+ found = 1;
+ } else if(S_ISREG(sce->st.st_mode)) {
+ const buffer *type = stat_cache_mimetype_by_ext(con, CONST_BUF_LEN(dst->path));
+ if (NULL != type) {
+ buffer_append_string_len(b, CONST_STR_LEN("<D:getcontenttype>"));
+ buffer_append_string_buffer(b, type);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
+ found = 1;
+ }
+ }
+ } else if (0 == strcmp(prop_name, "creationdate")) {
+ buffer_append_string_len(b, CONST_STR_LEN("<D:creationdate ns0:dt=\"dateTime.tz\">"));
+ strftime(ctime_buf, sizeof(ctime_buf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&(sce->st.st_ctime)));
+ buffer_append_string(b, ctime_buf);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:creationdate>"));
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getlastmodified")) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getlastmodified ns0:dt=\"dateTime.rfc1123\">"));
+ strftime(mtime_buf, sizeof(mtime_buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(sce->st.st_mtime)));
+ buffer_append_string(b, mtime_buf);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getlastmodified>"));
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getcontentlength")) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlength>"));
+ buffer_append_int(b, sce->st.st_size);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlength>"));
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getcontentlanguage")) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlanguage>"));
+ buffer_append_string_len(b, CONST_STR_LEN("en"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlanguage>"));
+ found = 1;
+ } else if (0 == strcmp(prop_name, "getetag")) {
+ etag_create(con->physical.etag, &sce->st, con->etag_flags);
+ etag_mutate(con->physical.etag, con->physical.etag);
+ buffer_append_string_len(b, CONST_STR_LEN("<D:getetag>"));
+ buffer_append_string_buffer(b, con->physical.etag);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getetag>"));
+ buffer_clear(con->physical.etag);
+ found = 1;
+ #ifdef USE_LOCKS
+ } else if (0 == strcmp(prop_name, "lockdiscovery")) {
+ webdav_get_live_property_lockdiscovery(srv, con, hctx, dst, b);
+ found = 1;
+ } else if (0 == strcmp(prop_name, "supportedlock")) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:supportedlock>"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:lockentry>"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:lockscope><D:exclusive/></D:lockscope>"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:locktype><D:write/></D:locktype>"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:lockentry>"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:supportedlock>"));
+ found = 1;
+ #endif
+ }
+ }
+
+ return found ? 0 : -1;
+}
+
+static int webdav_get_property(server *srv, connection *con, handler_ctx *hctx, physical *dst, char *prop_name, char *prop_ns, buffer *b) {
+ if (0 == strcmp(prop_ns, "DAV:")) {
+ /* a local 'live' property */
+ return webdav_get_live_property(srv, con, hctx, dst, prop_name, b);
+ } else {
+ int found = 0;
+#ifdef USE_PROPPATCH
+ sqlite3_stmt *stmt = hctx->conf.stmt_select_prop;
+
+ if (stmt) {
+ /* perhaps it is in sqlite3 */
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(dst->rel_path),
+ SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 2,
+ prop_name,
+ strlen(prop_name),
+ SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 3,
+ prop_ns,
+ strlen(prop_ns),
+ SQLITE_TRANSIENT);
+
+ /* it is the PK */
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ /* there is a row for us, we only expect a single col 'value' */
+ webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
+ found = 1;
+ }
+ }
+#endif
+ return found ? 0 : -1;
+ }
+
+ /* not found */
+ return -1;
+}
+
+typedef struct {
+ char *ns;
+ char *prop;
+} webdav_property;
+
+static webdav_property live_properties[] = {
+ { "DAV:", "creationdate" },
+ /*{ "DAV:", "displayname" },*//*(not implemented)*/
+ { "DAV:", "getcontentlanguage" },
+ { "DAV:", "getcontentlength" },
+ { "DAV:", "getcontenttype" },
+ { "DAV:", "getetag" },
+ { "DAV:", "getlastmodified" },
+ { "DAV:", "resourcetype" },
+ /*{ "DAV:", "source" },*//*(not implemented)*/
+ #ifdef USE_LOCKS
+ { "DAV:", "lockdiscovery" },
+ { "DAV:", "supportedlock" },
+ #endif
+
+ { NULL, NULL }
+};
+
+typedef struct {
+ webdav_property **ptr;
+
+ size_t used;
+ size_t size;
+} webdav_properties;
+
+static int webdav_get_props(server *srv, connection *con, handler_ctx *hctx, physical *dst, webdav_properties *props, buffer *b_200, buffer *b_404) {
+ size_t i;
+
+ if (props && props->used) {
+ for (i = 0; i < props->used; i++) {
+ webdav_property *prop;
+
+ prop = props->ptr[i];
+
+ if (0 != webdav_get_property(srv, con, hctx,
+ dst, prop->prop, prop->ns, b_200)) {
+ webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
+ }
+ }
+ } else {
+ for (i = 0; live_properties[i].prop; i++) {
+ /* a local 'live' property */
+ webdav_get_live_property(srv, con, hctx, dst, live_properties[i].prop, b_200);
+ }
+ }
+
+ return 0;
+}
+
+#ifdef USE_PROPPATCH
+static int webdav_parse_chunkqueue(server *srv, connection *con, handler_ctx *hctx, chunkqueue *cq, xmlDoc **ret_xml) {
+ xmlParserCtxtPtr ctxt;
+ xmlDoc *xml;
+ int res;
+ int err;
+
+ chunk *c;
+
+ UNUSED(con);
+
+ /* read the chunks in to the XML document */
+ ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
+
+ for (c = cq->first; cq->bytes_out != cq->bytes_in; c = cq->first) {
+ size_t weWant = cq->bytes_out - cq->bytes_in;
+ size_t weHave;
+ int mapped;
+ void *data;
+
+ switch(c->type) {
+ case FILE_CHUNK:
+ weHave = c->file.length - c->offset;
+
+ if (weHave > weWant) weHave = weWant;
+
+ /* xml chunks are always memory, mmap() is our friend */
+ mapped = (c->file.mmap.start != MAP_FAILED);
+ if (mapped) {
+ data = c->file.mmap.start + c->offset;
+ } else {
+ if (-1 == c->file.fd && /* open the file if not already open */
+ -1 == (c->file.fd = fdevent_open_cloexec(c->mem->ptr, O_RDONLY, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+
+ return -1;
+ }
+
+ if (MAP_FAILED != (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_PRIVATE, c->file.fd, 0))) {
+ /* chunk_reset() or chunk_free() will cleanup for us */
+ c->file.mmap.length = c->file.length;
+ data = c->file.mmap.start + c->offset;
+ mapped = 1;
+ } else {
+ ssize_t rd;
+ if (weHave > 65536) weHave = 65536;
+ data = malloc(weHave);
+ force_assert(data);
+ if (-1 == lseek(c->file.fd, c->file.start + c->offset, SEEK_SET)
+ || 0 > (rd = read(c->file.fd, data, weHave))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "lseek/read failed: ",
+ strerror(errno), c->mem, c->file.fd);
+ free(data);
+ return -1;
+ }
+ weHave = (size_t)rd;
+ }
+ }
+
+ if (XML_ERR_OK != (err = xmlParseChunk(ctxt, data, weHave, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
+ }
+
+ chunkqueue_mark_written(cq, weHave);
+
+ if (!mapped) free(data);
+ break;
+ case MEM_CHUNK:
+ /* append to the buffer */
+ weHave = buffer_string_length(c->mem) - c->offset;
+
+ if (weHave > weWant) weHave = weWant;
+
+ if (hctx->conf.log_xml) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "XML-request-body:", c->mem->ptr + c->offset);
+ }
+
+ if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
+ }
+
+ chunkqueue_mark_written(cq, weHave);
+
+ break;
+ }
+ }
+
+ switch ((err = xmlParseChunk(ctxt, 0, 0, 1))) {
+ case XML_ERR_DOCUMENT_END:
+ case XML_ERR_OK:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd", "xmlParseChunk failed at final packet:", err);
+ break;
+ }
+
+ xml = ctxt->myDoc;
+ res = ctxt->wellFormed;
+ xmlFreeParserCtxt(ctxt);
+
+ if (res == 0) {
+ xmlFreeDoc(xml);
+ } else {
+ *ret_xml = xml;
+ }
+
+ return res;
+}
+#endif
+
+#ifdef USE_LOCKS
+static int webdav_lockdiscovery(connection *con, buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
+
+ buffer *b = chunkqueue_append_buffer_open(con->write_queue);
+
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE,
+ CONST_STR_LEN("Content-Type"),
+ CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:lockdiscovery>\n"));
+ webdav_activelock(b, locktoken, lockscope, locktype, depth, 600);
+ buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ return 0;
+}
+#endif
+
+/**
+ * check if resource is having the right locks to access to resource
+ *
+ *
+ *
+ */
+static int webdav_has_lock(server *srv, connection *con, handler_ctx *hctx, buffer *uri) {
+ int has_lock = 1;
+
+#ifdef USE_LOCKS
+ buffer *vb;
+ UNUSED(srv);
+
+ /**
+ * This implementation is more fake than real
+ * we need a parser for the If: header to really handle the full scope
+ *
+ * X-Litmus: locks: 11 (owner_modify)
+ * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
+ * - a tagged check:
+ * if http://127.0.0.1:1025/dav/litmus/lockme is locked with
+ * opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1, go on
+ *
+ * X-Litmus: locks: 16 (fail_cond_put)
+ * If: (<DAV:no-lock> ["-1622396671"])
+ * - untagged:
+ * go on if the resource has the etag [...] and the lock
+ */
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("If")))) {
+ /* Ooh, ooh. A if tag, now the fun begins.
+ *
+ * this can only work with a real parser
+ **/
+ } else {
+ /* we didn't provided a lock-token -> */
+ /* if the resource is locked -> 423 */
+
+ sqlite3_stmt *stmt = hctx->conf.stmt_read_lock_by_uri;
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(uri),
+ SQLITE_TRANSIENT);
+
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ has_lock = 0;
+ }
+ }
+#else
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(hctx);
+ UNUSED(uri);
+#endif
+
+ return has_lock;
+}
+
+static int mod_webdav_depth(connection *con) {
+ buffer *b =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Depth"));
+ if (NULL != b && 1 == buffer_string_length(b)) {
+ if (b->ptr[0] == '0') return 0;
+ if (b->ptr[0] == '1') return 1;
+ }
+ return -1; /* (Depth: infinity) */
+}
+
+static handler_t mod_webdav_propfind(server *srv, connection *con, plugin_data *p, handler_ctx *hctx) {
+ buffer *b;
+ DIR *dir;
+ int depth = mod_webdav_depth(con);
+ struct stat st;
+ buffer *prop_200;
+ buffer *prop_404;
+ webdav_properties *req_props;
+ stat_cache_entry *sce = NULL;
+
+ /* they want to know the properties of the directory */
+ req_props = NULL;
+
+ /* is there a content-body ? */
+
+ switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ case HANDLER_ERROR:
+ if (errno == ENOENT) {
+ con->http_status = 404;
+ return HANDLER_FINISHED;
+ }
+ else if (errno == EACCES) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ else {
+ con->http_status = 500;
+ return HANDLER_FINISHED;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (S_ISDIR(sce->st.st_mode) && con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
+ http_response_redirect_to_directory(srv, con);
+ return HANDLER_FINISHED;
+ }
+
+#ifdef USE_PROPPATCH
+ /* any special requests or just allprop ? */
+ if (con->request.content_length) {
+ xmlDocPtr xml;
+
+ if (con->state == CON_STATE_READ_POST) {
+ handler_t r = connection_handle_read_post_state(srv, con);
+ if (r != HANDLER_GO_ON) return r;
+ }
+
+ if (1 == webdav_parse_chunkqueue(srv, con, hctx, con->request_content_queue, &xml)) {
+ xmlNode *rootnode = xmlDocGetRootElement(xml);
+
+ force_assert(rootnode);
+
+ if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propfind")) {
+ xmlNode *cmd;
+
+ req_props = calloc(1, sizeof(*req_props));
+
+ for (cmd = rootnode->children; cmd; cmd = cmd->next) {
+
+ if (0 == xmlStrcmp(cmd->name, BAD_CAST "prop")) {
+ /* get prop by name */
+ xmlNode *prop;
+
+ for (prop = cmd->children; prop; prop = prop->next) {
+ if (prop->type == XML_TEXT_NODE) continue; /* ignore WS */
+
+ if (prop->ns &&
+ (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
+ (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
+ size_t i;
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "no name space for:",
+ prop->name);
+
+ xmlFreeDoc(xml);
+
+ for (i = 0; i < req_props->used; i++) {
+ free(req_props->ptr[i]->ns);
+ free(req_props->ptr[i]->prop);
+ free(req_props->ptr[i]);
+ }
+ free(req_props->ptr);
+ free(req_props);
+
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+
+ /* add property to requested list */
+ if (req_props->size == 0) {
+ req_props->size = 16;
+ req_props->ptr = malloc(sizeof(*(req_props->ptr)) * req_props->size);
+ } else if (req_props->used == req_props->size) {
+ req_props->size += 16;
+ req_props->ptr = realloc(req_props->ptr, sizeof(*(req_props->ptr)) * req_props->size);
+ }
+
+ req_props->ptr[req_props->used] = malloc(sizeof(webdav_property));
+ req_props->ptr[req_props->used]->ns = (char *)xmlStrdup(prop->ns ? prop->ns->href : (xmlChar *)"");
+ req_props->ptr[req_props->used]->prop = (char *)xmlStrdup(prop->name);
+ req_props->used++;
+ }
+ } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "propname")) {
+ sqlite3_stmt *stmt = p->conf.stmt_select_propnames;
+
+ if (stmt) {
+ /* get all property names (EMPTY) */
+ sqlite3_reset(stmt);
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ }
+ }
+ } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
+ /* get all properties (EMPTY) */
+ }
+ }
+ }
+
+ xmlFreeDoc(xml);
+ } else {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ }
+#endif
+ con->http_status = 207;
+
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+ b = chunkqueue_append_buffer_open(con->write_queue);
+
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
+
+ /* allprop */
+
+ prop_200 = buffer_init();
+ prop_404 = buffer_init();
+
+ {
+ /* Depth: 0 or Depth: 1 */
+ webdav_get_props(srv, con, hctx, &(con->physical), req_props, prop_200, prop_404);
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
+ buffer_append_string_buffer(b, con->uri.scheme);
+ buffer_append_string_len(b,CONST_STR_LEN("://"));
+ buffer_append_string_buffer(b, con->uri.authority);
+ buffer_append_string_encoded(b, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
+
+ if (!buffer_string_is_empty(prop_200)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+ buffer_append_string_buffer(b, prop_200);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
+ }
+ if (!buffer_string_is_empty(prop_404)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+ buffer_append_string_buffer(b, prop_404);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
+ }
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
+ }
+
+ if (depth == 1) {
+
+ if (NULL != (dir = opendir(con->physical.path->ptr))) {
+ struct dirent *de;
+ physical d;
+ physical *dst = &(con->physical);
+
+ d.path = buffer_init();
+ d.rel_path = buffer_init();
+
+ while(NULL != (de = readdir(dir))) {
+ size_t nlen;
+ if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) {
+ continue;
+ /* ignore the parent and target dir */
+ }
+
+ nlen = strlen(de->d_name);
+ buffer_copy_buffer(d.path, dst->path);
+ buffer_append_path_len(d.path, de->d_name, nlen);
+
+ buffer_copy_buffer(d.rel_path, dst->rel_path);
+ buffer_append_path_len(d.rel_path, de->d_name, nlen);
+
+ buffer_clear(prop_200);
+ buffer_clear(prop_404);
+
+ webdav_get_props(srv, con, hctx, &d, req_props, prop_200, prop_404);
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
+ buffer_append_string_buffer(b, con->uri.scheme);
+ buffer_append_string_len(b,CONST_STR_LEN("://"));
+ buffer_append_string_buffer(b, con->uri.authority);
+ buffer_append_string_encoded(b, CONST_BUF_LEN(d.rel_path), ENCODING_REL_URI);
+ if (0 == stat(d.path->ptr, &st) && S_ISDIR(st.st_mode)) {
+ /* Append a '/' on subdirectories */
+ buffer_append_string_len(b,CONST_STR_LEN("/"));
+ }
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
+
+ if (!buffer_string_is_empty(prop_200)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+ buffer_append_string_buffer(b, prop_200);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
+ }
+ if (!buffer_string_is_empty(prop_404)) {
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
+
+ buffer_append_string_buffer(b, prop_404);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
+ }
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
+ }
+ closedir(dir);
+ buffer_free(d.path);
+ buffer_free(d.rel_path);
+ }
+
+ }
+
+ if (req_props) {
+ size_t i;
+ for (i = 0; i < req_props->used; i++) {
+ free(req_props->ptr[i]->ns);
+ free(req_props->ptr[i]->prop);
+ free(req_props->ptr[i]);
+ }
+ free(req_props->ptr);
+ free(req_props);
+ }
+
+ buffer_free(prop_200);
+ buffer_free(prop_404);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
+
+ if (p->conf.log_xml) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
+ }
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_webdav_mkcol(connection *con, plugin_data *p) {
+ if (p->conf.is_readonly) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+
+ if (con->request.content_length != 0) {
+ /* we don't support MKCOL with a body */
+ con->http_status = 415;
+
+ return HANDLER_FINISHED;
+ }
+
+ /* let's create the directory */
+
+ if (-1 == mkdir(con->physical.path->ptr, WEBDAV_DIR_MODE)) {
+ switch(errno) {
+ case EPERM:
+ con->http_status = 403;
+ break;
+ case ENOENT:
+ case ENOTDIR:
+ con->http_status = 409;
+ break;
+ case EEXIST:
+ default:
+ con->http_status = 405; /* not allowed */
+ break;
+ }
+ } else {
+ con->http_status = 201;
+ con->file_finished = 1;
+ }
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_webdav_delete(server *srv, connection *con, plugin_data *p, handler_ctx *hctx) {
+ struct stat st;
+
+ if (p->conf.is_readonly) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+
+ /* does the client have a lock for this connection ? */
+ if (!webdav_has_lock(srv, con, hctx, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
+ /* stat and unlink afterwards */
+ if (-1 == stat(con->physical.path->ptr, &st)) {
+ /* don't about it yet, unlink will fail too */
+ switch(errno) {
+ case ENOENT:
+ con->http_status = 404;
+ break;
+ default:
+ con->http_status = 403;
+ break;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ buffer *multi_status_resp;
+
+ if (con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
+ http_response_redirect_to_directory(srv, con);
+ return HANDLER_FINISHED;
+ }
+
+ multi_status_resp = buffer_init();
+
+ if (webdav_delete_dir(srv, con, hctx, &(con->physical), multi_status_resp)) {
+ /* we got an error somewhere in between, build a 207 */
+ buffer *b;
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+ b = chunkqueue_append_buffer_open(con->write_queue);
+
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\">\n"));
+
+ buffer_append_string_buffer(b, multi_status_resp);
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
+
+ if (p->conf.log_xml) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
+ }
+
+ chunkqueue_append_buffer_commit(con->write_queue);
+
+ con->http_status = 207;
+ con->file_finished = 1;
+ } else {
+ /* everything went fine, remove the directory */
+
+ if (-1 == rmdir(con->physical.path->ptr)) {
+ switch(errno) {
+ case EPERM:
+ con->http_status = 403;
+ break;
+ case ENOENT:
+ con->http_status = 404;
+ break;
+ default:
+ con->http_status = 501;
+ break;
+ }
+ } else {
+ con->http_status = 204;
+ }
+ }
+
+ buffer_free(multi_status_resp);
+ } else if (-1 == unlink(con->physical.path->ptr)) {
+ switch(errno) {
+ case EPERM:
+ con->http_status = 403;
+ break;
+ case ENOENT:
+ con->http_status = 404;
+ break;
+ default:
+ con->http_status = 501;
+ break;
+ }
+ } else {
+ con->http_status = 204;
+ }
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_webdav_put(server *srv, connection *con, plugin_data *p, handler_ctx *hctx) {
+ buffer *b;
+ int fd;
+ chunkqueue *cq = con->request_content_queue;
+ chunk *c;
+
+ if (p->conf.is_readonly) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+
+ /* is a exclusive lock set on the source */
+ /* (check for lock once before potentially reading large input) */
+ if (0 == cq->bytes_in && !webdav_has_lock(srv, con, hctx, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
+ if (con->state == CON_STATE_READ_POST) {
+ handler_t r = connection_handle_read_post_state(srv, con);
+ if (r != HANDLER_GO_ON) return r;
+ }
+
+ /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
+ * - most important Content-Range
+ *
+ *
+ * Example: Content-Range: bytes 100-1037/1038 */
+
+ if (NULL != (b = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Content-Range")))) {
+ const char *num = b->ptr;
+ off_t offset;
+ char *err = NULL;
+
+ if (0 != strncmp(num, "bytes ", 6)) {
+ con->http_status = 501; /* not implemented */
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we only support <num>- ... */
+
+ num += 6;
+
+ /* skip WS */
+ while (*num == ' ' || *num == '\t') num++;
+
+ if (*num == '\0') {
+ con->http_status = 501; /* not implemented */
+
+ return HANDLER_FINISHED;
+ }
+
+ offset = strtoll(num, &err, 10);
+
+ if (*err != '-' || offset < 0) {
+ con->http_status = 501; /* not implemented */
+
+ return HANDLER_FINISHED;
+ }
+
+ if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, WEBDAV_FILE_MODE))) {
+ switch (errno) {
+ case ENOENT:
+ con->http_status = 404; /* not found */
+ break;
+ default:
+ con->http_status = 403; /* not found */
+ break;
+ }
+ return HANDLER_FINISHED;
+ }
+
+ if (-1 == lseek(fd, offset, SEEK_SET)) {
+ con->http_status = 501; /* not implemented */
+
+ close(fd);
+
+ return HANDLER_FINISHED;
+ }
+ con->http_status = 200; /* modified */
+ } else {
+ /* 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, WEBDAV_FILE_MODE))) {
+ if (errno != ENOENT ||
+ -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, WEBDAV_FILE_MODE))) {
+ /* we can't open the file */
+ con->http_status = 403;
+
+ return HANDLER_FINISHED;
+ } else {
+ con->http_status = 201; /* created */
+ }
+ } else {
+ con->http_status = 200; /* modified */
+ }
+ }
+
+ con->file_finished = 1;
+
+ for (c = cq->first; c; c = cq->first) {
+ int r = 0;
+ int mapped;
+ void *data;
+ size_t dlen;
+
+ /* copy all chunks */
+ switch(c->type) {
+ case FILE_CHUNK:
+
+ mapped = (c->file.mmap.start != MAP_FAILED);
+ dlen = c->file.length - c->offset;
+ if (mapped) {
+ data = c->file.mmap.start + c->offset;
+ } else {
+ if (-1 == c->file.fd && /* open the file if not already open */
+ -1 == (c->file.fd = fdevent_open_cloexec(c->mem->ptr, O_RDONLY, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+ close(fd);
+ return HANDLER_ERROR;
+ }
+
+ if (MAP_FAILED != (c->file.mmap.start = mmap(NULL, c->file.length, PROT_READ, MAP_PRIVATE, c->file.fd, 0))) {
+ /* chunk_reset() or chunk_free() will cleanup for us */
+ c->file.mmap.length = c->file.length;
+ data = c->file.mmap.start + c->offset;
+ mapped = 1;
+ } else {
+ ssize_t rd;
+ if (dlen > 65536) dlen = 65536;
+ data = malloc(dlen);
+ force_assert(data);
+ if (-1 == lseek(c->file.fd, c->file.start + c->offset, SEEK_SET)
+ || 0 > (rd = read(c->file.fd, data, dlen))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "lseek/read failed: ",
+ strerror(errno), c->mem, c->file.fd);
+ free(data);
+ close(fd);
+ return HANDLER_ERROR;
+ }
+ dlen = (size_t)rd;
+ }
+
+ }
+
+ if ((r = write(fd, data, dlen)) < 0) {
+ switch(errno) {
+ case ENOSPC:
+ con->http_status = 507;
+
+ break;
+ default:
+ con->http_status = 403;
+ break;
+ }
+ }
+
+ if (!mapped) free(data);
+ break;
+ case MEM_CHUNK:
+ if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
+ switch(errno) {
+ case ENOSPC:
+ con->http_status = 507;
+
+ break;
+ default:
+ con->http_status = 403;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (r > 0) {
+ chunkqueue_mark_written(cq, r);
+ } else {
+ break;
+ }
+ }
+ if (0 != close(fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "close ", con->physical.path, "failed: ", strerror(errno));
+ return HANDLER_ERROR;
+ }
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_webdav_copymove(server *srv, connection *con, plugin_data *p, handler_ctx *hctx) {
+ buffer *b;
+ struct stat st;
+ buffer *destination = NULL;
+ char *sep, *sep2, *start;
+ int overwrite = 1;
+
+ if (p->conf.is_readonly) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+
+ /* is a exclusive lock set on the source */
+ if (con->request.http_method == HTTP_METHOD_MOVE) {
+ if (!webdav_has_lock(srv, con, hctx, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+ }
+
+ if (NULL == (destination = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Destination")))) {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+
+ if (NULL != (b = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Overwrite")))) {
+ if (buffer_string_length(b) != 1 ||
+ (b->ptr[0] != 'F' &&
+ b->ptr[0] != 'T') ) {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ overwrite = (b->ptr[0] == 'F' ? 0 : 1);
+ }
+ /* let's parse the Destination
+ *
+ * http://127.0.0.1:1025/dav/litmus/copydest
+ *
+ * - host has to be the same as the Host: header we got
+ * - we have to stay inside the document root
+ * - the query string is thrown away
+ * */
+
+ start = destination->ptr;
+ sep = start + buffer_string_length(con->uri.scheme);
+
+ if (0 != strncmp(start, con->uri.scheme->ptr, sep - start)
+ || sep[0] != ':' || sep[1] != '/' || sep[2] != '/') {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ buffer_copy_buffer(p->uri.scheme, con->uri.scheme); /*(unused?)*/
+
+ start = sep + 3;
+
+ if (NULL == (sep = strchr(start, '/'))) {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ if (NULL != (sep2 = memchr(start, '@', sep - start))) {
+ /* skip login information */
+ start = sep2 + 1;
+ }
+ buffer_copy_string_len(p->uri.authority, start, sep - start);
+
+ start = sep + 1;
+
+ if (NULL == (sep = strchr(start, '?'))) {
+ /* no query string, good */
+ buffer_copy_string(p->uri.path, start);
+ } else {
+ buffer_copy_string_len(p->uri.path, start, sep - start);
+ }
+
+ if (!buffer_is_equal(p->uri.authority, con->uri.authority)) {
+ /* not the same host */
+ con->http_status = 502;
+ return HANDLER_FINISHED;
+ }
+
+ buffer_urldecode_path(p->uri.path);
+ if (!buffer_is_valid_UTF8(p->uri.path)) {
+ /* invalid UTF-8 after url-decode */
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ buffer_path_simplify(p->uri.path, p->uri.path);
+
+ if (buffer_string_is_empty(p->uri.path) || p->uri.path->ptr[0] != '/') {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+
+ /* we now have a URI which is clean. transform it into a physical path */
+ buffer_copy_buffer(p->physical.doc_root, con->physical.doc_root);
+ buffer_copy_buffer(p->physical.rel_path, p->uri.path);
+
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(p->physical.rel_path);
+ }
+
+ /* Destination physical path
+ * src con->physical.path might have been remapped with mod_alias.
+ * (but mod_alias does not modify con->physical.rel_path)
+ * Find matching prefix to support use of mod_alias to remap webdav root.
+ * Aliasing of paths underneath the webdav root might not work.
+ * Likewise, mod_rewrite URL rewriting might thwart this comparison.
+ * Use mod_redirect instead of mod_alias to remap paths *under* webdav root.
+ * Use mod_redirect instead of mod_rewrite on *any* parts of path to webdav.
+ * (Related, use mod_auth to protect webdav root, but avoid attempting to
+ * use mod_auth on paths underneath webdav root, as Destination is not
+ * validated with mod_auth)
+ *
+ * tl;dr: webdav paths and webdav properties are managed by mod_webdav,
+ * so do not modify paths externally or else undefined behavior
+ * or corruption may occur
+ */
+ {
+ /* find matching URI prefix
+ * check if remaining con->physical.rel_path matches suffix
+ * of con->physical.basedir so that we can use it to
+ * remap Destination physical path */
+ size_t i, remain;
+ sep = con->uri.path->ptr;
+ sep2 = p->uri.path->ptr;
+ for (i = 0; sep[i] && sep[i] == sep2[i]; ++i) ;
+ if (sep[i] == '\0' && (sep2[i] == '\0' || sep2[i] == '/' || (i > 0 && sep[i-1] == '/'))) {
+ /* src and dst URI match or dst is nested inside src; invalid COPY or MOVE */
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ while (i != 0 && sep[--i] != '/') ; /* find matching directory path */
+ remain = buffer_string_length(con->uri.path) - i;
+ if (!con->conf.force_lowercase_filenames
+ ? buffer_is_equal_right_len(con->physical.path, con->physical.rel_path, remain)
+ :(buffer_string_length(con->physical.path) >= remain
+ && 0 == strncasecmp(con->physical.path->ptr+buffer_string_length(con->physical.path)-remain, con->physical.rel_path->ptr+i, remain))) {
+ /* (at this point, p->physical.rel_path is identical to (or lowercased version of) p->uri.path) */
+ buffer_copy_string_len(p->physical.path, con->physical.path->ptr, buffer_string_length(con->physical.path)-remain);
+ buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr+i, buffer_string_length(p->physical.rel_path)-i);
+
+ buffer_copy_buffer(p->physical.basedir, con->physical.basedir);
+ buffer_append_slash(p->physical.basedir);
+ } else {
+ /* unable to perform physical path remap here;
+ * assume doc_root/rel_path and no remapping */
+ buffer_copy_buffer(p->physical.path, p->physical.doc_root);
+ buffer_append_slash(p->physical.path);
+ buffer_copy_buffer(p->physical.basedir, p->physical.path);
+ buffer_append_path_len(p->physical.path, CONST_BUF_LEN(p->physical.rel_path));
+ }
+ }
+
+ /* let's see if the source is a directory
+ * if yes, we fail with 501 */
+
+ if (-1 == stat(con->physical.path->ptr, &st)) {
+ /* don't about it yet, unlink will fail too */
+ switch(errno) {
+ case ENOENT:
+ con->http_status = 404;
+ break;
+ default:
+ con->http_status = 403;
+ break;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ int r;
+ int created = 0;
+ /* src is a directory */
+
+ if (con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
+ http_response_redirect_to_directory(srv, con);
+ return HANDLER_FINISHED;
+ }
+
+ if (-1 == stat(p->physical.path->ptr, &st)) {
+ if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ created = 1;
+ } else if (!S_ISDIR(st.st_mode)) {
+ if (overwrite == 0) {
+ /* copying into a non-dir ? */
+ con->http_status = 409;
+ return HANDLER_FINISHED;
+ } else {
+ unlink(p->physical.path->ptr);
+ if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ created = 1;
+ }
+ }
+
+ /* copy the content of src to dest */
+ if (0 != (r = webdav_copy_dir(srv, con, hctx, &(con->physical), &(p->physical), overwrite))) {
+ con->http_status = r;
+ return HANDLER_FINISHED;
+ }
+ if (con->request.http_method == HTTP_METHOD_MOVE) {
+ b = buffer_init();
+ webdav_delete_dir(srv, con, hctx, &(con->physical), b); /* content */
+ buffer_free(b);
+
+ rmdir(con->physical.path->ptr);
+ }
+ con->http_status = created ? 201 : 204;
+ con->file_finished = 1;
+ } else {
+ /* it is just a file, good */
+ int r;
+ int destdir = 0;
+
+ /* does the client have a lock for this connection ? */
+ if (!webdav_has_lock(srv, con, hctx, p->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
+ /* destination exists */
+ if (0 == (r = stat(p->physical.path->ptr, &st))) {
+ if (S_ISDIR(st.st_mode)) {
+ /* file to dir/
+ * append basename to physical path */
+ destdir = 1;
+
+ if (NULL != (sep = strrchr(con->physical.path->ptr, '/'))) {
+ buffer_append_string(p->physical.path, sep);
+ r = stat(p->physical.path->ptr, &st);
+ }
+ }
+ }
+
+ if (-1 == r) {
+ con->http_status = destdir ? 204 : 201; /* we will create a new one */
+ con->file_finished = 1;
+
+ switch(errno) {
+ case ENOTDIR:
+ con->http_status = 409;
+ return HANDLER_FINISHED;
+ }
+ } else if (overwrite == 0) {
+ /* destination exists, but overwrite is not set */
+ con->http_status = 412;
+ return HANDLER_FINISHED;
+ } else {
+ con->http_status = 204; /* resource already existed */
+ }
+
+ if (con->request.http_method == HTTP_METHOD_MOVE) {
+ /* try a rename */
+
+ if (0 == rename(con->physical.path->ptr, p->physical.path->ptr)) {
+#ifdef USE_PROPPATCH
+ sqlite3_stmt *stmt;
+
+ stmt = p->conf.stmt_move_uri;
+ if (stmt) {
+
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->uri.path),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
+ }
+ }
+#endif
+ return HANDLER_FINISHED;
+ }
+
+ /* rename failed, fall back to COPY + DELETE */
+ }
+
+ if (0 != (r = webdav_copy_file(srv, con, hctx, &(con->physical), &(p->physical), overwrite))) {
+ con->http_status = r;
+
+ return HANDLER_FINISHED;
+ }
+
+ if (con->request.http_method == HTTP_METHOD_MOVE) {
+ b = buffer_init();
+ webdav_delete_file(srv, con, hctx, &(con->physical), b);
+ buffer_free(b);
+ }
+ }
+
+ return HANDLER_FINISHED;
+}
+
+static handler_t mod_webdav_proppatch(server *srv, connection *con, plugin_data *p, handler_ctx *hctx) {
+ struct stat st;
+ if (p->conf.is_readonly) {
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+
+ if (!webdav_has_lock(srv, con, hctx, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
+ /* check if destination exists */
+ if (-1 == stat(con->physical.path->ptr, &st)) {
+ switch(errno) {
+ case ENOENT:
+ con->http_status = 404;
+ break;
+ default:
+ con->http_status = 403;
+ break;
+ }
+ return HANDLER_FINISHED;
+ }
+
+ if (S_ISDIR(st.st_mode) && con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
+ http_response_redirect_to_directory(srv, con);
+ return HANDLER_FINISHED;
+ }
+
+#ifdef USE_PROPPATCH
+ if (con->request.content_length) {
+ xmlDocPtr xml;
+
+ if (con->state == CON_STATE_READ_POST) {
+ handler_t r = connection_handle_read_post_state(srv, con);
+ if (r != HANDLER_GO_ON) return r;
+ }
+
+ if (1 == webdav_parse_chunkqueue(srv, con, hctx, con->request_content_queue, &xml)) {
+ xmlNode *rootnode = xmlDocGetRootElement(xml);
+
+ if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propertyupdate")) {
+ xmlNode *cmd;
+ char *err = NULL;
+ int empty_ns = 0; /* send 400 on a empty namespace attribute */
+
+ /* start response */
+
+ if (SQLITE_OK != sqlite3_exec(p->conf.sql, "BEGIN TRANSACTION", NULL, NULL, &err)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
+ sqlite3_free(err);
+
+ goto propmatch_cleanup;
+ }
+
+ /* a UPDATE request, we know 'set' and 'remove' */
+ for (cmd = rootnode->children; cmd; cmd = cmd->next) {
+ xmlNode *props;
+ /* either set or remove */
+
+ if ((0 == xmlStrcmp(cmd->name, BAD_CAST "set")) ||
+ (0 == xmlStrcmp(cmd->name, BAD_CAST "remove"))) {
+
+ sqlite3_stmt *stmt;
+
+ stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
+ p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
+
+ for (props = cmd->children; props; props = props->next) {
+ if (0 == xmlStrcmp(props->name, BAD_CAST "prop")) {
+ xmlNode *prop;
+ char *propval = NULL;
+ int r;
+
+ prop = props->children;
+
+ if (prop->ns &&
+ (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
+ (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "no name space for:",
+ prop->name);
+
+ empty_ns = 1;
+ break;
+ }
+
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 2,
+ (char *)prop->name,
+ strlen((char *)prop->name),
+ SQLITE_TRANSIENT);
+ if (prop->ns) {
+ sqlite3_bind_text(stmt, 3,
+ (char *)prop->ns->href,
+ strlen((char *)prop->ns->href),
+ SQLITE_TRANSIENT);
+ } else {
+ sqlite3_bind_text(stmt, 3,
+ "",
+ 0,
+ SQLITE_TRANSIENT);
+ }
+ if (stmt == p->conf.stmt_update_prop) {
+ propval = prop->children
+ ? (char *)xmlNodeListGetString(xml, prop->children, 0)
+ : NULL;
+
+ sqlite3_bind_text(stmt, 4,
+ propval ? propval : "",
+ propval ? strlen(propval) : 0,
+ SQLITE_TRANSIENT);
+ }
+
+ if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "sql-set failed:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ if (propval) xmlFree(propval);
+ }
+ }
+ if (empty_ns) break;
+ }
+ }
+
+ if (empty_ns) {
+ if (SQLITE_OK != sqlite3_exec(p->conf.sql, "ROLLBACK", NULL, NULL, &err)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't rollback transaction:", err);
+ sqlite3_free(err);
+
+ goto propmatch_cleanup;
+ }
+
+ con->http_status = 400;
+ } else {
+ if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't commit transaction:", err);
+ sqlite3_free(err);
+
+ goto propmatch_cleanup;
+ }
+ con->http_status = 200;
+ }
+ con->file_finished = 1;
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+
+propmatch_cleanup:
+
+ xmlFreeDoc(xml);
+ } else {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ }
+#endif
+ con->http_status = 501;
+ return HANDLER_FINISHED;
+}
+
+#ifdef USE_LOCKS
+static handler_t mod_webdav_lock(server *srv, connection *con, plugin_data *p, handler_ctx *hctx) {
+ /**
+ * a mac wants to write
+ *
+ * LOCK /dav/expire.txt HTTP/1.1\r\n
+ * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
+ * Accept: * / *\r\n
+ * Depth: 0\r\n
+ * Timeout: Second-600\r\n
+ * Content-Type: text/xml; charset=\"utf-8\"\r\n
+ * Content-Length: 229\r\n
+ * Connection: keep-alive\r\n
+ * Host: 192.168.178.23:1025\r\n
+ * \r\n
+ * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
+ * <D:lockinfo xmlns:D=\"DAV:\">\n
+ * <D:lockscope><D:exclusive/></D:lockscope>\n
+ * <D:locktype><D:write/></D:locktype>\n
+ * <D:owner>\n
+ * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
+ * </D:owner>\n
+ * </D:lockinfo>\n
+ */
+
+ int depth = mod_webdav_depth(con);
+ if (depth != 0 && depth != -1) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+ if (con->request.content_length) {
+ xmlDocPtr xml;
+ buffer *hdr_if = NULL;
+ int created = 0;
+ struct stat st;
+
+ if (con->state == CON_STATE_READ_POST) {
+ handler_t r = connection_handle_read_post_state(srv, con);
+ if (r != HANDLER_GO_ON) return r;
+ }
+
+ hdr_if = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("If"));
+
+ if (0 != stat(con->physical.path->ptr, &st)) {
+ if (errno == ENOENT) {
+ int fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_APPEND|O_BINARY|FIFO_NONBLOCK, WEBDAV_FILE_MODE);
+ if (fd >= 0) {
+ close(fd);
+ created = 1;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sBss",
+ "create file", con->physical.path, ":", strerror(errno));
+ con->http_status = 403; /* Forbidden */
+
+ return HANDLER_FINISHED;
+ }
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sBss",
+ "stat", con->physical.path, ":", strerror(errno));
+ con->http_status = 403; /* Forbidden */
+ return HANDLER_FINISHED;
+ }
+ } else if (hdr_if == NULL && depth == -1) {
+ /* we don't support Depth: Infinity on directories */
+ if (S_ISDIR(st.st_mode)) {
+ con->http_status = 409; /* Conflict */
+
+ return HANDLER_FINISHED;
+ }
+ }
+
+ if (1 == webdav_parse_chunkqueue(srv, con, hctx, con->request_content_queue, &xml)) {
+ xmlNode *rootnode = xmlDocGetRootElement(xml);
+
+ force_assert(rootnode);
+
+ if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
+ xmlNode *lockinfo;
+ const xmlChar *lockscope = NULL, *locktype = NULL; /* TODO: compiler says unused: *owner = NULL; */
+
+ for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
+ if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
+ xmlNode *value;
+ for (value = lockinfo->children; value; value = value->next) {
+ if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
+ (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
+ lockscope = value->name;
+ } else {
+ con->http_status = 400;
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+ }
+ } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
+ xmlNode *value;
+ for (value = lockinfo->children; value; value = value->next) {
+ if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
+ locktype = value->name;
+ } else {
+ con->http_status = 400;
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+ }
+
+ } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
+ }
+ }
+
+ if (lockscope && locktype) {
+ sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
+
+ /* is this resourse already locked ? */
+
+ /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
+ * FROM locks
+ * WHERE resource = ? */
+
+ if (stmt) {
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+
+ /* it is the PK */
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ /* we found a lock
+ * 1. is it compatible ?
+ * 2. is it ours */
+ char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
+
+ if (strcmp(sql_lockscope, "exclusive")) {
+ con->http_status = 423;
+ } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
+ /* resourse is locked with a shared lock
+ * client wants exclusive */
+ con->http_status = 423;
+ }
+ }
+ if (con->http_status == 423) {
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+ }
+
+ stmt = p->conf.stmt_create_lock;
+ if (stmt) {
+ /* create a lock-token */
+ uuid_t id;
+ char uuid[37] /* 36 + \0 */;
+
+ uuid_generate(id);
+ uuid_unparse(id, uuid);
+
+ buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("opaquelocktoken:"));
+ buffer_append_string(p->tmp_buf, uuid);
+
+ /* "CREATE TABLE locks ("
+ * " locktoken TEXT NOT NULL,"
+ * " resource TEXT NOT NULL,"
+ * " lockscope TEXT NOT NULL,"
+ * " locktype TEXT NOT NULL,"
+ * " owner TEXT NOT NULL,"
+ * " depth INT NOT NULL,"
+ */
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->tmp_buf),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 3,
+ (const char *)lockscope,
+ xmlStrlen(lockscope),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 4,
+ (const char *)locktype,
+ xmlStrlen(locktype),
+ SQLITE_TRANSIENT);
+
+ /* owner */
+ sqlite3_bind_text(stmt, 5,
+ "",
+ 0,
+ SQLITE_TRANSIENT);
+
+ /* depth */
+ sqlite3_bind_int(stmt, 6,
+ depth);
+
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "create lock:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ /* looks like we survived */
+ webdav_lockdiscovery(con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth);
+
+ con->http_status = created ? 201 : 200;
+ con->file_finished = 1;
+ }
+ }
+ }
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ } else {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ } else {
+ buffer *b;
+ if (NULL != (b = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("If")))) {
+ buffer *locktoken = b;
+ sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
+
+ /* remove the < > around the token */
+ if (buffer_string_length(locktoken) < 5) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+ buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, buffer_string_length(locktoken) - 4);
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->tmp_buf),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "refresh lock:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ webdav_lockdiscovery(con, p->tmp_buf, "exclusive", "write", 0);
+
+ con->http_status = 200;
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ } else {
+ /* we need a lock-token to refresh */
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+ }
+}
+#endif
+
+#ifdef USE_LOCKS
+static handler_t mod_webdav_unlock(server *srv, connection *con, plugin_data *p) {
+ buffer *b;
+ if (NULL != (b = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Lock-Token")))) {
+ buffer *locktoken = b;
+ sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
+
+ /* remove the < > around the token */
+ if (buffer_string_length(locktoken) < 3) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+ /**
+ * FIXME:
+ *
+ * if the resourse is locked:
+ * - by us: unlock
+ * - by someone else: 401
+ * if the resource is not locked:
+ * - 412
+ * */
+
+ buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, buffer_string_length(locktoken) - 2);
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->tmp_buf),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "remove lock:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ if (0 == sqlite3_changes(p->conf.sql)) {
+ con->http_status = 401;
+ } else {
+ con->http_status = 204;
+ }
+ return HANDLER_FINISHED;
+ } else {
+ /* we need a lock-token to unlock */
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+}
+#endif
+
+SUBREQUEST_FUNC(mod_webdav_subrequest_handler_huge) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (!hctx->conf.enabled) return HANDLER_GO_ON;
+ /* physical path is setup */
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ switch (con->request.http_method) {
+ case HTTP_METHOD_PROPFIND:
+ return mod_webdav_propfind(srv, con, p, hctx);
+ case HTTP_METHOD_MKCOL:
+ return mod_webdav_mkcol(con, p);
+ case HTTP_METHOD_DELETE:
+ return mod_webdav_delete(srv, con, p, hctx);
+ case HTTP_METHOD_PUT:
+ return mod_webdav_put(srv, con, p, hctx);
+ case HTTP_METHOD_MOVE:
+ case HTTP_METHOD_COPY:
+ return mod_webdav_copymove(srv, con, p, hctx);
+ case HTTP_METHOD_PROPPATCH:
+ return mod_webdav_proppatch(srv, con, p, hctx);
+ #ifdef USE_LOCKS
+ case HTTP_METHOD_LOCK:
+ return mod_webdav_lock(srv, con, p, hctx);
+ case HTTP_METHOD_UNLOCK:
+ return mod_webdav_unlock(srv, con, p);
+ #else
+ case HTTP_METHOD_LOCK:
+ case HTTP_METHOD_UNLOCK:
+ con->http_status = 501;
+ return HANDLER_FINISHED;
+ #endif
+ default:
+ return HANDLER_GO_ON; /* not found */
+ }
+}
+
+
+SUBREQUEST_FUNC(mod_webdav_subrequest_handler) {
+ handler_t r;
+ plugin_data *p = p_d;
+ if (con->mode != p->id) return HANDLER_GO_ON;
+
+ r = mod_webdav_subrequest_handler_huge(srv, con, p_d);
+ if (con->http_status >= 400) con->mode = DIRECT;
+ return r;
+}
+
+
+PHYSICALPATH_FUNC(mod_webdav_physical_handler) {
+ plugin_data *p = p_d;
+ if (!p->conf.enabled) return HANDLER_GO_ON;
+
+ /* physical path is setup */
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ UNUSED(srv);
+
+ switch (con->request.http_method) {
+ case HTTP_METHOD_PROPFIND:
+ case HTTP_METHOD_PROPPATCH:
+ case HTTP_METHOD_PUT:
+ case HTTP_METHOD_COPY:
+ case HTTP_METHOD_MOVE:
+ case HTTP_METHOD_MKCOL:
+ case HTTP_METHOD_DELETE:
+ case HTTP_METHOD_LOCK:
+ case HTTP_METHOD_UNLOCK: {
+ handler_ctx *hctx = calloc(1, sizeof(*hctx));
+ memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
+ con->plugin_ctx[p->id] = hctx;
+ con->conf.stream_request_body = 0;
+ con->mode = p->id;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_webdav_connection_reset(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (hctx) {
+ free(hctx);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_webdav_plugin_init(plugin *p);
+int mod_webdav_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("webdav");
+
+ p->init = mod_webdav_init;
+ p->handle_uri_clean = mod_webdav_uri_handler;
+ p->handle_physical = mod_webdav_physical_handler;
+ p->handle_subrequest = mod_webdav_subrequest_handler;
+ p->connection_reset = mod_webdav_connection_reset;
+ p->set_defaults = mod_webdav_set_defaults;
+ p->cleanup = mod_webdav_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/mod_wstunnel.c b/data/lighttpd/lighttpd-1.4.53/src/mod_wstunnel.c
new file mode 100644
index 000000000..6843ace56
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/mod_wstunnel.c
@@ -0,0 +1,1363 @@
+/*
+ * mod_wstunnel originally based off https://github.com/nori0428/mod_websocket
+ * Portions of this module Copyright(c) 2017, Glenn Strauss, All rights reserved
+ * Portions of this module Copyright(c) 2010, Norio Kobota, All rights reserved.
+ */
+
+/*
+ * Copyright(c) 2010, Norio Kobota, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the 'incremental' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* NOTES:
+ *
+ * mod_wstunnel has been largely rewritten from Norio Kobota mod_websocket.
+ *
+ * highlighted differences from Norio Kobota mod_websocket
+ * - re-coded to use lighttpd 1.4.46 buffer, chunkqueue, and gw_backend APIs
+ * - websocket.server "ext" value is no longer regex;
+ * operates similar to mod_proxy for either path prefix or extension match
+ * - validation of "origins" value is no longer regex; operates as suffix match
+ * (admin could use lighttpd.conf regex on "Origin" or "Sec-WebSocket-Origin"
+ * and reject non-matches with mod_access if such regex validation required)
+ * - websocket transparent proxy mode removed; functionality is now in mod_proxy
+ * Backend server which responds to Connection: upgrade and Upgrade: websocket
+ * should check "Origin" and/or "Sec-WebSocket-Origin". lighttpd.conf could
+ * additionally be configured to check
+ * $REQUEST_HEADER["Sec-WebSocket-Origin"] !~ "..."
+ * with regex, and mod_access used to reject non-matches, if desired.
+ * - connections to backend no longer block, but only first address returned
+ * by getaddrinfo() is used; lighttpd does not cycle through all addresses
+ * returned by DNS resolution. Note: DNS resolution occurs once at startup.
+ * - directives renamed from websocket.* to wstunnel.*
+ * - directive websocket.ping_interval replaced with wstunnel.ping-interval
+ * (note the '_' changed to '-')
+ * - directive websocket.timeout should be replaced with server.max-read-idle
+ * - attribute "type" is an independent directive wstunnel.frame-type
+ * (default is "text" unless "binary" is specified)
+ * - attribute "origins" is an independent directive wstunnel.origins
+ * - attribute "proto" removed; mod_proxy can proxy to backend websocket server
+ * - attribute "subproto" should be replaced with mod_setenv directive
+ * setenv.set-response-header = ( "Sec-WebSocket-Protocol" => "..." )
+ * if header is required
+ *
+ * not reviewed:
+ * - websocket protocol compliance has not been reviewed
+ * e.g. when to send 1000 Normal Closure and when to send 1001 Going Away
+ * - websocket protocol sanity checking has not been reviewed
+ *
+ * References:
+ * https://en.wikipedia.org/wiki/WebSocket
+ * https://tools.ietf.org/html/rfc6455
+ * https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
+ */
+#include "first.h"
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gw_backend.h"
+
+#include "base.h"
+#include "array.h"
+#include "buffer.h"
+#include "chunk.h"
+#include "fdevent.h"
+#include "http_header.h"
+#include "joblist.h"
+#include "log.h"
+
+#define MOD_WEBSOCKET_LOG_NONE 0
+#define MOD_WEBSOCKET_LOG_ERR 1
+#define MOD_WEBSOCKET_LOG_WARN 2
+#define MOD_WEBSOCKET_LOG_INFO 3
+#define MOD_WEBSOCKET_LOG_DEBUG 4
+
+#define DEBUG_LOG(level, format, ...) \
+ if (hctx->gw.conf.debug >= (level)) { \
+ log_error_write(hctx->srv, __FILE__, __LINE__, (format), __VA_ARGS__); \
+ }
+
+typedef struct {
+ gw_plugin_config gw;
+ buffer *frame_type;
+ array *origins;
+ unsigned int ping_interval;
+} plugin_config;
+
+typedef struct plugin_data {
+ PLUGIN_DATA;
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+typedef enum {
+ MOD_WEBSOCKET_FRAME_STATE_INIT,
+
+ /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+ MOD_WEBSOCKET_FRAME_STATE_READ_LENGTH,
+ MOD_WEBSOCKET_FRAME_STATE_READ_EX_LENGTH,
+ MOD_WEBSOCKET_FRAME_STATE_READ_MASK,
+ /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+
+ MOD_WEBSOCKET_FRAME_STATE_READ_PAYLOAD
+} mod_wstunnel_frame_state_t;
+
+typedef enum {
+ MOD_WEBSOCKET_FRAME_TYPE_TEXT,
+ MOD_WEBSOCKET_FRAME_TYPE_BIN,
+ MOD_WEBSOCKET_FRAME_TYPE_CLOSE,
+
+ /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+ MOD_WEBSOCKET_FRAME_TYPE_PING,
+ MOD_WEBSOCKET_FRAME_TYPE_PONG
+ /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+
+} mod_wstunnel_frame_type_t;
+
+typedef struct {
+ uint64_t siz;
+
+ /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+ int siz_cnt;
+ int mask_cnt;
+ #define MOD_WEBSOCKET_MASK_CNT 4
+ unsigned char mask[MOD_WEBSOCKET_MASK_CNT];
+ /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+
+} mod_wstunnel_frame_control_t;
+
+typedef struct {
+ mod_wstunnel_frame_state_t state;
+ mod_wstunnel_frame_control_t ctl;
+ mod_wstunnel_frame_type_t type, type_before, type_backend;
+ buffer *payload;
+} mod_wstunnel_frame_t;
+
+typedef struct {
+ gw_handler_ctx gw;
+ mod_wstunnel_frame_t frame;
+
+ int hybivers;
+ time_t ping_ts;
+ int subproto;
+
+ server *srv; /*(for mod_wstunnel module-specific DEBUG_LOG() macro)*/
+ plugin_config conf;
+} handler_ctx;
+
+/* prototypes */
+static handler_t mod_wstunnel_handshake_create_response(handler_ctx *);
+static int mod_wstunnel_frame_send(handler_ctx *, mod_wstunnel_frame_type_t, const char *, size_t);
+static int mod_wstunnel_frame_recv(handler_ctx *);
+#define _MOD_WEBSOCKET_SPEC_IETF_00_
+#define _MOD_WEBSOCKET_SPEC_RFC_6455_
+
+INIT_FUNC(mod_wstunnel_init) {
+ return calloc(1, sizeof(plugin_data));
+}
+
+FREE_FUNC(mod_wstunnel_free) {
+ plugin_data *p = p_d;
+ if (p->config_storage) {
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ plugin_config *s = p->config_storage[i];
+ if (NULL == s) continue;
+ buffer_free(s->frame_type);
+ array_free(s->origins);
+ /*assert(0 == offsetof(s->gw));*/
+ gw_plugin_config_free(&s->gw);
+ /*free(s);*//*free'd by gw_plugin_config_free()*/
+ }
+ free(p->config_storage);
+ }
+ free(p);
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_wstunnel_set_defaults) {
+ plugin_data *p = p_d;
+ data_unset *du;
+ config_values_t cv[] = {
+ { "wstunnel.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },
+ { "wstunnel.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "wstunnel.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },
+ { "wstunnel.map-extensions",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "wstunnel.frame-type", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_CONNECTION },
+ { "wstunnel.origins", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ { "wstunnel.ping-interval", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
+ force_assert(p->config_storage);
+ for (size_t i = 0; i < srv->config_context->used; ++i) {
+ array *ca = ((data_config *)(srv->config_context->data[i]))->value;
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+ force_assert(s);
+
+ s->gw.debug = 0; /* MOD_WEBSOCKET_LOG_NONE */
+ s->gw.ext_mapping = array_init();
+ s->frame_type = buffer_init();
+ s->origins = array_init();
+ s->ping_interval = 0; /* do not send ping */
+
+ cv[0].destination = NULL; /* T_CONFIG_LOCAL */
+ cv[1].destination = &(s->gw.debug);
+ cv[2].destination = NULL; /* T_CONFIG_LOCAL */
+ cv[3].destination = s->gw.ext_mapping;
+ cv[4].destination = s->frame_type;
+ cv[5].destination = s->origins;
+ cv[6].destination = &(s->ping_interval);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ca, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(ca, "wstunnel.server");
+ if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, du, i, 0)) {
+ return HANDLER_ERROR;
+ }
+
+ du = array_get_element(ca, "wstunnel.balance");
+ if (!gw_set_defaults_balance(srv, &s->gw, du)) {
+ return HANDLER_ERROR;
+ }
+
+ /* disable check-local for all exts (default enabled) */
+ if (s->gw.exts) { /*(check after gw_set_defaults_backend())*/
+ for (size_t j = 0; j < s->gw.exts->used; ++j) {
+ gw_extension *ex = s->gw.exts->exts[j];
+ for (size_t n = 0; n < ex->used; ++n) {
+ ex->hosts[n]->check_local = 0;
+ }
+ }
+ }
+
+ /* error if "mode" = "authorizer"; wstunnel can not act as authorizer */
+ /*(check after gw_set_defaults_backend())*/
+ if (s->gw.exts_auth && s->gw.exts_auth->used) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "wstunnel.server must not define any hosts "
+ "with attribute \"mode\" = \"authorizer\"");
+ return HANDLER_ERROR;
+ }
+
+ /*(default frame-type to "text" unless "binary" is specified)*/
+ if (!buffer_is_empty(s->frame_type)
+ && !buffer_is_equal_caseless_string(s->frame_type,
+ CONST_STR_LEN("binary"))) {
+ buffer_clear(s->frame_type);
+ }
+
+ if (!array_is_vlist(s->origins)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for wstunnel.origins; expected wstunnel.origins = ( \"...\", \"...\" )");
+ return HANDLER_ERROR;
+ }
+ for (size_t j = 0; j < s->origins->used; ++j) {
+ if (buffer_string_is_empty(((data_string *)s->origins->data[j])->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected empty string in wstunnel.origins");
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+ /*assert(0 == offsetof(s->gw));*/
+ return HANDLER_GO_ON;
+}
+
+static handler_t wstunnel_create_env(server *srv, gw_handler_ctx *gwhctx) {
+ handler_ctx *hctx = (handler_ctx *)gwhctx;
+ connection *con = hctx->gw.remote_conn;
+ handler_t rc;
+ if (0 == con->request.content_length) {
+ http_response_upgrade_read_body_unknown(srv, con);
+ chunkqueue_append_chunkqueue(con->request_content_queue,
+ con->read_queue);
+ }
+ rc = mod_wstunnel_handshake_create_response(hctx);
+ if (rc != HANDLER_GO_ON) return rc;
+
+ con->http_status = 101; /* Switching Protocols */
+ con->file_started = 1;
+
+ hctx->ping_ts = srv->cur_ts;
+ gw_set_transparent(srv, &hctx->gw);
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t wstunnel_stdin_append(server *srv, gw_handler_ctx *gwhctx) {
+ /* prepare websocket frames to backend */
+ /* (caller should verify con->request_content_queue) */
+ /*assert(!chunkqueue_is_empty(con->request_content_queue));*/
+ handler_ctx *hctx = (handler_ctx *)gwhctx;
+ if (0 == mod_wstunnel_frame_recv(hctx))
+ return HANDLER_GO_ON;
+ else {
+ /*(error)*/
+ /* future: might differentiate client close request from client error,
+ * and then send 1000 or 1001 */
+ connection *con = hctx->gw.remote_conn;
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "sds",
+ "disconnected from client ( fd =", con->fd, ")");
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sds",
+ "send close response to client ( fd =", con->fd, ")");
+ mod_wstunnel_frame_send(hctx, MOD_WEBSOCKET_FRAME_TYPE_CLOSE, CONST_STR_LEN("1000")); /* 1000 Normal Closure */
+ gw_connection_reset(srv, con, hctx->gw.plugin_data);
+ return HANDLER_FINISHED;
+ }
+}
+
+static handler_t wstunnel_recv_parse(server *srv, connection *con, http_response_opts *opts, buffer *b, size_t n) {
+ handler_ctx *hctx = (handler_ctx *)opts->pdata;
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sdsx",
+ "recv data from backend ( fd =", hctx->gw.fd, "), size =", n);
+ if (0 == n) return HANDLER_FINISHED;
+ if (mod_wstunnel_frame_send(hctx,hctx->frame.type_backend,b->ptr,n) < 0) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "fail to send data to client");
+ return HANDLER_ERROR;
+ }
+ buffer_clear(b);
+ UNUSED(srv);
+ UNUSED(con);
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) p->conf.x = s->x
+#define PATCH_GW(x) p->conf.gw.x = s->gw.x
+static void mod_wstunnel_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH_GW(exts);
+ PATCH_GW(exts_auth);
+ PATCH_GW(exts_resp);
+ PATCH_GW(debug);
+ PATCH_GW(balance);
+ PATCH_GW(ext_mapping);
+ PATCH(frame_type);
+ PATCH(origins);
+ PATCH(ping_interval);
+
+ /* 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("wstunnel.server"))) {
+ PATCH_GW(exts);
+ /*(wstunnel can not act as authorizer,
+ * but p->conf.exts_auth must not be NULL)*/
+ PATCH_GW(exts_auth);
+ PATCH_GW(exts_resp);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("wstunnel.debug"))) {
+ PATCH_GW(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("wstunnel.balance"))) {
+ PATCH_GW(balance);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("wstunnel.map-extensions"))) {
+ PATCH_GW(ext_mapping);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("wstunnel.frame-type"))) {
+ PATCH(frame_type);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("wstunnel.origins"))) {
+ PATCH(origins);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("wstunnel.ping-interval"))) {
+ PATCH(ping_interval);
+ }
+ }
+ }
+}
+#undef PATCH_GW
+#undef PATCH
+
+static int header_contains_token (buffer *b, const char *m, size_t mlen)
+{
+ for (char *s = b->ptr; s; s = strchr(s, ',')) {
+ while (*s == ' ' || *s == '\t' || *s == ',') ++s;
+ if (0 == strncasecmp(s, m, mlen)) {
+ s += mlen;
+ if (*s == '\0' || *s == ' ' || *s == '\t' || *s == ',' || *s == ';')
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int wstunnel_is_allowed_origin(connection *con, handler_ctx *hctx) {
+ /* If allowed origins is set (and not empty list), fail closed if no match.
+ * Note that origin provided in request header has not been normalized, so
+ * change in case or other non-normal forms might not match allowed list */
+ const array * const allowed_origins = hctx->conf.origins;
+ buffer *origin = NULL;
+ size_t olen;
+
+ if (0 == allowed_origins->used) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "s", "allowed origins not specified");
+ return 1;
+ }
+
+ /* "Origin" header is preferred
+ * ("Sec-WebSocket-Origin" is from older drafts of websocket spec) */
+ origin = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Origin"));
+ if (NULL == origin) {
+ origin =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Origin"));
+ }
+ olen = buffer_string_length(origin);
+ if (0 == olen) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "Origin header is invalid");
+ con->http_status = 400; /* Bad Request */
+ return 0;
+ }
+
+ for (size_t i = 0; i < allowed_origins->used; ++i) {
+ buffer *b = ((data_string *)allowed_origins->data[i])->value;
+ size_t blen = buffer_string_length(b);
+ if ((olen > blen ? origin->ptr[olen-blen-1] == '.' : olen == blen)
+ && buffer_is_equal_right_len(origin, b, blen)) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "bsb",
+ origin, "matches allowed origin:", b);
+ return 1;
+ }
+ }
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "bs",
+ origin, "does not match any allowed origins");
+ con->http_status = 403; /* Forbidden */
+ return 0;
+}
+
+static int wstunnel_check_request(connection *con, handler_ctx *hctx) {
+ const buffer * const vers =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Version"));
+ const long hybivers = (NULL != vers) ? strtol(vers->ptr, NULL, 10) : 0;
+ if (hybivers < 0 || hybivers > INT_MAX) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "invalid Sec-WebSocket-Version");
+ con->http_status = 400; /* Bad Request */
+ return -1;
+ }
+
+ /*(redundant since HTTP/1.1 required in mod_wstunnel_check_extension())*/
+ if (buffer_is_empty(con->request.http_host)) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "Host header does not exist");
+ con->http_status = 400; /* Bad Request */
+ return -1;
+ }
+
+ if (!wstunnel_is_allowed_origin(con, hctx)) {
+ return -1;
+ }
+
+ return (int)hybivers;
+}
+
+static void wstunnel_backend_error(gw_handler_ctx *gwhctx) {
+ handler_ctx *hctx = (handler_ctx *)gwhctx;
+ if (hctx->gw.state == GW_STATE_WRITE || hctx->gw.state == GW_STATE_READ) {
+ mod_wstunnel_frame_send(hctx, MOD_WEBSOCKET_FRAME_TYPE_CLOSE, CONST_STR_LEN("1001")); /* 1001 Going Away */
+ }
+}
+
+static void wstunnel_handler_ctx_free(void *gwhctx) {
+ handler_ctx *hctx = (handler_ctx *)gwhctx;
+ chunk_buffer_release(hctx->frame.payload);
+}
+
+static handler_t wstunnel_handler_setup (server *srv, connection *con, plugin_data *p) {
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ int binary;
+ int hybivers;
+ hctx->srv = srv; /*(for mod_wstunnel module-specific DEBUG_LOG() macro)*/
+ hctx->conf = p->conf; /*(copies struct)*/
+ hybivers = wstunnel_check_request(con, hctx);
+ if (hybivers < 0) return HANDLER_FINISHED;
+ hctx->hybivers = hybivers;
+ if (0 == hybivers) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO,"s","WebSocket Version = hybi-00");
+ }
+ else {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO,"sd","WebSocket Version =",hybivers);
+ }
+
+ hctx->gw.opts.backend = BACKEND_PROXY; /*(act proxy-like; not used)*/
+ hctx->gw.opts.pdata = hctx;
+ hctx->gw.opts.parse = wstunnel_recv_parse;
+ hctx->gw.stdin_append = wstunnel_stdin_append;
+ hctx->gw.create_env = wstunnel_create_env;
+ hctx->gw.handler_ctx_free = wstunnel_handler_ctx_free;
+ hctx->gw.backend_error = wstunnel_backend_error;
+ hctx->gw.response = chunk_buffer_acquire();
+
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_INIT;
+ hctx->frame.ctl.siz = 0;
+ hctx->frame.payload = chunk_buffer_acquire();
+
+ binary = !buffer_is_empty(hctx->conf.frame_type); /*("binary")*/
+ if (!binary) {
+ buffer *vb =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Protocol"));
+ if (NULL != vb) {
+ for (const char *s = vb->ptr; *s; ++s) {
+ while (*s==' '||*s=='\t'||*s=='\r'||*s=='\n') ++s;
+ if (0 == strncasecmp(s, "binary", sizeof("binary")-1)) {
+ s += sizeof("binary")-1;
+ while (*s==' '||*s=='\t'||*s=='\r'||*s=='\n') ++s;
+ if (*s==','||*s=='\0') {
+ hctx->subproto = 1;
+ binary = 1;
+ break;
+ }
+ }
+ else if (0 == strncasecmp(s, "base64", sizeof("base64")-1)) {
+ s += sizeof("base64")-1;
+ while (*s==' '||*s=='\t'||*s=='\r'||*s=='\n') ++s;
+ if (*s==','||*s=='\0') {
+ hctx->subproto = -1;
+ break;
+ }
+ }
+ s = strchr(s, ',');
+ if (NULL == s) break;
+ }
+ }
+ }
+
+ if (binary) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "s",
+ "will recv binary data from backend");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_BIN;
+ hctx->frame.type_before = MOD_WEBSOCKET_FRAME_TYPE_BIN;
+ hctx->frame.type_backend = MOD_WEBSOCKET_FRAME_TYPE_BIN;
+ }
+ else {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "s",
+ "will recv text data from backend");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_TEXT;
+ hctx->frame.type_before = MOD_WEBSOCKET_FRAME_TYPE_TEXT;
+ hctx->frame.type_backend = MOD_WEBSOCKET_FRAME_TYPE_TEXT;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static handler_t mod_wstunnel_check_extension(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *vb;
+ handler_t rc;
+
+ if (con->mode != DIRECT)
+ return HANDLER_GO_ON;
+ if (con->request.http_method != HTTP_METHOD_GET)
+ return HANDLER_GO_ON;
+ if (con->request.http_version != HTTP_VERSION_1_1)
+ return HANDLER_GO_ON;
+
+ /*
+ * Connection: upgrade, keep-alive, ...
+ * Upgrade: WebSocket, ...
+ */
+ vb = http_header_request_get(con, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade"));
+ if (NULL == vb
+ || !header_contains_token(vb, CONST_STR_LEN("websocket")))
+ return HANDLER_GO_ON;
+ vb = http_header_request_get(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"));
+ if (NULL == vb
+ || !header_contains_token(vb, CONST_STR_LEN("upgrade")))
+ return HANDLER_GO_ON;
+
+ mod_wstunnel_patch_connection(srv, con, p);
+ if (NULL == p->conf.gw.exts) return HANDLER_GO_ON;
+
+ rc = gw_check_extension(srv,con,(gw_plugin_data *)p,1,sizeof(handler_ctx));
+ return (HANDLER_GO_ON == rc && con->mode == p->id)
+ ? wstunnel_handler_setup(srv, con, p)
+ : rc;
+}
+
+TRIGGER_FUNC(mod_wstunnel_handle_trigger) {
+ const plugin_data * const p = p_d;
+ const time_t cur_ts = srv->cur_ts + 1;
+
+ gw_handle_trigger(srv, p_d);
+
+ for (size_t i = 0; i < srv->conns->used; ++i) {
+ connection *con = srv->conns->ptr[i];
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx || con->mode != p->id)
+ continue;
+
+ if (hctx->gw.state != GW_STATE_WRITE && hctx->gw.state != GW_STATE_READ)
+ continue;
+
+ if (cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_INFO, "sds",
+ "timeout client ( fd =", con->fd, ")");
+ mod_wstunnel_frame_send(hctx, MOD_WEBSOCKET_FRAME_TYPE_CLOSE, NULL, 0);
+ gw_connection_reset(srv, con, p_d);
+ joblist_append(srv, con);
+ /* avoid server.c closing connection with error due to max_read_idle
+ * (might instead run joblist after plugins_call_handle_trigger())*/
+ con->read_idle_ts = cur_ts;
+ continue;
+ }
+
+ if (0 != hctx->hybivers
+ && hctx->conf.ping_interval > 0
+ && (time_t)hctx->conf.ping_interval + hctx->ping_ts < cur_ts) {
+ hctx->ping_ts = cur_ts;
+ mod_wstunnel_frame_send(hctx, MOD_WEBSOCKET_FRAME_TYPE_PING, CONST_STR_LEN("ping"));
+ joblist_append(srv, con);
+ continue;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+int mod_wstunnel_plugin_init(plugin *p);
+int mod_wstunnel_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("wstunnel");
+ p->init = mod_wstunnel_init;
+ p->cleanup = mod_wstunnel_free;
+ p->set_defaults = mod_wstunnel_set_defaults;
+ p->connection_reset = gw_connection_reset;
+ p->handle_uri_clean = mod_wstunnel_check_extension;
+ p->handle_subrequest = gw_handle_subrequest;
+ p->handle_trigger = mod_wstunnel_handle_trigger;
+ p->handle_waitpid = gw_handle_waitpid_cb;
+ p->data = NULL;
+ return 0;
+}
+
+
+
+
+/*
+ * modified from Norio Kobota mod_websocket_handshake.c
+ */
+
+#ifdef _MOD_WEBSOCKET_SPEC_IETF_00_
+
+#include "sys-endian.h" /* lighttpd */
+#include "md5.h" /* lighttpd */
+
+static int get_key3(connection *con, char *buf) {
+ /* 8 bytes should have been sent with request
+ * for draft-ietf-hybi-thewebsocketprotocol-00 */
+ chunkqueue *cq = con->request_content_queue;
+ size_t bytes = 8;
+ /*(caller should ensure bytes available prior to calling this routine)*/
+ /*assert(chunkqueue_length(cq) >= 8);*/
+ for (chunk *c = cq->first; NULL != c; c = c->next) {
+ /*(chunk_remaining_length() on MEM_CHUNK)*/
+ size_t n = (size_t)(buffer_string_length(c->mem) - c->offset);
+ /*(expecting 8 bytes to be in memory directly after headers)*/
+ if (c->type != MEM_CHUNK) break; /* FILE_CHUNK not handled here */
+ if (n > bytes) n = bytes;
+ memcpy(buf, c->mem->ptr+c->offset, n);
+ buf += n;
+ if (0 == (bytes -= n)) break;
+ }
+ if (0 != bytes) return -1;
+ chunkqueue_mark_written(cq, 8);
+ return 0;
+}
+
+static int get_key_number(uint32_t *ret, const buffer *b) {
+ const char * const s = b->ptr;
+ size_t j = 0;
+ unsigned long n;
+ uint32_t sp = 0;
+ char tmp[10 + 1]; /* #define UINT32_MAX_STRLEN 10 */
+
+ for (size_t i = 0, used = buffer_string_length(b); i < used; ++i) {
+ if (light_isdigit(s[i])) {
+ tmp[j] = s[i];
+ if (++j >= sizeof(tmp)) return -1;
+ }
+ else if (s[i] == ' ') ++sp; /* count num spaces */
+ }
+ tmp[j] = '\0';
+ n = strtoul(tmp, NULL, 10);
+ if (n > UINT32_MAX || 0 == sp) return -1;
+ *ret = (uint32_t)n / sp;
+ return 0;
+}
+
+static int create_MD5_sum(connection *con) {
+ uint32_t buf[4]; /* MD5 binary hash len */
+ li_MD5_CTX ctx;
+
+ const buffer *key1 =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Key1"));
+ const buffer *key2 =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Key2"));
+
+ if (NULL == key1 || get_key_number(buf+0, key1) < 0 ||
+ NULL == key2 || get_key_number(buf+1, key2) < 0 ||
+ get_key3(con, (char *)(buf+2)) < 0) {
+ return -1;
+ }
+ #ifdef __BIG_ENDIAN__
+ #define ws_htole32(s,u)\
+ (s)[0]=((u)>>24); \
+ (s)[1]=((u)>>16); \
+ (s)[2]=((u)>>8); \
+ (s)[3]=((u))
+ ws_htole32((unsigned char *)(buf+0), buf[0]);
+ ws_htole32((unsigned char *)(buf+1), buf[1]);
+ #endif
+ li_MD5_Init(&ctx);
+ li_MD5_Update(&ctx, buf, sizeof(buf));
+ li_MD5_Final((unsigned char *)buf, &ctx); /*(overwrite buf[] with result)*/
+ chunkqueue_append_mem(con->write_queue, (char *)buf, sizeof(buf));
+ return 0;
+}
+
+static int create_response_ietf_00(handler_ctx *hctx) {
+ connection *con = hctx->gw.remote_conn;
+ buffer *value = hctx->srv->tmp_buf;
+
+ /* "Origin" header is preferred
+ * ("Sec-WebSocket-Origin" is from older drafts of websocket spec) */
+ buffer *origin = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Origin"));
+ if (NULL == origin) {
+ origin =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Origin"));
+ }
+ if (NULL == origin) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "Origin header is invalid");
+ return -1;
+ }
+ if (buffer_is_empty(con->request.http_host)) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "Host header does not exist");
+ return -1;
+ }
+
+ /* calc MD5 sum from keys */
+ if (create_MD5_sum(con) < 0) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "Sec-WebSocket-Key is invalid");
+ return -1;
+ }
+
+ http_header_response_set(con, HTTP_HEADER_UPGRADE,
+ CONST_STR_LEN("Upgrade"),
+ CONST_STR_LEN("websocket"));
+ #if 0 /*(added later in http_response_write_header())*/
+ http_header_response_append(con, HTTP_HEADER_CONNECTION,
+ CONST_STR_LEN("Connection"),
+ CONST_STR_LEN("upgrade"));
+ #endif
+ #if 0 /*(Sec-WebSocket-Origin header is not required for hybi-00)*/
+ /* Note: it is insecure to simply reflect back origin provided by client
+ * (if admin did not configure restricted list of valid origins)
+ * (see wstunnel_check_request()) */
+ http_header_response_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("Sec-WebSocket-Origin"),
+ CONST_BUF_LEN(origin));
+ #endif
+
+ if (buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https")))
+ buffer_copy_string_len(value, CONST_STR_LEN("wss://"));
+ else
+ buffer_copy_string_len(value, CONST_STR_LEN("ws://"));
+ buffer_append_string_buffer(value, con->request.http_host);
+ buffer_append_string_buffer(value, con->uri.path);
+ http_header_response_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("Sec-WebSocket-Location"),
+ CONST_BUF_LEN(value));
+
+ return 0;
+}
+
+#endif /* _MOD_WEBSOCKET_SPEC_IETF_00_ */
+
+
+#ifdef _MOD_WEBSOCKET_SPEC_RFC_6455_
+
+#include "algo_sha1.h" /* lighttpd */
+#include "base64.h" /* lighttpd */
+
+static int create_response_rfc_6455(handler_ctx *hctx) {
+ connection *con = hctx->gw.remote_conn;
+ SHA_CTX sha;
+ unsigned char sha_digest[SHA_DIGEST_LENGTH];
+
+ buffer *value =
+ http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Key"));
+ if (NULL == value) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "Sec-WebSocket-Key is invalid");
+ return -1;
+ }
+
+ /* get SHA1 hash of key */
+ /* refer: RFC-6455 Sec.1.3 Opening Handshake */
+ SHA1_Init(&sha);
+ SHA1_Update(&sha, (const unsigned char *)CONST_BUF_LEN(value));
+ SHA1_Update(&sha, (const unsigned char *)CONST_STR_LEN("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
+ SHA1_Final(sha_digest, &sha);
+
+ http_header_response_set(con, HTTP_HEADER_UPGRADE,
+ CONST_STR_LEN("Upgrade"),
+ CONST_STR_LEN("websocket"));
+ #if 0 /*(added later in http_response_write_header())*/
+ http_header_response_append(con, HTTP_HEADER_CONNECTION,
+ CONST_STR_LEN("Connection"),
+ CONST_STR_LEN("upgrade"));
+ #endif
+
+ value = hctx->srv->tmp_buf;
+ buffer_clear(value);
+ buffer_append_base64_encode(value, sha_digest, SHA_DIGEST_LENGTH, BASE64_STANDARD);
+ http_header_response_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("Sec-WebSocket-Accept"),
+ CONST_BUF_LEN(value));
+
+ if (hctx->frame.type == MOD_WEBSOCKET_FRAME_TYPE_BIN)
+ http_header_response_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("Sec-WebSocket-Protocol"),
+ CONST_STR_LEN("binary"));
+ else if (-1 == hctx->subproto)
+ http_header_response_set(con, HTTP_HEADER_OTHER,
+ CONST_STR_LEN("Sec-WebSocket-Protocol"),
+ CONST_STR_LEN("base64"));
+
+ return 0;
+}
+
+#endif /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+
+
+handler_t mod_wstunnel_handshake_create_response(handler_ctx *hctx) {
+ connection *con = hctx->gw.remote_conn;
+ #ifdef _MOD_WEBSOCKET_SPEC_RFC_6455_
+ if (hctx->hybivers >= 8) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "send handshake response");
+ if (0 != create_response_rfc_6455(hctx)) {
+ con->http_status = 400; /* Bad Request */
+ return HANDLER_ERROR;
+ }
+ return HANDLER_GO_ON;
+ }
+ #endif /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+
+ #ifdef _MOD_WEBSOCKET_SPEC_IETF_00_
+ if (hctx->hybivers == 0) {
+ #ifdef _MOD_WEBSOCKET_SPEC_IETF_00_
+ /* 8 bytes should have been sent with request
+ * for draft-ietf-hybi-thewebsocketprotocol-00 */
+ chunkqueue *cq = con->request_content_queue;
+ if (0 == hctx->hybivers && chunkqueue_length(cq) < 8)
+ return HANDLER_WAIT_FOR_EVENT;
+ #endif /* _MOD_WEBSOCKET_SPEC_IETF_00_ */
+
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "send handshake response");
+ if (0 != create_response_ietf_00(hctx)) {
+ con->http_status = 400; /* Bad Request */
+ return HANDLER_ERROR;
+ }
+ return HANDLER_GO_ON;
+ }
+ #endif /* _MOD_WEBSOCKET_SPEC_IETF_00_ */
+
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "not supported WebSocket Version");
+ con->http_status = 503; /* Service Unavailable */
+ return HANDLER_ERROR;
+}
+
+
+
+
+/*
+ * modified from Norio Kobota mod_websocket_frame.c
+ */
+
+#include "base64.h" /* lighttpd */
+#include "http_chunk.h" /* lighttpd */
+
+#define MOD_WEBSOCKET_BUFMAX (0x0fffff)
+
+#ifdef _MOD_WEBSOCKET_SPEC_IETF_00_
+
+#include <stdlib.h>
+static int send_ietf_00(handler_ctx *hctx, mod_wstunnel_frame_type_t type, const char *payload, size_t siz) {
+ static const char head = 0; /* 0x00 */
+ static const char tail = ~0; /* 0xff */
+ server *srv = hctx->srv;
+ connection *con = hctx->gw.remote_conn;
+ char *mem;
+ size_t len;
+
+ switch (type) {
+ case MOD_WEBSOCKET_FRAME_TYPE_TEXT:
+ if (0 == siz) return 0;
+ http_chunk_append_mem(srv, con, &head, 1);
+ http_chunk_append_mem(srv, con, payload, siz);
+ http_chunk_append_mem(srv, con, &tail, 1);
+ len = siz+2;
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_BIN:
+ if (0 == siz) return 0;
+ http_chunk_append_mem(srv, con, &head, 1);
+ len = 4*(siz/3)+4+1;
+ /* avoid accumulating too much data in memory; send to tmpfile */
+ mem = malloc(len);
+ force_assert(mem);
+ len=li_to_base64(mem,len,(unsigned char *)payload,siz,BASE64_STANDARD);
+ http_chunk_append_mem(srv, con, mem, len);
+ free(mem);
+ http_chunk_append_mem(srv, con, &tail, 1);
+ len += 2;
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_CLOSE:
+ http_chunk_append_mem(srv, con, &tail, 1);
+ http_chunk_append_mem(srv, con, &head, 1);
+ len = 2;
+ break;
+ default:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "invalid frame type");
+ return -1;
+ }
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sdsx",
+ "send data to client ( fd =", con->fd, "), frame size =", len);
+ return 0;
+}
+
+static int recv_ietf_00(handler_ctx *hctx) {
+ connection *con = hctx->gw.remote_conn;
+ chunkqueue *cq = con->request_content_queue;
+ buffer *payload = hctx->frame.payload;
+ char *mem;
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sdsx",
+ "recv data from client ( fd =", con->fd,
+ "), size =", chunkqueue_length(cq));
+ for (chunk *c = cq->first; c; c = c->next) {
+ char *frame = c->mem->ptr+c->offset;
+ /*(chunk_remaining_length() on MEM_CHUNK)*/
+ size_t flen = (size_t)(buffer_string_length(c->mem) - c->offset);
+ /*(FILE_CHUNK not handled, but might need to add support)*/
+ force_assert(c->type == MEM_CHUNK);
+ for (size_t i = 0; i < flen; ) {
+ switch (hctx->frame.state) {
+ case MOD_WEBSOCKET_FRAME_STATE_INIT:
+ hctx->frame.ctl.siz = 0;
+ if (frame[i] == 0x00) {
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_READ_PAYLOAD;
+ i++;
+ }
+ else if (((unsigned char *)frame)[i] == 0xff) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG,"s","recv close frame");
+ return -1;
+ }
+ else {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG,"s","recv invalid frame");
+ return -1;
+ }
+ break;
+ case MOD_WEBSOCKET_FRAME_STATE_READ_PAYLOAD:
+ mem = (char *)memchr(frame+i, 0xff, flen - i);
+ if (mem == NULL) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "got continuous payload, size =", flen - i);
+ hctx->frame.ctl.siz += flen - i;
+ if (hctx->frame.ctl.siz > MOD_WEBSOCKET_BUFMAX) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_WARN, "sx",
+ "frame size has been exceeded:",
+ MOD_WEBSOCKET_BUFMAX);
+ return -1;
+ }
+ buffer_append_string_len(payload, frame+i, flen - i);
+ i += flen - i;
+ }
+ else {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "got final payload, size =", (mem - frame+i));
+ hctx->frame.ctl.siz += (mem - frame+i);
+ if (hctx->frame.ctl.siz > MOD_WEBSOCKET_BUFMAX) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_WARN, "sx",
+ "frame size has been exceeded:",
+ MOD_WEBSOCKET_BUFMAX);
+ return -1;
+ }
+ buffer_append_string_len(payload, frame+i, mem - frame+i);
+ i += (mem - frame+i);
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_INIT;
+ }
+ i++;
+ if (hctx->frame.type == MOD_WEBSOCKET_FRAME_TYPE_TEXT
+ && !buffer_is_empty(payload)) {
+ hctx->frame.ctl.siz = 0;
+ chunkqueue_append_buffer(hctx->gw.wb, payload);
+ buffer_clear(payload);
+ }
+ else {
+ if (hctx->frame.state == MOD_WEBSOCKET_FRAME_STATE_INIT
+ && !buffer_is_empty(payload)) {
+ buffer *b;
+ size_t len = buffer_string_length(payload);
+ len = (len+3)/4*3+1;
+ chunkqueue_get_memory(hctx->gw.wb, &len);
+ b = hctx->gw.wb->last->mem;
+ len = buffer_string_length(b);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "ss",
+ "try to base64 decode:", payload->ptr);
+ if (NULL == buffer_append_base64_decode(b, CONST_BUF_LEN(payload), BASE64_STANDARD)) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s",
+ "fail to base64-decode");
+ return -1;
+ }
+ buffer_clear(payload);
+ /*chunkqueue_use_memory()*/
+ hctx->gw.wb->bytes_in += buffer_string_length(b)-len;
+ }
+ }
+ break;
+ default: /* never reach */
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR,"s", "BUG: unknown state");
+ return -1;
+ }
+ }
+ }
+ /* XXX: should add ability to handle and preserve partial frames above */
+ /*(not chunkqueue_reset(); do not reset cq->bytes_in, cq->bytes_out)*/
+ chunkqueue_mark_written(cq, chunkqueue_length(cq));
+ return 0;
+}
+
+#endif /* _MOD_WEBSOCKET_SPEC_IETF_00_ */
+
+
+#ifdef _MOD_WEBSOCKET_SPEC_RFC_6455_
+
+#define MOD_WEBSOCKET_OPCODE_CONT 0x00
+#define MOD_WEBSOCKET_OPCODE_TEXT 0x01
+#define MOD_WEBSOCKET_OPCODE_BIN 0x02
+#define MOD_WEBSOCKET_OPCODE_CLOSE 0x08
+#define MOD_WEBSOCKET_OPCODE_PING 0x09
+#define MOD_WEBSOCKET_OPCODE_PONG 0x0A
+
+#define MOD_WEBSOCKET_FRAME_LEN16 0x7E
+#define MOD_WEBSOCKET_FRAME_LEN63 0x7F
+#define MOD_WEBSOCKET_FRAME_LEN16_CNT 2
+#define MOD_WEBSOCKET_FRAME_LEN63_CNT 8
+
+static int send_rfc_6455(handler_ctx *hctx, mod_wstunnel_frame_type_t type, const char *payload, size_t siz) {
+ server *srv = hctx->srv;
+ connection *con = hctx->gw.remote_conn;
+ char mem[10];
+ size_t len;
+
+ /* allowed null payload for ping, pong, close frame */
+ if (payload == NULL && ( type == MOD_WEBSOCKET_FRAME_TYPE_TEXT
+ || type == MOD_WEBSOCKET_FRAME_TYPE_BIN )) {
+ return -1;
+ }
+
+ switch (type) {
+ case MOD_WEBSOCKET_FRAME_TYPE_TEXT:
+ mem[0] = (char)(0x80 | MOD_WEBSOCKET_OPCODE_TEXT);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = text");
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_BIN:
+ mem[0] = (char)(0x80 | MOD_WEBSOCKET_OPCODE_BIN);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = binary");
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_PING:
+ mem[0] = (char) (0x80 | MOD_WEBSOCKET_OPCODE_PING);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = ping");
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_PONG:
+ mem[0] = (char)(0x80 | MOD_WEBSOCKET_OPCODE_PONG);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = pong");
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_CLOSE:
+ default:
+ mem[0] = (char)(0x80 | MOD_WEBSOCKET_OPCODE_CLOSE);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = close");
+ break;
+ }
+
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx", "payload size =", siz);
+ if (siz < MOD_WEBSOCKET_FRAME_LEN16) {
+ mem[1] = siz;
+ len = 2;
+ }
+ else if (siz <= UINT16_MAX) {
+ mem[1] = MOD_WEBSOCKET_FRAME_LEN16;
+ mem[2] = (siz >> 8) & 0xff;
+ mem[3] = siz & 0xff;
+ len = 1+MOD_WEBSOCKET_FRAME_LEN16_CNT+1;
+ }
+ else {
+ mem[1] = MOD_WEBSOCKET_FRAME_LEN63;
+ mem[2] = 0;
+ mem[3] = 0;
+ mem[4] = 0;
+ mem[5] = 0;
+ mem[6] = (siz >> 24) & 0xff;
+ mem[7] = (siz >> 16) & 0xff;
+ mem[8] = (siz >> 8) & 0xff;
+ mem[9] = siz & 0xff;
+ len = 1+MOD_WEBSOCKET_FRAME_LEN63_CNT+1;
+ }
+ http_chunk_append_mem(srv, con, mem, len);
+ if (siz) http_chunk_append_mem(srv, con, payload, siz);
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sdsx",
+ "send data to client ( fd =",con->fd,"), frame size =",len+siz);
+ return 0;
+}
+
+static void unmask_payload(handler_ctx *hctx) {
+ buffer * const b = hctx->frame.payload;
+ for (size_t i = 0, used = buffer_string_length(b); i < used; ++i) {
+ b->ptr[i] ^= hctx->frame.ctl.mask[hctx->frame.ctl.mask_cnt];
+ hctx->frame.ctl.mask_cnt = (hctx->frame.ctl.mask_cnt + 1) % 4;
+ }
+}
+
+static int recv_rfc_6455(handler_ctx *hctx) {
+ connection *con = hctx->gw.remote_conn;
+ chunkqueue *cq = con->request_content_queue;
+ buffer *payload = hctx->frame.payload;
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sdsx",
+ "recv data from client ( fd =", con->fd,
+ "), size =", chunkqueue_length(cq));
+ for (chunk *c = cq->first; c; c = c->next) {
+ char *frame = c->mem->ptr+c->offset;
+ /*(chunk_remaining_length() on MEM_CHUNK)*/
+ size_t flen = (size_t)(buffer_string_length(c->mem) - c->offset);
+ /*(FILE_CHUNK not handled, but might need to add support)*/
+ force_assert(c->type == MEM_CHUNK);
+ for (size_t i = 0; i < flen; ) {
+ switch (hctx->frame.state) {
+ case MOD_WEBSOCKET_FRAME_STATE_INIT:
+ switch (frame[i] & 0x0f) {
+ case MOD_WEBSOCKET_OPCODE_CONT:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = continue");
+ hctx->frame.type = hctx->frame.type_before;
+ break;
+ case MOD_WEBSOCKET_OPCODE_TEXT:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = text");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_TEXT;
+ hctx->frame.type_before = hctx->frame.type;
+ break;
+ case MOD_WEBSOCKET_OPCODE_BIN:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = binary");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_BIN;
+ hctx->frame.type_before = hctx->frame.type;
+ break;
+ case MOD_WEBSOCKET_OPCODE_PING:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = ping");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_PING;
+ break;
+ case MOD_WEBSOCKET_OPCODE_PONG:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = pong");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_PONG;
+ break;
+ case MOD_WEBSOCKET_OPCODE_CLOSE:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "s", "type = close");
+ hctx->frame.type = MOD_WEBSOCKET_FRAME_TYPE_CLOSE;
+ return -1;
+ break;
+ default:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "type is invalid");
+ return -1;
+ break;
+ }
+ i++;
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_READ_LENGTH;
+ break;
+ case MOD_WEBSOCKET_FRAME_STATE_READ_LENGTH:
+ if ((frame[i] & 0x80) != 0x80) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s",
+ "payload was not masked");
+ return -1;
+ }
+ hctx->frame.ctl.mask_cnt = 0;
+ hctx->frame.ctl.siz = (uint64_t)(frame[i] & 0x7f);
+ if (hctx->frame.ctl.siz == 0) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "specified payload size =", hctx->frame.ctl.siz);
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_READ_MASK;
+ }
+ else if (hctx->frame.ctl.siz == MOD_WEBSOCKET_FRAME_LEN16) {
+ hctx->frame.ctl.siz = 0;
+ hctx->frame.ctl.siz_cnt = MOD_WEBSOCKET_FRAME_LEN16_CNT;
+ hctx->frame.state =
+ MOD_WEBSOCKET_FRAME_STATE_READ_EX_LENGTH;
+ }
+ else if (hctx->frame.ctl.siz == MOD_WEBSOCKET_FRAME_LEN63) {
+ hctx->frame.ctl.siz = 0;
+ hctx->frame.ctl.siz_cnt = MOD_WEBSOCKET_FRAME_LEN63_CNT;
+ hctx->frame.state =
+ MOD_WEBSOCKET_FRAME_STATE_READ_EX_LENGTH;
+ }
+ else {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "specified payload size =", hctx->frame.ctl.siz);
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_READ_MASK;
+ }
+ i++;
+ break;
+ case MOD_WEBSOCKET_FRAME_STATE_READ_EX_LENGTH:
+ hctx->frame.ctl.siz =
+ (hctx->frame.ctl.siz << 8) + (frame[i] & 0xff);
+ hctx->frame.ctl.siz_cnt--;
+ if (hctx->frame.ctl.siz_cnt <= 0) {
+ if (hctx->frame.type == MOD_WEBSOCKET_FRAME_TYPE_PING &&
+ hctx->frame.ctl.siz > MOD_WEBSOCKET_BUFMAX) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_WARN, "sx",
+ "frame size has been exceeded:",
+ MOD_WEBSOCKET_BUFMAX);
+ return -1;
+ }
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "specified payload size =", hctx->frame.ctl.siz);
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_READ_MASK;
+ }
+ i++;
+ break;
+ case MOD_WEBSOCKET_FRAME_STATE_READ_MASK:
+ hctx->frame.ctl.mask[hctx->frame.ctl.mask_cnt] = frame[i];
+ hctx->frame.ctl.mask_cnt++;
+ if (hctx->frame.ctl.mask_cnt >= MOD_WEBSOCKET_MASK_CNT) {
+ hctx->frame.ctl.mask_cnt = 0;
+ if (hctx->frame.type == MOD_WEBSOCKET_FRAME_TYPE_PING &&
+ hctx->frame.ctl.siz == 0) {
+ mod_wstunnel_frame_send(hctx,
+ MOD_WEBSOCKET_FRAME_TYPE_PONG,
+ NULL, 0);
+ }
+ if (hctx->frame.ctl.siz == 0) {
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_INIT;
+ }
+ else {
+ hctx->frame.state =
+ MOD_WEBSOCKET_FRAME_STATE_READ_PAYLOAD;
+ }
+ }
+ i++;
+ break;
+ case MOD_WEBSOCKET_FRAME_STATE_READ_PAYLOAD:
+ /* hctx->frame.ctl.siz <= SIZE_MAX */
+ if (hctx->frame.ctl.siz <= flen - i) {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "read payload, size =", hctx->frame.ctl.siz);
+ buffer_append_string_len(payload, frame+i, (size_t)
+ (hctx->frame.ctl.siz & SIZE_MAX));
+ i += (size_t)(hctx->frame.ctl.siz & SIZE_MAX);
+ hctx->frame.ctl.siz = 0;
+ hctx->frame.state = MOD_WEBSOCKET_FRAME_STATE_INIT;
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "rest of frame size =", flen - i);
+ /* SIZE_MAX < hctx->frame.ctl.siz */
+ }
+ else {
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "read payload, size =", flen - i);
+ buffer_append_string_len(payload, frame+i, flen - i);
+ hctx->frame.ctl.siz -= flen - i;
+ i += flen - i;
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_DEBUG, "sx",
+ "rest of payload size =", hctx->frame.ctl.siz);
+ }
+ switch (hctx->frame.type) {
+ case MOD_WEBSOCKET_FRAME_TYPE_TEXT:
+ case MOD_WEBSOCKET_FRAME_TYPE_BIN:
+ {
+ unmask_payload(hctx);
+ chunkqueue_append_buffer(hctx->gw.wb, payload);
+ buffer_clear(payload);
+ break;
+ }
+ case MOD_WEBSOCKET_FRAME_TYPE_PING:
+ if (hctx->frame.ctl.siz == 0) {
+ unmask_payload(hctx);
+ mod_wstunnel_frame_send(hctx,
+ MOD_WEBSOCKET_FRAME_TYPE_PONG,
+ payload->ptr, buffer_string_length(payload));
+ buffer_clear(payload);
+ }
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_PONG:
+ buffer_clear(payload);
+ break;
+ case MOD_WEBSOCKET_FRAME_TYPE_CLOSE:
+ default:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s",
+ "BUG: invalid frame type");
+ return -1;
+ }
+ break;
+ default:
+ DEBUG_LOG(MOD_WEBSOCKET_LOG_ERR, "s", "BUG: invalid state");
+ return -1;
+ }
+ }
+ }
+ /* XXX: should add ability to handle and preserve partial frames above */
+ /*(not chunkqueue_reset(); do not reset cq->bytes_in, cq->bytes_out)*/
+ chunkqueue_mark_written(cq, chunkqueue_length(cq));
+ return 0;
+}
+
+#endif /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+
+
+int mod_wstunnel_frame_send(handler_ctx *hctx, mod_wstunnel_frame_type_t type,
+ const char *payload, size_t siz) {
+ #ifdef _MOD_WEBSOCKET_SPEC_RFC_6455_
+ if (hctx->hybivers >= 8) return send_rfc_6455(hctx, type, payload, siz);
+ #endif /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+ #ifdef _MOD_WEBSOCKET_SPEC_IETF_00_
+ if (0 == hctx->hybivers) return send_ietf_00(hctx, type, payload, siz);
+ #endif /* _MOD_WEBSOCKET_SPEC_IETF_00_ */
+ return -1;
+}
+
+int mod_wstunnel_frame_recv(handler_ctx *hctx) {
+ #ifdef _MOD_WEBSOCKET_SPEC_RFC_6455_
+ if (hctx->hybivers >= 8) return recv_rfc_6455(hctx);
+ #endif /* _MOD_WEBSOCKET_SPEC_RFC_6455_ */
+ #ifdef _MOD_WEBSOCKET_SPEC_IETF_00_
+ if (0 == hctx->hybivers) return recv_ietf_00(hctx);
+ #endif /* _MOD_WEBSOCKET_SPEC_IETF_00_ */
+ return -1;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/network.c b/data/lighttpd/lighttpd-1.4.53/src/network.c
new file mode 100644
index 000000000..016d0d5bb
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/network.c
@@ -0,0 +1,540 @@
+#include "first.h"
+
+#include "network.h"
+#include "base.h"
+#include "fdevent.h"
+#include "log.h"
+#include "connections.h"
+#include "configfile.h"
+#include "sock_addr.h"
+
+#include "network_write.h"
+#include "sys-socket.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+void
+network_accept_tcp_nagle_disable (const int fd)
+{
+ static int noinherit_tcpnodelay = -1;
+ int opt;
+
+ if (!noinherit_tcpnodelay) /* TCP_NODELAY inherited from listen socket */
+ return;
+
+ if (noinherit_tcpnodelay < 0) {
+ socklen_t optlen = sizeof(opt);
+ if (0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen)) {
+ noinherit_tcpnodelay = !opt;
+ if (opt) /* TCP_NODELAY inherited from listen socket */
+ return;
+ }
+ }
+
+ opt = 1;
+ (void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+}
+
+static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) {
+ server_socket *srv_socket = (server_socket *)context;
+ connection *con;
+ int loops = 0;
+
+ UNUSED(context);
+
+ if (0 == (revents & FDEVENT_IN)) {
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
+ "strange event for server socket",
+ srv_socket->fd,
+ revents);
+ return HANDLER_ERROR;
+ }
+
+ /* accept()s at most 100 connections directly
+ *
+ * we jump out after 100 to give the waiting connections a chance */
+ for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
+ connection_state_machine(srv, con);
+ }
+ return HANDLER_GO_ON;
+}
+
+static void network_host_normalize_addr_str(buffer *host, sock_addr *addr) {
+ buffer_clear(host);
+ sock_addr_stringify_append_buffer(host, addr);
+}
+
+static int network_host_parse_addr(server *srv, sock_addr *addr, socklen_t *addr_len, buffer *host, int use_ipv6) {
+ char *h;
+ char *colon = NULL;
+ const char *chost;
+ sa_family_t family = use_ipv6 ? AF_INET6 : AF_INET;
+ unsigned int port = srv->srvconf.port;
+ if (buffer_string_is_empty(host)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "value of $SERVER[\"socket\"] must not be empty");
+ return -1;
+ }
+ h = host->ptr;
+ if (h[0] == '/') {
+ #ifdef HAVE_SYS_UN_H
+ return (1 == sock_addr_from_str_hints(srv,addr,addr_len,h,AF_UNIX,0))
+ ? 0
+ : -1;
+ #else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: Unix Domain sockets are not supported.");
+ return -1;
+ #endif
+ }
+ buffer_copy_buffer(srv->tmp_buf, host);
+ h = srv->tmp_buf->ptr;
+ if (h[0] == '[') {
+ family = AF_INET6;
+ if ((h = strchr(h, ']'))) {
+ *h++ = '\0';
+ if (*h == ':') colon = h;
+ } /*(else should not happen; validated in configparser.y)*/
+ h = srv->tmp_buf->ptr+1;
+ }
+ else {
+ colon = strrchr(h, ':');
+ }
+ if (colon) {
+ *colon++ = '\0';
+ port = strtol(colon, NULL, 10);
+ if (port == 0 || port > 65535) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "port not set or out of range:", port);
+ return -1;
+ }
+ }
+ chost = *h ? h : family == AF_INET ? "0.0.0.0" : "::";
+ if (1 != sock_addr_from_str_hints(srv,addr,addr_len,chost,family,port)) {
+ return -1;
+ }
+ return 0;
+}
+
+static void network_srv_sockets_append(server *srv, server_socket *srv_socket) {
+ if (srv->srv_sockets.size == 0) {
+ srv->srv_sockets.size = 4;
+ srv->srv_sockets.used = 0;
+ srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket*));
+ force_assert(NULL != srv->srv_sockets.ptr);
+ } else if (srv->srv_sockets.used == srv->srv_sockets.size) {
+ srv->srv_sockets.size += 4;
+ srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*));
+ force_assert(NULL != srv->srv_sockets.ptr);
+ }
+ srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
+}
+
+static int network_server_init(server *srv, buffer *host_token, size_t sidx, int stdin_fd) {
+ server_socket *srv_socket;
+ const char *host;
+ specific_config *s = srv->config_storage[sidx];
+ socklen_t addr_len = sizeof(sock_addr);
+ sock_addr addr;
+ int family = 0;
+ int set_v6only = 0;
+
+ if (buffer_string_is_empty(host_token)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "value of $SERVER[\"socket\"] must not be empty");
+ return -1;
+ }
+
+ /* check if we already know this socket, and if yes, don't init it
+ * (optimization: check strings here to filter out exact matches;
+ * binary addresses are matched further below) */
+ for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
+ if (buffer_is_equal(srv->srv_sockets.ptr[i]->srv_token, host_token)) {
+ buffer_copy_buffer(host_token, srv->srv_sockets.ptr[i]->srv_token);
+ return 0;
+ }
+ }
+
+ host = host_token->ptr;
+ if ((s->use_ipv6 && (*host == '\0' || *host == ':')) || (host[0] == '[' && host[1] == ']')) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "warning: please use server.use-ipv6 only for hostnames, not without server.bind / empty address; your config will break if the kernel default for IPV6_V6ONLY changes");
+ }
+ if (*host == '[') s->use_ipv6 = 1;
+
+ memset(&addr, 0, sizeof(addr));
+ if (-1 != stdin_fd) {
+ if (-1 == getsockname(stdin_fd, (struct sockaddr *)&addr, &addr_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "getsockname()", strerror(errno));
+ return -1;
+ }
+ } else if (0 != network_host_parse_addr(srv, &addr, &addr_len, host_token, s->use_ipv6)) {
+ return -1;
+ }
+
+ family = sock_addr_get_family(&addr);
+
+ #ifdef HAVE_IPV6
+ if (*host != '\0' && AF_INET6 == family) {
+ if (s->set_v6only) {
+ set_v6only = 1;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "s", "warning: server.set-v6only will be removed soon, update your config to have different sockets for ipv4 and ipv6");
+ }
+ }
+ #endif
+
+ network_host_normalize_addr_str(host_token, &addr);
+ host = host_token->ptr;
+
+ if (srv->srvconf.preflight_check) {
+ return 0;
+ }
+
+ /* check if we already know this socket (after potential DNS resolution), and if yes, don't init it */
+ for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
+ if (0 == memcmp(&srv->srv_sockets.ptr[i]->addr, &addr, sizeof(addr))) {
+ return 0;
+ }
+ }
+
+ srv_socket = calloc(1, sizeof(*srv_socket));
+ force_assert(NULL != srv_socket);
+ memcpy(&srv_socket->addr, &addr, addr_len);
+ srv_socket->fd = -1;
+ srv_socket->fde_ndx = -1;
+ srv_socket->sidx = sidx;
+ srv_socket->is_ssl = s->ssl_enabled;
+ srv_socket->srv_token = buffer_init_buffer(host_token);
+
+ network_srv_sockets_append(srv, srv_socket);
+
+ if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
+ return 0;
+ }
+
+ if (srv->srvconf.systemd_socket_activation) {
+ for (size_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
+ if (0 != memcmp(&srv->srv_sockets_inherited.ptr[i]->addr, &srv_socket->addr, addr_len)) continue;
+ if ((unsigned short)~0u == srv->srv_sockets_inherited.ptr[i]->sidx) {
+ srv->srv_sockets_inherited.ptr[i]->sidx = sidx;
+ }
+ stdin_fd = srv->srv_sockets_inherited.ptr[i]->fd;
+ break;
+ }
+ }
+
+ if (-1 != stdin_fd) {
+ srv_socket->fd = stdin_fd;
+ if (-1 == fdevent_fcntl_set_nb_cloexec(srv->ev, stdin_fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl:", strerror(errno));
+ return -1;
+ }
+ } else
+#ifdef HAVE_SYS_UN_H
+ if (AF_UNIX == family) {
+ /* check if the socket exists and try to connect to it. */
+ force_assert(host); /*(static analysis hint)*/
+ if (-1 == (srv_socket->fd = fdevent_socket_cloexec(AF_UNIX, SOCK_STREAM, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
+ return -1;
+ }
+ if (0 == connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "server socket is still in use:",
+ host);
+
+
+ return -1;
+ }
+
+ /* connect failed */
+ switch(errno) {
+ case ECONNREFUSED:
+ unlink(host);
+ break;
+ case ENOENT:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "testing socket failed:",
+ host, strerror(errno));
+
+ return -1;
+ }
+
+ fdevent_fcntl_set_nb(srv->ev, srv_socket->fd);
+ } else
+#endif
+ {
+ if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(family, SOCK_STREAM, IPPROTO_TCP))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
+ return -1;
+ }
+ }
+
+#ifdef HAVE_IPV6
+ if (set_v6only && -1 == stdin_fd) {
+ int val = 1;
+ if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(IPV6_V6ONLY) failed:", strerror(errno));
+ return -1;
+ }
+ }
+#endif
+
+ /* */
+ srv->cur_fds = srv_socket->fd;
+
+ if (fdevent_set_so_reuseaddr(srv_socket->fd, 1) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(SO_REUSEADDR) failed:", strerror(errno));
+ return -1;
+ }
+
+ if (family != AF_UNIX) {
+ if (fdevent_set_tcp_nodelay(srv_socket->fd, 1) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(TCP_NODELAY) failed:", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (-1 != stdin_fd) { } else
+ if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "can't bind to socket:", host, strerror(errno));
+ return -1;
+ }
+
+ if (-1 != stdin_fd) { } else
+ if (AF_UNIX == family && !buffer_string_is_empty(s->socket_perms)) {
+ mode_t m = 0;
+ for (char *str = s->socket_perms->ptr; *str; ++str) {
+ m <<= 3;
+ m |= (*str - '0');
+ }
+ if (0 != m && -1 == chmod(host, m)) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbss", "chmod(\"", host, "\", ", s->socket_perms, "):", strerror(errno));
+ }
+ }
+
+ if (-1 != stdin_fd) { } else
+ if (-1 == listen(srv_socket->fd, s->listen_backlog)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
+ return -1;
+ }
+
+ if (s->ssl_enabled) {
+#ifdef TCP_DEFER_ACCEPT
+ } else if (s->defer_accept) {
+ int v = s->defer_accept;
+ if (-1 == setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &v, sizeof(v))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't set TCP_DEFER_ACCEPT: ", strerror(errno));
+ }
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__DragonFly__)
+ } else if (!buffer_is_empty(s->bsd_accept_filter)
+ && (buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("httpready"))
+ || buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("dataready")))) {
+#ifdef SO_ACCEPTFILTER
+ /* FreeBSD accf_http filter */
+ struct accept_filter_arg afa;
+ memset(&afa, 0, sizeof(afa));
+ strncpy(afa.af_name, s->bsd_accept_filter->ptr, sizeof(afa.af_name));
+ if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
+ if (errno != ENOENT) {
+ log_error_write(srv, __FILE__, __LINE__, "SBss", "can't set accept-filter '", s->bsd_accept_filter, "':", strerror(errno));
+ }
+ }
+#endif
+#endif
+ }
+
+ return 0;
+}
+
+int network_close(server *srv) {
+ size_t i;
+ for (i = 0; i < srv->srv_sockets.used; i++) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+ if (srv_socket->fd != -1) {
+ network_unregister_sock(srv, srv_socket);
+ close(srv_socket->fd);
+ }
+
+ buffer_free(srv_socket->srv_token);
+
+ free(srv_socket);
+ }
+
+ free(srv->srv_sockets.ptr);
+ srv->srv_sockets.ptr = NULL;
+ srv->srv_sockets.used = 0;
+ srv->srv_sockets.size = 0;
+
+ for (i = 0; i < srv->srv_sockets_inherited.used; i++) {
+ server_socket *srv_socket = srv->srv_sockets_inherited.ptr[i];
+ if (srv_socket->fd != -1 && srv_socket->sidx != (unsigned short)~0u) {
+ close(srv_socket->fd);
+ }
+
+ buffer_free(srv_socket->srv_token);
+
+ free(srv_socket);
+ }
+
+ free(srv->srv_sockets_inherited.ptr);
+ srv->srv_sockets_inherited.ptr = NULL;
+ srv->srv_sockets_inherited.used = 0;
+ srv->srv_sockets_inherited.size = 0;
+
+ return 0;
+}
+
+static int network_socket_activation_nfds(server *srv, int nfds) {
+ buffer *host = buffer_init();
+ socklen_t addr_len;
+ sock_addr addr;
+ int rc = 0;
+ nfds += 3; /* #define SD_LISTEN_FDS_START 3 */
+ for (int fd = 3; fd < nfds; ++fd) {
+ addr_len = sizeof(sock_addr);
+ if (-1 == (rc = getsockname(fd, (struct sockaddr *)&addr, &addr_len))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "socket activation getsockname()", strerror(errno));
+ break;
+ }
+ network_host_normalize_addr_str(host, &addr);
+ rc = network_server_init(srv, host, 0, fd);
+ if (0 != rc) break;
+ srv->srv_sockets.ptr[srv->srv_sockets.used-1]->sidx = (unsigned short)~0u;
+ }
+ buffer_free(host);
+ memcpy(&srv->srv_sockets_inherited, &srv->srv_sockets, sizeof(server_socket_array));
+ memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
+ return rc;
+}
+
+static int network_socket_activation_from_env(server *srv) {
+ char *listen_pid = getenv("LISTEN_PID");
+ char *listen_fds = getenv("LISTEN_FDS");
+ pid_t lpid = listen_pid ? (pid_t)strtoul(listen_pid,NULL,10) : 0;
+ int nfds = listen_fds ? atoi(listen_fds) : 0;
+ int rc = (lpid == getpid() && nfds > 0)
+ ? network_socket_activation_nfds(srv, nfds)
+ : 0;
+ unsetenv("LISTEN_PID");
+ unsetenv("LISTEN_FDS");
+ unsetenv("LISTEN_FDNAMES");
+ /*(upon graceful restart, unsetenv will result in no-op above)*/
+ return rc;
+}
+
+int network_init(server *srv, int stdin_fd) {
+ #ifdef __WIN32
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ if (0 != WSAStartup(wVersionRequested, &wsaData)) {
+ /* Tell the user that we could not find a usable WinSock DLL */
+ return -1;
+ }
+ #endif
+
+ if (0 != network_write_init(srv)) return -1;
+
+ if (srv->srvconf.systemd_socket_activation) {
+ for (size_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
+ srv->srv_sockets_inherited.ptr[i]->sidx = (unsigned short)~0u;
+ }
+ if (0 != network_socket_activation_from_env(srv)) return -1;
+ if (0 == srv->srv_sockets_inherited.used) {
+ srv->srvconf.systemd_socket_activation = 0;
+ }
+ }
+
+ /* process srv->srvconf.bindhost
+ * (skip if systemd socket activation is enabled and bindhost is empty; do not additionally listen on "*") */
+ if (!srv->srvconf.systemd_socket_activation || !buffer_string_is_empty(srv->srvconf.bindhost)) {
+ int rc;
+ buffer *b = buffer_init();
+ buffer_copy_buffer(b, srv->srvconf.bindhost);
+ if (b->ptr[0] != '/') { /*(skip adding port if unix socket path)*/
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_int(b, srv->srvconf.port);
+ }
+
+ rc = (-1 == stdin_fd || 0 == srv->srv_sockets.used)
+ ? network_server_init(srv, b, 0, stdin_fd)
+ : close(stdin_fd);/*(graceful restart listening to "/dev/stdin")*/
+ buffer_free(b);
+ if (0 != rc) return -1;
+ }
+
+ /* check for $SERVER["socket"] */
+ for (size_t i = 1; i < srv->config_context->used; ++i) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+
+ /* not our stage */
+ if (COMP_SERVER_SOCKET != dc->comp) continue;
+
+ if (dc->cond == CONFIG_COND_NE) {
+ socklen_t addr_len = sizeof(sock_addr);
+ sock_addr addr;
+ if (0 != network_host_parse_addr(srv, &addr, &addr_len, dc->string, srv->config_storage[i]->use_ipv6)) {
+ return -1;
+ }
+ network_host_normalize_addr_str(dc->string, &addr);
+ continue;
+ }
+
+ if (dc->cond != CONFIG_COND_EQ) continue;
+
+ if (0 != network_server_init(srv, dc->string, i, -1)) return -1;
+ }
+
+ if (srv->srvconf.systemd_socket_activation) {
+ /* activate any inherited sockets not explicitly listed in config file */
+ server_socket *srv_socket;
+ for (size_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
+ if ((unsigned short)~0u != srv->srv_sockets_inherited.ptr[i]->sidx) continue;
+ srv->srv_sockets_inherited.ptr[i]->sidx = 0;
+ srv_socket = calloc(1, sizeof(server_socket));
+ force_assert(NULL != srv_socket);
+ memcpy(srv_socket, srv->srv_sockets_inherited.ptr[i], sizeof(server_socket));
+ network_srv_sockets_append(srv, srv_socket);
+ }
+ }
+
+ return 0;
+}
+
+void network_unregister_sock(server *srv, server_socket *srv_socket) {
+ if (-1 == srv_socket->fd || -1 == srv_socket->fde_ndx) return;
+ fdevent_event_del(srv->ev, &srv_socket->fde_ndx, srv_socket->fd);
+ fdevent_unregister(srv->ev, srv_socket->fd);
+}
+
+int network_register_fdevents(server *srv) {
+ size_t i;
+
+ if (-1 == fdevent_reset(srv->ev)) {
+ return -1;
+ }
+
+ if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
+
+ /* register fdevents after reset */
+ for (i = 0; i < srv->srv_sockets.used; i++) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+
+ fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
+ fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
+ }
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/network.h b/data/lighttpd/lighttpd-1.4.53/src/network.h
new file mode 100644
index 000000000..f6f9f3fe3
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/network.h
@@ -0,0 +1,17 @@
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+struct server_socket; /* declaration */
+
+void network_accept_tcp_nagle_disable(int fd);
+
+int network_init(server *srv, int stdin_fd);
+int network_close(server *srv);
+
+int network_register_fdevents(server *srv);
+void network_unregister_sock(server *srv, struct server_socket *srv_socket);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/network_write.c b/data/lighttpd/lighttpd-1.4.53/src/network_write.c
new file mode 100644
index 000000000..325546bbf
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/network_write.c
@@ -0,0 +1,738 @@
+#include "first.h"
+
+#include "network_write.h"
+
+#include "base.h"
+#include "log.h"
+
+#include <sys/types.h>
+#include "sys-socket.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* on linux 2.4.x you get either sendfile or LFS */
+#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILE \
+ && (!defined _LARGEFILE_SOURCE || defined HAVE_SENDFILE64) \
+ && defined(__linux__) && !defined HAVE_SENDFILE_BROKEN
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "linux-sendfile"
+# define NETWORK_WRITE_USE_LINUX_SENDFILE
+#endif
+
+#if defined HAVE_SENDFILE && (defined(__FreeBSD__) || defined(__DragonFly__))
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "freebsd-sendfile"
+# define NETWORK_WRITE_USE_FREEBSD_SENDFILE
+#endif
+
+#if defined HAVE_SENDFILE && defined(__APPLE__)
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "darwin-sendfile"
+# define NETWORK_WRITE_USE_DARWIN_SENDFILE
+#endif
+
+#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined(__sun)
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "solaris-sendfilev"
+# define NETWORK_WRITE_USE_SOLARIS_SENDFILEV
+#endif
+
+/* not supported so far
+#if defined HAVE_SEND_FILE && defined(__aix)
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "aix-sendfile"
+# define NETWORK_WRITE_USE_AIX_SENDFILE
+#endif
+*/
+
+#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV
+# define NETWORK_WRITE_USE_WRITEV
+#endif
+
+#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP && defined ENABLE_MMAP
+# define NETWORK_WRITE_USE_MMAP
+#endif
+
+
+static int network_write_error(server *srv, int fd) {
+ #if defined(__WIN32)
+ int lastError = WSAGetLastError();
+ switch (lastError) {
+ case WSAEINTR:
+ case WSAEWOULDBLOCK:
+ return -3;
+ case WSAECONNRESET:
+ case WSAETIMEDOUT:
+ case WSAECONNABORTED:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
+ "send failed: ", lastError, fd);
+ return -1;
+ }
+ #else /* __WIN32 */
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ return -3;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+ return -1;
+ }
+ #endif /* __WIN32 */
+}
+
+inline
+static ssize_t network_write_data_len(int fd, const char *data, off_t len) {
+ #if defined(__WIN32)
+ return send(fd, data, len, 0);
+ #else /* __WIN32 */
+ return write(fd, data, len);
+ #endif /* __WIN32 */
+}
+
+
+
+
+/* write next chunk(s); finished chunks are removed afterwards after successful writes.
+ * return values: similar as backends (0 succes, -1 error, -2 remote close, -3 try again later (EINTR/EAGAIN)) */
+/* next chunk must be MEM_CHUNK. use write()/send() */
+static int network_write_mem_chunk(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk* const c = cq->first;
+ ssize_t wr;
+ off_t c_len = (off_t)buffer_string_length(c->mem);
+ force_assert(c->offset >= 0 && c->offset <= c_len);
+ c_len -= c->offset;
+ if (c_len > *p_max_bytes) c_len = *p_max_bytes;
+
+ if (0 == c_len) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ wr = network_write_data_len(fd, c->mem->ptr + c->offset, c_len);
+ if (wr >= 0) {
+ *p_max_bytes -= wr;
+ chunkqueue_mark_written(cq, wr);
+ return (wr > 0 && wr == c_len) ? 0 : -3;
+ } else {
+ return network_write_error(srv, fd);
+ }
+}
+
+
+
+
+#if !defined(NETWORK_WRITE_USE_MMAP)
+
+static int network_write_file_chunk_no_mmap(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk* const c = cq->first;
+ off_t offset, toSend;
+ ssize_t wr;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ if (toSend > *p_max_bytes) toSend = *p_max_bytes;
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ if (toSend > 64*1024) toSend = 64*1024; /* max read 64kb in one step */
+ buffer_string_prepare_copy(srv->tmp_buf, toSend);
+
+ if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss","lseek:",strerror(errno));
+ return -1;
+ }
+ if (-1 == (toSend = read(c->file.fd, srv->tmp_buf->ptr, toSend))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss","read:",strerror(errno));
+ return -1;
+ }
+
+ wr = network_write_data_len(fd, srv->tmp_buf->ptr, toSend);
+ if (wr >= 0) {
+ *p_max_bytes -= wr;
+ chunkqueue_mark_written(cq, wr);
+ return (wr > 0 && wr == toSend) ? 0 : -3;
+ } else {
+ return network_write_error(srv, fd);
+ }
+}
+
+#endif
+
+
+
+
+#if defined(NETWORK_WRITE_USE_MMAP)
+
+#include "sys-mmap.h"
+
+#include <setjmp.h>
+#include <signal.h>
+
+#define MMAP_CHUNK_SIZE (512*1024)
+
+static off_t mmap_align_offset(off_t start) {
+ static long pagesize = 0;
+ if (0 == pagesize) {
+ pagesize = sysconf(_SC_PAGESIZE);
+ force_assert(pagesize < MMAP_CHUNK_SIZE);
+ }
+ force_assert(start >= (start % pagesize));
+ return start - (start % pagesize);
+}
+
+static volatile int sigbus_jmp_valid;
+static sigjmp_buf sigbus_jmp;
+
+static void sigbus_handler(int sig) {
+ UNUSED(sig);
+ if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
+ log_failed_assert(__FILE__, __LINE__, "SIGBUS");
+}
+
+/* next chunk must be FILE_CHUNK. send mmap()ed file with write() */
+static int network_write_file_chunk_mmap(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk* const c = cq->first;
+ off_t offset, toSend, file_end;
+ ssize_t r;
+ size_t mmap_offset, mmap_avail;
+ const char *data;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ if (toSend > *p_max_bytes) toSend = *p_max_bytes;
+ file_end = c->file.start + c->file.length; /*file end offset in this chunk*/
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ /* mmap buffer if offset is outside old mmap area or not mapped at all */
+ if (MAP_FAILED == c->file.mmap.start
+ || offset < c->file.mmap.offset
+ || offset >= (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
+
+ if (MAP_FAILED != c->file.mmap.start) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ }
+
+ /* Optimizations for the future:
+ *
+ * adaptive mem-mapping
+ * the problem:
+ * we mmap() the whole file. If someone has alot large files and
+ * 32-bit machine the virtual address area will be unrun and we
+ * will have a failing mmap() call.
+ * solution:
+ * only mmap 16M in one chunk and move the window as soon as we have
+ * finished the first 8M
+ *
+ * read-ahead buffering
+ * the problem:
+ * sending out several large files in parallel trashes read-ahead
+ * of the kernel leading to long wait-for-seek times.
+ * solutions: (increasing complexity)
+ * 1. use madvise
+ * 2. use a internal read-ahead buffer in the chunk-structure
+ * 3. use non-blocking IO for file-transfers
+ * */
+
+ c->file.mmap.offset = mmap_align_offset(offset);
+
+ /* all mmap()ed areas are MMAP_CHUNK_SIZE
+ * except the last which might be smaller */
+ c->file.mmap.length = MMAP_CHUNK_SIZE;
+ if (c->file.mmap.offset > file_end - (off_t)c->file.mmap.length) {
+ c->file.mmap.length = file_end - c->file.mmap.offset;
+ }
+
+ c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ,
+ MAP_SHARED, c->file.fd, c->file.mmap.offset);
+ if (MAP_FAILED == c->file.mmap.start) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbdoo", "mmap failed:",
+ strerror(errno), c->mem, c->file.fd,
+ c->file.mmap.offset, (off_t) c->file.mmap.length);
+ return -1;
+ }
+
+ #if defined(HAVE_MADVISE)
+ /* don't advise files < 64Kb */
+ if (c->file.mmap.length > (64*1024)) {
+ /* darwin 7 is returning EINVAL all the time and I don't know how to
+ * detect this at runtime.
+ *
+ * ignore the return value for now */
+ madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED);
+ }
+ #endif
+ }
+
+ force_assert(offset >= c->file.mmap.offset);
+ mmap_offset = offset - c->file.mmap.offset;
+ force_assert(c->file.mmap.length > mmap_offset);
+ mmap_avail = c->file.mmap.length - mmap_offset;
+ if (toSend > (off_t) mmap_avail) toSend = mmap_avail;
+
+ data = c->file.mmap.start + mmap_offset;
+
+ /* setup SIGBUS handler, but don't activate sigbus_jmp_valid yet */
+ if (0 == sigsetjmp(sigbus_jmp, 1)) {
+ signal(SIGBUS, sigbus_handler);
+
+ sigbus_jmp_valid = 1;
+ r = network_write_data_len(fd, data, toSend);
+ sigbus_jmp_valid = 0;
+ } else {
+ sigbus_jmp_valid = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:",
+ c->mem, c->file.fd);
+
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ return -1;
+ }
+
+ if (r >= 0) {
+ *p_max_bytes -= r;
+ chunkqueue_mark_written(cq, r);
+ return (r > 0 && r == toSend) ? 0 : -3;
+ } else {
+ return network_write_error(srv, fd);
+ }
+}
+
+#endif /* NETWORK_WRITE_USE_MMAP */
+
+
+
+
+#if defined(NETWORK_WRITE_USE_WRITEV)
+
+#if defined(HAVE_SYS_UIO_H)
+# include <sys/uio.h>
+#endif
+
+#if defined(UIO_MAXIOV)
+# define SYS_MAX_CHUNKS UIO_MAXIOV
+#elif defined(IOV_MAX)
+/* new name for UIO_MAXIOV since IEEE Std 1003.1-2001 */
+# define SYS_MAX_CHUNKS IOV_MAX
+#elif defined(_XOPEN_IOV_MAX)
+/* minimum value for sysconf(_SC_IOV_MAX); posix requires this to be at least 16, which is good enough - no need to call sysconf() */
+# define SYS_MAX_CHUNKS _XOPEN_IOV_MAX
+#else
+# error neither UIO_MAXIOV nor IOV_MAX nor _XOPEN_IOV_MAX are defined
+#endif
+
+/* allocate iovec[MAX_CHUNKS] on stack, so pick a sane limit:
+ * - each entry will use 1 pointer + 1 size_t
+ * - 32 chunks -> 256 / 512 bytes (32-bit/64-bit pointers)
+ */
+#define STACK_MAX_ALLOC_CHUNKS 32
+#if SYS_MAX_CHUNKS > STACK_MAX_ALLOC_CHUNKS
+# define MAX_CHUNKS STACK_MAX_ALLOC_CHUNKS
+#else
+# define MAX_CHUNKS SYS_MAX_CHUNKS
+#endif
+
+/* next chunk must be MEM_CHUNK. send multiple mem chunks using writev() */
+static int network_writev_mem_chunks(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ struct iovec chunks[MAX_CHUNKS];
+ size_t num_chunks = 0;
+ off_t max_bytes = *p_max_bytes;
+ off_t toSend = 0;
+ ssize_t r;
+
+ for (const chunk *c = cq->first;
+ NULL != c && MEM_CHUNK == c->type
+ && num_chunks < MAX_CHUNKS && toSend < max_bytes;
+ c = c->next) {
+ size_t c_len = buffer_string_length(c->mem);
+ force_assert(c->offset >= 0 && c->offset <= (off_t)c_len);
+ c_len -= c->offset;
+ if (c_len > 0) {
+ toSend += c_len;
+
+ chunks[num_chunks].iov_base = c->mem->ptr + c->offset;
+ chunks[num_chunks].iov_len = c_len;
+
+ ++num_chunks;
+ }
+ }
+
+ if (0 == num_chunks) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ r = writev(fd, chunks, num_chunks);
+
+ if (r < 0) switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "writev failed:", strerror(errno), fd);
+ return -1;
+ }
+
+ if (r >= 0) {
+ *p_max_bytes -= r;
+ chunkqueue_mark_written(cq, r);
+ }
+
+ return (r > 0 && r == toSend) ? 0 : -3;
+}
+
+#endif /* NETWORK_WRITE_USE_WRITEV */
+
+
+
+
+#if defined(NETWORK_WRITE_USE_SENDFILE)
+
+#if defined(NETWORK_WRITE_USE_LINUX_SENDFILE) \
+ || defined(NETWORK_WRITE_USE_SOLARIS_SENDFILEV)
+#include <sys/sendfile.h>
+#endif
+
+#if defined(NETWORK_WRITE_USE_FREEBSD_SENDFILE) \
+ || defined(NETWORK_WRITE_USE_DARWIN_SENDFILE)
+#include <sys/uio.h>
+#endif
+
+static int network_write_file_chunk_sendfile(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk * const c = cq->first;
+ ssize_t r;
+ off_t offset;
+ off_t toSend;
+ off_t written = 0;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ if (toSend > *p_max_bytes) toSend = *p_max_bytes;
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ /* Darwin, FreeBSD, and Solaris variants support iovecs and could
+ * be optimized to send more than just file in single syscall */
+
+ #if defined(NETWORK_WRITE_USE_LINUX_SENDFILE)
+
+ r = sendfile(fd, c->file.fd, &offset, toSend);
+ if (r > 0) written = (off_t)r;
+
+ #elif defined(NETWORK_WRITE_USE_DARWIN_SENDFILE)
+
+ written = toSend;
+ r = sendfile(c->file.fd, fd, offset, &written, NULL, 0);
+ /* (for EAGAIN/EINTR written still contains the sent bytes) */
+
+ #elif defined(NETWORK_WRITE_USE_FREEBSD_SENDFILE)
+
+ r = sendfile(c->file.fd, fd, offset, toSend, NULL, &written, 0);
+ /* (for EAGAIN/EINTR written still contains the sent bytes) */
+
+ #elif defined(NETWORK_WRITE_USE_SOLARIS_SENDFILEV)
+ {
+ sendfilevec_t fvec;
+ fvec.sfv_fd = c->file.fd;
+ fvec.sfv_flag = 0;
+ fvec.sfv_off = offset;
+ fvec.sfv_len = toSend;
+
+ /* Solaris sendfilev() */
+ r = sendfilev(fd, &fvec, 1, (size_t *)&written);
+ /* (for EAGAIN/EINTR written still contains the sent bytes) */
+ }
+ #else
+
+ r = -1;
+ errno = ENOSYS;
+
+ #endif
+
+ if (-1 == r) {
+ switch(errno) {
+ case EAGAIN:
+ case EINTR:
+ break; /* try again later */
+ case EPIPE:
+ case ECONNRESET:
+ case ENOTCONN:
+ return -2;
+ case EINVAL:
+ case ENOSYS:
+ #if defined(ENOTSUP) && (!defined(EOPNOTSUPP) || EOPNOTSUPP != ENOTSUP)
+ case ENOTSUP:
+ #endif
+ #ifdef EOPNOTSUPP
+ case EOPNOTSUPP:
+ #endif
+ #ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT:
+ #endif
+ #ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+ #endif
+ #ifdef NETWORK_WRITE_USE_MMAP
+ return network_write_file_chunk_mmap(srv, fd, cq, p_max_bytes);
+ #else
+ return network_write_file_chunk_no_mmap(srv, fd, cq, p_max_bytes);
+ #endif
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssdSd",
+ "sendfile():", strerror(errno), errno, "fd:", fd);
+ return -1;
+ }
+ }
+
+ if (written >= 0) { /*(always true)*/
+ chunkqueue_mark_written(cq, written);
+ *p_max_bytes -= written;
+ }
+
+ return (r >= 0 && written == toSend) ? 0 : -3;
+}
+
+#endif
+
+
+
+
+/* return values:
+ * >= 0 : no error
+ * -1 : error (on our side)
+ * -2 : remote close
+ */
+
+static int network_write_chunkqueue_write(server *srv, int fd, chunkqueue *cq, off_t max_bytes) {
+ while (max_bytes > 0 && NULL != cq->first) {
+ int r = -1;
+
+ switch (cq->first->type) {
+ case MEM_CHUNK:
+ r = network_write_mem_chunk(srv, fd, cq, &max_bytes);
+ break;
+ case FILE_CHUNK:
+ #ifdef NETWORK_WRITE_USE_MMAP
+ r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ }
+
+ if (-3 == r) return 0;
+ if (0 != r) return r;
+ }
+
+ return 0;
+}
+
+#if defined(NETWORK_WRITE_USE_WRITEV)
+static int network_write_chunkqueue_writev(server *srv, int fd, chunkqueue *cq, off_t max_bytes) {
+ while (max_bytes > 0 && NULL != cq->first) {
+ int r = -1;
+
+ switch (cq->first->type) {
+ case MEM_CHUNK:
+ #if defined(NETWORK_WRITE_USE_WRITEV)
+ r = network_writev_mem_chunks(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_mem_chunk(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ case FILE_CHUNK:
+ #ifdef NETWORK_WRITE_USE_MMAP
+ r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ }
+
+ if (-3 == r) return 0;
+ if (0 != r) return r;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(NETWORK_WRITE_USE_SENDFILE)
+static int network_write_chunkqueue_sendfile(server *srv, int fd, chunkqueue *cq, off_t max_bytes) {
+ while (max_bytes > 0 && NULL != cq->first) {
+ int r = -1;
+
+ switch (cq->first->type) {
+ case MEM_CHUNK:
+ #if defined(NETWORK_WRITE_USE_WRITEV)
+ r = network_writev_mem_chunks(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_mem_chunk(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ case FILE_CHUNK:
+ #if defined(NETWORK_WRITE_USE_SENDFILE)
+ r = network_write_file_chunk_sendfile(srv, fd, cq, &max_bytes);
+ #elif defined(NETWORK_WRITE_USE_MMAP)
+ r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ }
+
+ if (-3 == r) return 0;
+ if (0 != r) return r;
+ }
+
+ return 0;
+}
+#endif
+
+int network_write_init(server *srv) {
+ typedef enum {
+ NETWORK_BACKEND_UNSET,
+ NETWORK_BACKEND_WRITE,
+ NETWORK_BACKEND_WRITEV,
+ NETWORK_BACKEND_SENDFILE,
+ } network_backend_t;
+
+ network_backend_t backend;
+
+ struct nb_map {
+ network_backend_t nb;
+ const char *name;
+ } network_backends[] = {
+ /* lowest id wins */
+ { NETWORK_BACKEND_SENDFILE, "sendfile" },
+ { NETWORK_BACKEND_SENDFILE, "linux-sendfile" },
+ { NETWORK_BACKEND_SENDFILE, "freebsd-sendfile" },
+ { NETWORK_BACKEND_SENDFILE, "solaris-sendfilev" },
+ { NETWORK_BACKEND_WRITEV, "writev" },
+ { NETWORK_BACKEND_WRITE, "write" },
+ { NETWORK_BACKEND_UNSET, NULL }
+ };
+
+ /* get a useful default */
+ backend = network_backends[0].nb;
+
+ /* match name against known types */
+ if (!buffer_string_is_empty(srv->srvconf.network_backend)) {
+ const char *name;
+ for (size_t i = 0; NULL != (name = network_backends[i].name); ++i) {
+ if (0 == strcmp(srv->srvconf.network_backend->ptr, name)) {
+ backend = network_backends[i].nb;
+ break;
+ }
+ }
+ if (NULL == name) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.network-backend has an unknown value:",
+ srv->srvconf.network_backend);
+ return -1;
+ }
+ }
+
+ switch(backend) {
+ case NETWORK_BACKEND_SENDFILE:
+ #if defined(NETWORK_WRITE_USE_SENDFILE)
+ srv->network_backend_write = network_write_chunkqueue_sendfile;
+ break;
+ #endif
+ case NETWORK_BACKEND_WRITEV:
+ #if defined(NETWORK_WRITE_USE_WRITEV)
+ srv->network_backend_write = network_write_chunkqueue_writev;
+ break;
+ #endif
+ case NETWORK_BACKEND_WRITE:
+ srv->network_backend_write = network_write_chunkqueue_write;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+const char * network_write_show_handlers(void) {
+ return
+ "\nNetwork handler:\n\n"
+ #if defined NETWORK_WRITE_USE_LINUX_SENDFILE
+ "\t+ linux-sendfile\n"
+ #else
+ "\t- linux-sendfile\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_FREEBSD_SENDFILE
+ "\t+ freebsd-sendfile\n"
+ #else
+ "\t- freebsd-sendfile\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_DARWIN_SENDFILE
+ "\t+ darwin-sendfile\n"
+ #else
+ "\t- darwin-sendfile\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_SOLARIS_SENDFILEV
+ "\t+ solaris-sendfilev\n"
+ #else
+ "\t- solaris-sendfilev\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_WRITEV
+ "\t+ writev\n"
+ #else
+ "\t- writev\n"
+ #endif
+ "\t+ write\n"
+ #ifdef NETWORK_WRITE_USE_MMAP
+ "\t+ mmap support\n"
+ #else
+ "\t- mmap support\n"
+ #endif
+ ;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/network_write.h b/data/lighttpd/lighttpd-1.4.53/src/network_write.h
new file mode 100644
index 000000000..a80cbcf89
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/network_write.h
@@ -0,0 +1,9 @@
+#ifndef INCLUDED_NETWORK_WRITE_H
+#define INCLUDED_NETWORK_WRITE_H
+#include "first.h"
+#include "base_decls.h"
+
+int network_write_init(server *srv);
+const char * network_write_show_handlers(void);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/plugin.c b/data/lighttpd/lighttpd-1.4.53/src/plugin.c
new file mode 100644
index 000000000..a509e4e65
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/plugin.c
@@ -0,0 +1,544 @@
+#include "first.h"
+
+#include "plugin.h"
+#include "base.h"
+#include "log.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_VALGRIND_VALGRIND_H
+# include <valgrind/valgrind.h>
+#endif
+
+#if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
+# include <dlfcn.h>
+#endif
+/*
+ *
+ * if you change this enum to add a new callback, be sure
+ * - that PLUGIN_FUNC_SIZEOF is the last entry
+ * - that you add PLUGIN_TO_SLOT twice:
+ * 1. as callback-dispatcher
+ * 2. in plugins_call_init()
+ *
+ */
+
+typedef struct {
+ PLUGIN_DATA;
+} plugin_data;
+
+typedef enum {
+ PLUGIN_FUNC_UNSET,
+
+ PLUGIN_FUNC_HANDLE_URI_CLEAN,
+ PLUGIN_FUNC_HANDLE_URI_RAW,
+ PLUGIN_FUNC_HANDLE_REQUEST_ENV,
+ PLUGIN_FUNC_HANDLE_REQUEST_DONE,
+ PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT,
+ PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR,
+ PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
+ PLUGIN_FUNC_HANDLE_TRIGGER,
+ PLUGIN_FUNC_HANDLE_SIGHUP,
+ PLUGIN_FUNC_HANDLE_WAITPID,
+ PLUGIN_FUNC_HANDLE_SUBREQUEST,
+ PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
+ PLUGIN_FUNC_HANDLE_RESPONSE_START,
+ PLUGIN_FUNC_HANDLE_DOCROOT,
+ PLUGIN_FUNC_HANDLE_PHYSICAL,
+ PLUGIN_FUNC_CONNECTION_RESET,
+ PLUGIN_FUNC_INIT,
+ PLUGIN_FUNC_CLEANUP,
+ PLUGIN_FUNC_SET_DEFAULTS,
+
+ PLUGIN_FUNC_SIZEOF
+} plugin_t;
+
+static plugin *plugin_init(void) {
+ plugin *p;
+
+ p = calloc(1, sizeof(*p));
+ force_assert(NULL != p);
+
+ return p;
+}
+
+static void plugin_free(plugin *p) {
+#if !defined(LIGHTTPD_STATIC)
+ int use_dlclose = 1;
+#endif
+
+ if (p->name) buffer_free(p->name);
+#if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
+ /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
+#endif
+
+#if !defined(LIGHTTPD_STATIC)
+ if (use_dlclose && p->lib) {
+#if defined(__WIN32)
+) FreeLibrary(p->lib);
+#else
+ dlclose(p->lib);
+#endif
+ }
+#endif
+
+ free(p);
+}
+
+static int plugins_register(server *srv, plugin *p) {
+ plugin **ps;
+ if (0 == srv->plugins.size) {
+ srv->plugins.size = 4;
+ srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps));
+ force_assert(NULL != srv->plugins.ptr);
+ srv->plugins.used = 0;
+ } else if (srv->plugins.used == srv->plugins.size) {
+ srv->plugins.size += 4;
+ srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
+ force_assert(NULL != srv->plugins.ptr);
+ }
+
+ ps = srv->plugins.ptr;
+ ps[srv->plugins.used++] = p;
+
+ return 0;
+}
+
+/**
+ *
+ *
+ *
+ */
+
+#if defined(LIGHTTPD_STATIC)
+
+/* pre-declare functions, as there is no header for them */
+#define PLUGIN_INIT(x)\
+ int x ## _plugin_init(plugin *p);
+
+#include "plugin-static.h"
+
+#undef PLUGIN_INIT
+
+/* build NULL-terminated table of name + init-function */
+
+typedef struct {
+ const char* name;
+ int (*plugin_init)(plugin *p);
+} plugin_load_functions;
+
+static const plugin_load_functions load_functions[] = {
+#define PLUGIN_INIT(x) \
+ { #x, &x ## _plugin_init },
+
+#include "plugin-static.h"
+
+ { NULL, NULL }
+#undef PLUGIN_INIT
+};
+
+int plugins_load(server *srv) {
+ plugin *p;
+ size_t i, j;
+
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ data_string *d = (data_string *)srv->srvconf.modules->data[i];
+ char *module = d->value->ptr;
+
+ for (j = 0; j < i; j++) {
+ if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "Cannot load plugin", d->value,
+ "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
+ continue;
+ }
+ }
+
+ for (j = 0; load_functions[j].name; ++j) {
+ if (0 == strcmp(load_functions[j].name, module)) {
+ p = plugin_init();
+ if ((*load_functions[j].plugin_init)(p)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
+ plugin_free(p);
+ return -1;
+ }
+ plugins_register(srv, p);
+ break;
+ }
+ }
+ if (!load_functions[j].name) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#else /* defined(LIGHTTPD_STATIC) */
+int plugins_load(server *srv) {
+ plugin *p;
+ int (*init)(plugin *pl);
+ size_t i, j;
+
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ data_string *d = (data_string *)srv->srvconf.modules->data[i];
+ char *module = d->value->ptr;
+
+ for (j = 0; j < i; j++) {
+ if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "Cannot load plugin", d->value,
+ "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
+ continue;
+ }
+ }
+
+ buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
+
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
+ buffer_append_string(srv->tmp_buf, module);
+#if defined(__WIN32) || defined(__CYGWIN__)
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
+#else
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
+#endif
+
+ p = plugin_init();
+#ifdef __WIN32
+ if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL);
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
+ lpMsgBuf, srv->tmp_buf);
+
+ plugin_free(p);
+
+ return -1;
+
+ }
+#else
+ if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
+ srv->tmp_buf, dlerror());
+
+ plugin_free(p);
+
+ return -1;
+ }
+
+#endif
+ buffer_copy_string(srv->tmp_buf, module);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
+
+#ifdef __WIN32
+ init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
+
+ if (init == NULL) {
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL);
+
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
+
+ plugin_free(p);
+ return -1;
+ }
+
+#else
+#if 1
+ init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
+#else
+ *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
+#endif
+ if (NULL == init) {
+ const char *error = dlerror();
+ if (error != NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym:", error);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym symbol not found:", srv->tmp_buf->ptr);
+ }
+
+ plugin_free(p);
+ return -1;
+ }
+
+#endif
+ if ((*init)(p)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
+
+ plugin_free(p);
+ return -1;
+ }
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
+#endif
+ plugins_register(srv, p);
+ }
+
+ return 0;
+}
+#endif /* defined(LIGHTTPD_STATIC) */
+
+#define PLUGIN_TO_SLOT(x, y) \
+ handler_t plugins_call_##y(server *srv, connection *con) {\
+ plugin **slot;\
+ size_t j;\
+ slot = ((plugin ***)(srv->plugin_slots))[x];\
+ if (!slot) return HANDLER_GO_ON;\
+ for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
+ plugin *p = slot[j];\
+ handler_t r;\
+ switch(r = p->y(srv, con, p->data)) {\
+ case HANDLER_GO_ON:\
+ break;\
+ case HANDLER_FINISHED:\
+ case HANDLER_COMEBACK:\
+ case HANDLER_WAIT_FOR_EVENT:\
+ case HANDLER_WAIT_FOR_FD:\
+ case HANDLER_ERROR:\
+ return r;\
+ default:\
+ log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
+ return HANDLER_ERROR;\
+ }\
+ }\
+ return HANDLER_GO_ON;\
+ }
+
+/**
+ * plugins that use
+ *
+ * - server *srv
+ * - connection *con
+ * - void *p_d (plugin_data *)
+ */
+
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
+
+#undef PLUGIN_TO_SLOT
+
+#define PLUGIN_TO_SLOT(x, y) \
+ handler_t plugins_call_##y(server *srv) {\
+ plugin **slot;\
+ size_t j;\
+ if (!srv->plugin_slots) return HANDLER_GO_ON;\
+ slot = ((plugin ***)(srv->plugin_slots))[x];\
+ if (!slot) return HANDLER_GO_ON;\
+ for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
+ plugin *p = slot[j];\
+ handler_t r;\
+ switch(r = p->y(srv, p->data)) {\
+ case HANDLER_GO_ON:\
+ break;\
+ case HANDLER_FINISHED:\
+ case HANDLER_COMEBACK:\
+ case HANDLER_WAIT_FOR_EVENT:\
+ case HANDLER_WAIT_FOR_FD:\
+ case HANDLER_ERROR:\
+ return r;\
+ default:\
+ log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
+ return HANDLER_ERROR;\
+ }\
+ }\
+ return HANDLER_GO_ON;\
+ }
+
+/**
+ * plugins that use
+ *
+ * - server *srv
+ * - void *p_d (plugin_data *)
+ */
+
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
+
+#undef PLUGIN_TO_SLOT
+
+handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) {
+ plugin ** const slot =
+ ((plugin ***)(srv->plugin_slots))[PLUGIN_FUNC_HANDLE_WAITPID];
+ if (!slot) return HANDLER_GO_ON;
+ for (size_t i = 0; i < srv->plugins.used && slot[i]; ++i) {
+ plugin *p = slot[i];
+ handler_t r = p->handle_waitpid(srv, p->data, pid, status);
+ if (r != HANDLER_GO_ON) return r;
+ }
+ return HANDLER_GO_ON;
+}
+
+#if 0
+/**
+ *
+ * special handler
+ *
+ */
+handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
+ size_t i;
+ plugin **ps;
+
+ ps = srv->plugins.ptr;
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ plugin *p = ps[i];
+ if (p->handle_fdevent) {
+ handler_t r;
+ switch(r = p->handle_fdevent(srv, fdc, p->data)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ case HANDLER_COMEBACK:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_ERROR:
+ return r;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "d", r);
+ break;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+#endif
+/**
+ *
+ * - call init function of all plugins to init the plugin-internals
+ * - added each plugin that supports has callback to the corresponding slot
+ *
+ * - is only called once.
+ */
+
+handler_t plugins_call_init(server *srv) {
+ size_t i;
+ plugin **ps;
+
+ ps = srv->plugins.ptr;
+
+ /* fill slots */
+
+ srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
+ force_assert(NULL != srv->plugin_slots);
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ size_t j;
+ /* check which calls are supported */
+
+ plugin *p = ps[i];
+
+#define PLUGIN_TO_SLOT(x, y) \
+ if (p->y) { \
+ plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
+ if (!slot) { \
+ slot = calloc(srv->plugins.used, sizeof(*slot));\
+ force_assert(NULL != slot); \
+ ((plugin ***)(srv->plugin_slots))[x] = slot; \
+ } \
+ for (j = 0; j < srv->plugins.used; j++) { \
+ if (slot[j]) continue;\
+ slot[j] = p;\
+ break;\
+ }\
+ }
+
+
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_WAITPID, handle_waitpid);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
+#undef PLUGIN_TO_SLOT
+
+ if (p->init) {
+ if (NULL == (p->data = p->init())) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "plugin-init failed for module", p->name);
+ return HANDLER_ERROR;
+ }
+
+ /* used for con->mode, DIRECT == 0, plugins above that */
+ ((plugin_data *)(p->data))->id = i + 1;
+
+ if (p->version != LIGHTTPD_VERSION_ID) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "plugin-version doesn't match lighttpd-version for", p->name);
+ return HANDLER_ERROR;
+ }
+ } else {
+ p->data = NULL;
+ }
+
+ if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+void plugins_free(server *srv) {
+ size_t i;
+ plugins_call_cleanup(srv);
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ plugin *p = ((plugin **)srv->plugins.ptr)[i];
+
+ plugin_free(p);
+ }
+
+ for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
+ plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
+
+ if (slot) free(slot);
+ }
+
+ free(srv->plugin_slots);
+ srv->plugin_slots = NULL;
+
+ free(srv->plugins.ptr);
+ srv->plugins.ptr = NULL;
+ srv->plugins.used = 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/plugin.h b/data/lighttpd/lighttpd-1.4.53/src/plugin.h
new file mode 100644
index 000000000..97961a9b6
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/plugin.h
@@ -0,0 +1,96 @@
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+#include "array.h"
+#include "configfile.h"
+
+#define SERVER_FUNC(x) \
+ static handler_t x(server *srv, void *p_d)
+
+#define CONNECTION_FUNC(x) \
+ static handler_t x(server *srv, connection *con, void *p_d)
+
+#define INIT_FUNC(x) \
+ static void *x(void)
+
+#define FREE_FUNC SERVER_FUNC
+#define TRIGGER_FUNC SERVER_FUNC
+#define SETDEFAULTS_FUNC SERVER_FUNC
+#define SIGHUP_FUNC SERVER_FUNC
+
+#define SUBREQUEST_FUNC CONNECTION_FUNC
+#define PHYSICALPATH_FUNC CONNECTION_FUNC
+#define REQUESTDONE_FUNC CONNECTION_FUNC
+#define URIHANDLER_FUNC CONNECTION_FUNC
+
+#define PLUGIN_DATA size_t id
+
+typedef struct {
+ size_t version;
+
+ buffer *name; /* name of the plugin */
+
+ void *(* init) ();
+ handler_t (* priv_defaults) (server *srv, void *p_d);
+ handler_t (* set_defaults) (server *srv, void *p_d);
+ handler_t (* cleanup) (server *srv, void *p_d);
+ /* is called ... */
+ handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
+ handler_t (* handle_sighup) (server *srv, void *p_d); /* at a sighup */
+ handler_t (* handle_waitpid) (server *srv, void *p_d, pid_t pid, int status); /* upon a child process exit */
+
+ handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
+ handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
+ handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
+ handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path */
+ handler_t (* handle_request_env) (server *srv, connection *con, void *p_d); /* (deferred env populate) */
+ handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
+ handler_t (* handle_connection_accept) (server *srv, connection *con, void *p_d); /* after accept() socket */
+ handler_t (* handle_connection_shut_wr)(server *srv, connection *con, void *p_d); /* done writing to socket */
+ handler_t (* handle_connection_close) (server *srv, connection *con, void *p_d); /* before close() of socket */
+
+
+
+ handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
+
+ /* when a handler for the request
+ * has to be found
+ */
+ handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
+ handler_t (* handle_response_start) (server *srv, connection *con, void *p_d); /* before response headers are written */
+ handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* after request done or request abort */
+ void *data;
+
+ /* dlopen handle */
+ void *lib;
+} plugin;
+
+int plugins_load(server *srv);
+void plugins_free(server *srv);
+
+handler_t plugins_call_handle_uri_raw(server *srv, connection *con);
+handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
+handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
+handler_t plugins_call_handle_subrequest(server *srv, connection *con);
+handler_t plugins_call_handle_response_start(server *srv, connection *con);
+handler_t plugins_call_handle_request_env(server *srv, connection *con);
+handler_t plugins_call_handle_request_done(server *srv, connection *con);
+handler_t plugins_call_handle_docroot(server *srv, connection *con);
+handler_t plugins_call_handle_physical(server *srv, connection *con);
+handler_t plugins_call_handle_connection_accept(server *srv, connection *con);
+handler_t plugins_call_handle_connection_shut_wr(server *srv, connection *con);
+handler_t plugins_call_handle_connection_close(server *srv, connection *con);
+handler_t plugins_call_connection_reset(server *srv, connection *con);
+
+handler_t plugins_call_handle_trigger(server *srv);
+handler_t plugins_call_handle_sighup(server *srv);
+handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status);
+
+handler_t plugins_call_init(server *srv);
+handler_t plugins_call_set_defaults(server *srv);
+handler_t plugins_call_cleanup(server *srv);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/rand.c b/data/lighttpd/lighttpd-1.4.53/src/rand.c
new file mode 100644
index 000000000..af24d46d7
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/rand.c
@@ -0,0 +1,232 @@
+#include "first.h"
+
+#include "rand.h"
+#include "base.h"
+#include "fdevent.h"
+#include "safe_memclear.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "sys-crypto.h"
+#ifdef USE_OPENSSL_CRYPTO
+#include <openssl/opensslv.h> /* OPENSSL_VERSION_NUMBER */
+#include <openssl/rand.h>
+#endif
+#ifdef HAVE_GETENTROPY
+#include <sys/random.h>
+#endif
+#ifdef HAVE_LINUX_RANDOM_H
+#include <sys/syscall.h>
+#include <linux/random.h>
+#endif
+#ifdef RNDGETENTCNT
+#include <sys/ioctl.h>
+#endif
+
+/* Take some reasonable steps to attempt to *seed* random number generators with
+ * cryptographically random data. Some of these initialization routines may
+ * block, and are intended to be called only at startup in lighttpd, or
+ * immediately after fork() to start lighttpd workers.
+ *
+ * Update: li_rand_init() is now deferred until first use so that installations
+ * that do not use modules which use these routines do need to potentially block
+ * at startup. Current use by core lighttpd modules is in mod_auth HTTP Digest
+ * auth and in mod_usertrack. Deferring collection of random data until first
+ * use may allow sufficient entropy to be collected by kernel before first use,
+ * helping reduce or avoid situations in low-entropy-generating embedded devices
+ * which might otherwise block lighttpd for minutes at device startup.
+ * Further discussion in https://redmine.lighttpd.net/boards/2/topics/6981
+ *
+ * Note: results from li_rand_pseudo_bytes() are not necessarily
+ * cryptographically random and must not be used for purposes such
+ * as key generation which require cryptographic randomness.
+ *
+ * https://wiki.openssl.org/index.php/Random_Numbers
+ * https://wiki.openssl.org/index.php/Random_fork-safety
+ *
+ * openssl random number generators are not thread-safe by default
+ * https://wiki.openssl.org/index.php/Manual:Threads(3)
+ *
+ * RFE: add more paranoid checks from the following to improve confidence:
+ * http://insanecoding.blogspot.co.uk/2014/05/a-good-idea-with-bad-usage-devurandom.html
+ * RFE: retry on EINTR
+ * RFE: check RAND_status()
+ */
+
+static int li_getentropy (void *buf, size_t buflen)
+{
+ #ifdef HAVE_GETENTROPY
+ return getentropy(buf, buflen);
+ #else
+ /*(see NOTES section in 'man getrandom' on Linux)*/
+ #if defined(HAVE_GETRANDOM) || defined(SYS_getrandom)
+ if (buflen <= 256) {
+ #ifdef HAVE_GETRANDOM /*(not implemented in glibc yet)*/
+ int num = getrandom(buf, buflen, 0);
+ #elif defined(SYS_getrandom)
+ /* https://lwn.net/Articles/605828/ */
+ /* https://bbs.archlinux.org/viewtopic.php?id=200039 */
+ int num = (int)syscall(SYS_getrandom, buf, buflen, 0);
+ #endif
+ if (num == (int)buflen) return 0;
+ if (num < 0) return num; /* -1 */
+ }
+ #else
+ UNUSED(buf);
+ UNUSED(buflen);
+ #endif
+ errno = EIO;
+ return -1;
+ #endif
+}
+
+static int li_rand_device_bytes (unsigned char *buf, int num)
+{
+ /* randomness from these devices is cryptographically strong,
+ * unless /dev/urandom is low on entropy */
+
+ static const char * const devices[] = {
+ #ifdef __OpenBSD__
+ "/dev/arandom",
+ #endif
+ "/dev/urandom",
+ "/dev/random"
+ };
+
+ /* device files might not be available in chroot environment,
+ * so prefer syscall, if available */
+ if (0 == li_getentropy(buf, (size_t)num)) return 1;
+
+ for (unsigned int u = 0; u < sizeof(devices)/sizeof(devices[0]); ++u) {
+ /*(some systems might have symlink to another device; omit O_NOFOLLOW)*/
+ int fd = fdevent_open_cloexec(devices[u], O_RDONLY, 0);
+ if (fd >= 0) {
+ ssize_t rd = 0;
+ #ifdef RNDGETENTCNT
+ int entropy;
+ if (0 == ioctl(fd, (unsigned long)(RNDGETENTCNT), &entropy)
+ && entropy >= num*8)
+ #endif
+ rd = read(fd, buf, (size_t)num);
+ close(fd);
+ if (rd == num) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int li_rand_inited;
+static unsigned short xsubi[3];
+
+static void li_rand_init (void)
+{
+ /* (intended to be called at init and after fork() in order to re-seed PRNG
+ * so that forked children, grandchildren, etc do not share PRNG seed)
+ * https://github.com/ramsey/uuid/issues/80
+ * https://www.agwa.name/blog/post/libressls_prng_is_unsafe_on_linux
+ * (issue in early version of libressl has since been fixed)
+ * https://github.com/libressl-portable/portable/commit/32d9eeeecf4e951e1566d5f4a42b36ea37b60f35
+ */
+ unsigned int u;
+ li_rand_inited = 1;
+ if (1 == li_rand_device_bytes((unsigned char *)xsubi, (int)sizeof(xsubi))) {
+ u = ((unsigned int)xsubi[0] << 16) | xsubi[1];
+ }
+ else {
+ #ifdef HAVE_ARC4RANDOM_BUF
+ u = arc4random();
+ arc4random_buf(xsubi, sizeof(xsubi));
+ #else
+ /* NOTE: not cryptographically random !!! */
+ srand((unsigned int)(time(NULL) ^ getpid()));
+ for (u = 0; u < sizeof(unsigned short); ++u)
+ /* coverity[dont_call : FALSE] */
+ xsubi[u] = (unsigned short)(rand() & 0xFFFF);
+ u = ((unsigned int)xsubi[0] << 16) | xsubi[1];
+ #endif
+ }
+ srand(u); /*(initialize just in case rand() used elsewhere)*/
+ #ifdef HAVE_SRANDOM
+ srandom(u); /*(initialize just in case random() used elsewhere)*/
+ #endif
+ #ifdef USE_OPENSSL_CRYPTO
+ RAND_poll();
+ RAND_seed(xsubi, (int)sizeof(xsubi));
+ #endif
+}
+
+void li_rand_reseed (void)
+{
+ if (li_rand_inited) li_rand_init();
+}
+
+int li_rand_pseudo (void)
+{
+ /* randomness *is not* cryptographically strong */
+ /* (attempt to use better mechanisms to replace the more portable rand()) */
+ #ifdef USE_OPENSSL_CRYPTO /* (openssl 1.1.0 deprecates RAND_pseudo_bytes()) */
+ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ int i;
+ if (-1 != RAND_pseudo_bytes((unsigned char *)&i, sizeof(i))) return i;
+ #endif
+ #endif
+ if (!li_rand_inited) li_rand_init();
+ #ifdef HAVE_ARC4RANDOM_BUF
+ return (int)arc4random();
+ #elif defined(HAVE_SRANDOM)
+ /* coverity[dont_call : FALSE] */
+ return (int)random();
+ #elif defined(HAVE_JRAND48)
+ /*(FYI: jrand48() reentrant, but use of file-scoped static xsubi[] is not)*/
+ /* coverity[dont_call : FALSE] */
+ return (int)jrand48(xsubi);
+ #else
+ /* coverity[dont_call : FALSE] */
+ return rand();
+ #endif
+}
+
+void li_rand_pseudo_bytes (unsigned char *buf, int num)
+{
+ for (int i = 0; i < num; ++i)
+ buf[i] = li_rand_pseudo() & 0xFF;
+}
+
+int li_rand_bytes (unsigned char *buf, int num)
+{
+ #ifdef USE_OPENSSL_CRYPTO
+ int rc = RAND_bytes(buf, num);
+ if (-1 != rc) {
+ return rc;
+ }
+ #endif
+ if (1 == li_rand_device_bytes(buf, num)) {
+ return 1;
+ }
+ else {
+ /* NOTE: not cryptographically random !!! */
+ li_rand_pseudo_bytes(buf, num);
+ /*(openssl RAND_pseudo_bytes rc for non-cryptographically random data)*/
+ return 0;
+ }
+}
+
+void li_rand_cleanup (void)
+{
+ #ifdef USE_OPENSSL_CRYPTO
+ #if OPENSSL_VERSION_NUMBER < 0x10100000L
+ RAND_cleanup();
+ #endif
+ #endif
+ safe_memclear(xsubi, sizeof(xsubi));
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/rand.h b/data/lighttpd/lighttpd-1.4.53/src/rand.h
new file mode 100644
index 000000000..d80f6a12a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/rand.h
@@ -0,0 +1,11 @@
+#ifndef LI_RAND_H_
+#define LI_RAND_H_
+#include "first.h"
+
+int li_rand_pseudo (void);
+void li_rand_pseudo_bytes (unsigned char *buf, int num);
+void li_rand_reseed (void);
+int li_rand_bytes (unsigned char *buf, int num);
+void li_rand_cleanup (void);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/request.c b/data/lighttpd/lighttpd-1.4.53/src/request.c
new file mode 100644
index 000000000..f2d3c5276
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/request.c
@@ -0,0 +1,1201 @@
+#include "first.h"
+
+#include "request.h"
+#include "base.h"
+#include "burl.h"
+#include "http_header.h"
+#include "http_kv.h"
+#include "log.h"
+#include "sock_addr.h"
+
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys-strings.h>
+
+static int request_check_hostname(buffer *host) {
+ enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
+ size_t i;
+ int label_len = 0;
+ size_t host_len, hostport_len;
+ char *colon;
+ int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
+ int level = 0;
+
+ /*
+ * hostport = host [ ":" port ]
+ * host = hostname | IPv4address | IPv6address
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+ * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ * IPv6address = "[" ... "]"
+ * port = *digit
+ */
+
+ /* IPv6 adress */
+ if (host->ptr[0] == '[') {
+ char *c = host->ptr + 1;
+ int colon_cnt = 0;
+
+ /* check the address inside [...] */
+ for (; *c && *c != ']'; c++) {
+ if (*c == ':') {
+ if (++colon_cnt > 7) {
+ return -1;
+ }
+ } else if (!light_isxdigit(*c) && '.' != *c) {
+ return -1;
+ }
+ }
+
+ /* missing ] */
+ if (!*c) {
+ return -1;
+ }
+
+ /* check port */
+ if (*(c+1) == ':') {
+ for (c += 2; *c; c++) {
+ if (!light_isdigit(*c)) {
+ return -1;
+ }
+ }
+ }
+ else if ('\0' != *(c+1)) {
+ /* only a port is allowed to follow [...] */
+ return -1;
+ }
+ return 0;
+ }
+
+ hostport_len = host_len = buffer_string_length(host);
+
+ if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
+ char *c = colon + 1;
+
+ /* check portnumber */
+ for (; *c; c++) {
+ if (!light_isdigit(*c)) return -1;
+ }
+
+ /* remove the port from the host-len */
+ host_len = colon - host->ptr;
+ }
+
+ /* Host is empty */
+ if (host_len == 0) return -1;
+
+ /* if the hostname ends in a "." strip it */
+ if (host->ptr[host_len-1] == '.') {
+ /* shift port info one left */
+ if (NULL != colon) memmove(colon-1, colon, hostport_len - host_len);
+ buffer_string_set_length(host, --hostport_len);
+ if (--host_len == 0) return -1;
+ }
+
+
+ /* scan from the right and skip the \0 */
+ for (i = host_len; i-- > 0; ) {
+ const char c = host->ptr[i];
+
+ switch (stage) {
+ case TOPLABEL:
+ if (c == '.') {
+ /* only switch stage, if this is not the last character */
+ if (i != host_len - 1) {
+ if (label_len == 0) {
+ return -1;
+ }
+
+ /* check the first character at right of the dot */
+ if (is_ip == 0) {
+ if (!light_isalnum(host->ptr[i+1])) {
+ return -1;
+ }
+ } else if (!light_isdigit(host->ptr[i+1])) {
+ is_ip = 0;
+ } else if ('-' == host->ptr[i+1]) {
+ return -1;
+ } else {
+ /* just digits */
+ is_ip = 1;
+ }
+
+ stage = DOMAINLABEL;
+
+ label_len = 0;
+ level++;
+ } else if (i == 0) {
+ /* just a dot and nothing else is evil */
+ return -1;
+ }
+ } else if (i == 0) {
+ /* the first character of the hostname */
+ if (!light_isalnum(c)) {
+ return -1;
+ }
+ label_len++;
+ } else {
+ if (c != '-' && !light_isalnum(c)) {
+ return -1;
+ }
+ if (is_ip == -1) {
+ if (!light_isdigit(c)) is_ip = 0;
+ }
+ label_len++;
+ }
+
+ break;
+ case DOMAINLABEL:
+ if (is_ip == 1) {
+ if (c == '.') {
+ if (label_len == 0) {
+ return -1;
+ }
+
+ label_len = 0;
+ level++;
+ } else if (!light_isdigit(c)) {
+ return -1;
+ } else {
+ label_len++;
+ }
+ } else {
+ if (c == '.') {
+ if (label_len == 0) {
+ return -1;
+ }
+
+ /* c is either - or alphanum here */
+ if ('-' == host->ptr[i+1]) {
+ return -1;
+ }
+
+ label_len = 0;
+ level++;
+ } else if (i == 0) {
+ if (!light_isalnum(c)) {
+ return -1;
+ }
+ label_len++;
+ } else {
+ if (c != '-' && !light_isalnum(c)) {
+ return -1;
+ }
+ label_len++;
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* a IP has to consist of 4 parts */
+ if (is_ip == 1 && level != 3) {
+ return -1;
+ }
+
+ if (label_len == 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int http_request_host_normalize(buffer *b, int scheme_port) {
+ /*
+ * check for and canonicalize numeric IP address and portnum (optional)
+ * (IP address may be followed by ":portnum" (optional))
+ * - IPv6: "[...]"
+ * - IPv4: "x.x.x.x"
+ * - IPv4: 12345678 (32-bit decimal number)
+ * - IPv4: 012345678 (32-bit octal number)
+ * - IPv4: 0x12345678 (32-bit hex number)
+ *
+ * allow any chars (except ':' and '\0' and stray '[' or ']')
+ * (other code may check chars more strictly or more pedantically)
+ * ':' delimits (optional) port at end of string
+ * "[]" wraps IPv6 address literal
+ * '\0' should have been rejected earlier were it present
+ *
+ * any chars includes, but is not limited to:
+ * - allow '-' any where, even at beginning of word
+ * (security caution: might be confused for cmd flag if passed to shell)
+ * - allow all-digit TLDs
+ * (might be mistaken for IPv4 addr by inet_aton()
+ * unless non-digits appear in subdomain)
+ */
+
+ /* Note: not using getaddrinfo() since it does not support "[]" around IPv6
+ * and is not as lenient as inet_aton() and inet_addr() for IPv4 strings.
+ * Not using inet_pton() (when available) on IPv4 for similar reasons. */
+
+ const char * const p = b->ptr;
+ const size_t blen = buffer_string_length(b);
+ long port = 0;
+
+ if (*p != '[') {
+ char * const colon = (char *)memchr(p, ':', blen);
+ if (colon) {
+ if (*p == ':') return -1; /*(empty host then port, or naked IPv6)*/
+ if (colon[1] != '\0') {
+ char *e;
+ port = strtol(colon+1, &e, 0); /*(allow decimal, octal, hex)*/
+ if (0 < port && port <= USHRT_MAX && *e == '\0') {
+ /* valid port */
+ } else {
+ return -1;
+ }
+ } /*(else ignore stray colon at string end)*/
+ buffer_string_set_length(b, (size_t)(colon - p)); /*(remove port str)*/
+ }
+
+ if (light_isdigit(*p)) do {
+ /* (IPv4 address literal or domain starting w/ digit (e.g. 3com))*/
+ /* (check one-element cache of normalized IPv4 address string) */
+ static struct { char s[INET_ADDRSTRLEN]; size_t n; } laddr;
+ size_t n = colon ? (size_t)(colon - p) : blen;
+ sock_addr addr;
+ if (n == laddr.n && 0 == memcmp(p, laddr.s, n)) break;
+ if (1 == sock_addr_inet_pton(&addr, p, AF_INET, 0)) {
+ sock_addr_inet_ntop_copy_buffer(b, &addr);
+ n = buffer_string_length(b);
+ if (n < sizeof(laddr.s)) memcpy(laddr.s, b->ptr, (laddr.n = n));
+ }
+ } while (0);
+ } else do { /* IPv6 addr */
+ #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+
+ /* (check one-element cache of normalized IPv4 address string) */
+ static struct { char s[INET6_ADDRSTRLEN]; size_t n; } laddr;
+ sock_addr addr;
+ char *bracket = b->ptr+blen-1;
+ char *percent = strchr(b->ptr+1, '%');
+ size_t len;
+ int rc;
+ char buf[INET6_ADDRSTRLEN+16]; /*(+16 for potential %interface name)*/
+ if (blen <= 2) return -1; /*(invalid "[]")*/
+ if (*bracket != ']') {
+ bracket = (char *)memchr(b->ptr+1, ']', blen-1);
+ if (NULL == bracket || bracket[1] != ':' || bracket - b->ptr == 1){
+ return -1;
+ }
+ if (bracket[2] != '\0') { /*(ignore stray colon at string end)*/
+ char *e;
+ port = strtol(bracket+2, &e, 0); /*(allow decimal, octal, hex)*/
+ if (0 < port && port <= USHRT_MAX && *e == '\0') {
+ /* valid port */
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ len = (size_t)((percent ? percent : bracket) - (b->ptr+1));
+ if (laddr.n == len && 0 == memcmp(laddr.s, b->ptr+1, len)) {
+ /* truncate after ']' and re-add normalized port, if needed */
+ buffer_string_set_length(b, (size_t)(bracket - b->ptr + 1));
+ break;
+ }
+
+ *bracket = '\0';/*(terminate IPv6 string)*/
+ if (percent) *percent = '\0'; /*(remove %interface from address)*/
+ rc = sock_addr_inet_pton(&addr, b->ptr+1, AF_INET6, 0);
+ if (percent) *percent = '%'; /*(restore %interface)*/
+ *bracket = ']'; /*(restore bracket)*/
+ if (1 != rc) return -1;
+
+ sock_addr_inet_ntop(&addr, buf, sizeof(buf));
+ len = strlen(buf);
+ if (percent) {
+ if (percent > bracket) return -1;
+ if (len + (size_t)(bracket - percent) >= sizeof(buf)) return -1;
+ if (len < sizeof(laddr.s)) memcpy(laddr.s, buf, (laddr.n = len));
+ memcpy(buf+len, percent, (size_t)(bracket - percent));
+ len += (size_t)(bracket - percent);
+ }
+ buffer_string_set_length(b, 1); /* truncate after '[' */
+ buffer_append_string_len(b, buf, len);
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+
+ #else
+
+ return -1;
+
+ #endif
+ } while (0);
+
+ if (0 != port && port != scheme_port) {
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_int(b, (int)port);
+ }
+
+ return 0;
+}
+
+static int scheme_port (const buffer *scheme)
+{
+ return buffer_is_equal_string(scheme, CONST_STR_LEN("https")) ? 443 : 80;
+}
+
+int http_request_host_policy (connection *con, buffer *b, const buffer *scheme) {
+ return (((con->conf.http_parseopts & HTTP_PARSEOPT_HOST_STRICT)
+ && 0 != request_check_hostname(b))
+ || ((con->conf.http_parseopts & HTTP_PARSEOPT_HOST_NORMALIZE)
+ && 0 != http_request_host_normalize(b, scheme_port(scheme))));
+}
+
+static int http_request_split_value(array *vals, const char *current, size_t len) {
+ int state = 0;
+ const char *token_start = NULL, *token_end = NULL;
+ /*
+ * parse
+ *
+ * val1, val2, val3, val4
+ *
+ * into a array (more or less a explode() incl. stripping of whitespaces
+ */
+
+ for (size_t i = 0; i <= len; ++i, ++current) {
+ switch (state) {
+ case 0: /* find start of a token */
+ switch (*current) {
+ case ' ':
+ case '\t': /* skip white space */
+ case ',': /* skip empty token */
+ break;
+ case '\0': /* end of string */
+ return 0;
+ default:
+ /* found real data, switch to state 1 to find the end of the token */
+ token_start = token_end = current;
+ state = 1;
+ break;
+ }
+ break;
+ case 1: /* find end of token and last non white space character */
+ switch (*current) {
+ case ' ':
+ case '\t':
+ /* space - don't update token_end */
+ break;
+ case ',':
+ case '\0': /* end of string also marks the end of a token */
+ array_insert_value(vals, token_start, token_end-token_start+1);
+ state = 0;
+ break;
+ default:
+ /* no white space, update token_end to include current character */
+ token_end = current;
+ break;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int request_uri_is_valid_char(unsigned char c) {
+ if (c <= 32) return 0;
+ if (c == 127) return 0;
+ if (c == 255) return 0;
+
+ return 1;
+}
+
+static void http_request_missing_CR_before_LF(server *srv, connection *con) {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "missing CR before LF in header -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request);
+ }
+}
+
+enum keep_alive_set {
+ HTTP_CONNECTION_UNSET,
+ HTTP_CONNECTION_KEEPALIVE,
+ HTTP_CONNECTION_CLOSE,
+};
+
+typedef struct {
+ enum keep_alive_set keep_alive_set;
+ char con_length_set;
+ char *reqline_host;
+ int reqline_hostlen;
+} parse_header_state;
+
+static void init_parse_header_state(parse_header_state* state) {
+ state->keep_alive_set = HTTP_CONNECTION_UNSET;
+ state->con_length_set = 0;
+ state->reqline_host = NULL;
+ state->reqline_hostlen = 0;
+}
+
+/* add header to list of headers
+ * certain headers are also parsed
+ * might drop a header if deemed unnecessary/broken
+ *
+ * returns 0 on error
+ */
+static int parse_single_header(server *srv, connection *con, parse_header_state *state, char *k, size_t klen, char *v, size_t vlen) {
+ const enum http_header_e id = http_header_hkey_get(k, klen);
+ buffer **saveb = NULL;
+
+ /* strip leading whitespace */
+ for (; vlen > 0 && (v[0] == ' ' || v[0] == '\t'); ++v, --vlen) ;
+
+ /* strip trailing whitespace */
+ while (vlen > 0 && (v[vlen - 1] == ' ' || v[vlen - 1] == '\t')) --vlen;
+
+ /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
+ if (0 == vlen) return 1; /* ignore header */
+
+ /*
+ * Note: k might not be '\0'-terminated
+ */
+
+ switch (id) {
+ /*case HTTP_HEADER_OTHER:*/
+ default:
+ break;
+ case HTTP_HEADER_HOST:
+ if (!(con->request.htags & HTTP_HEADER_HOST)) {
+ saveb = &con->request.http_host;
+ if (vlen >= 1024) { /*(expecting < 256)*/
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "uri-authority too long -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n", con->request.request);
+ }
+ return 0; /* invalid header */
+ }
+ }
+ else if (state->reqline_host) {
+ /* ignore all Host: headers as we got Host in request line */
+ return 1; /* ignore header */
+ }
+ else {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Host-header -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n", con->request.request);
+ }
+ return 0; /* invalid header */
+ }
+ break;
+ case HTTP_HEADER_CONNECTION:
+ {
+ array * const vals = srv->split_vals;
+ array_reset_data_strings(vals);
+ http_request_split_value(vals, v, vlen); /* split on , */
+ for (size_t vi = 0; vi < vals->used; ++vi) {
+ data_string *dsv = (data_string *)vals->data[vi];
+ if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value),
+ CONST_STR_LEN("keep-alive"))) {
+ state->keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
+ break;
+ }
+ else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value),
+ CONST_STR_LEN("close"))) {
+ state->keep_alive_set = HTTP_CONNECTION_CLOSE;
+ break;
+ }
+ }
+ }
+ break;
+ case HTTP_HEADER_CONTENT_TYPE:
+ if (con->request.htags & HTTP_HEADER_CONTENT_TYPE) {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Content-Type-header -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n", con->request.request);
+ }
+ return 0; /* invalid header */
+ }
+ break;
+ case HTTP_HEADER_IF_NONE_MATCH:
+ /* if dup, only the first one will survive */
+ if (con->request.htags & HTTP_HEADER_IF_NONE_MATCH) {
+ return 1; /* ignore header */
+ }
+ break;
+ case HTTP_HEADER_CONTENT_LENGTH:
+ if (!(con->request.htags & HTTP_HEADER_CONTENT_LENGTH)) {
+ char *err;
+ off_t r = strtoll(v, &err, 10);
+
+ if (*err == '\0' && r >= 0) {
+ con->request.content_length = r;
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "content-length broken:", v, "-> 400");
+ return 0; /* invalid header */
+ }
+ }
+ else {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Content-Length-header -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n", con->request.request);
+ }
+ return 0; /* invalid header */
+ }
+ break;
+ case HTTP_HEADER_IF_MODIFIED_SINCE:
+ if (con->request.htags & HTTP_HEADER_IF_MODIFIED_SINCE) {
+ /* Proxies sometimes send dup headers
+ * if they are the same we ignore the second
+ * if not, we raise an error */
+ buffer *vb =
+ http_header_request_get(con, HTTP_HEADER_IF_MODIFIED_SINCE,
+ CONST_STR_LEN("If-Modified-Since"));
+ if (vb && buffer_is_equal_caseless_string(vb, v, vlen)) {
+ /* ignore it if they are the same */
+ return 1; /* ignore header */
+ }
+ else {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate If-Modified-Since header -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n", con->request.request);
+ }
+ return 0; /* invalid header */
+ }
+ }
+ break;
+ }
+
+ con->request.htags |= id;
+ http_header_request_append(con, id, k, klen, v, vlen);
+
+ if (saveb) {
+ *saveb = http_header_request_get(con, id, k, klen);
+ }
+
+ return 1;
+}
+
+static size_t http_request_parse_reqline(server *srv, connection *con, parse_header_state *state) {
+ char *uri = NULL, *proto = NULL, *method = NULL;
+ int line = 0;
+
+ int request_line_stage = 0;
+ size_t i, first, ilen;
+ const unsigned int http_header_strict = (con->conf.http_parseopts & HTTP_PARSEOPT_HEADER_STRICT);
+
+ /*
+ * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
+ * Option : "^([-a-zA-Z]+): (.+)$"
+ * End : "^$"
+ */
+
+ if (con->conf.log_request_header) {
+ log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
+ "fd:", con->fd,
+ "request-len:", buffer_string_length(con->request.request),
+ "\n", con->request.request);
+ }
+
+ if (con->request_count > 1 &&
+ con->request.request->ptr[0] == '\r' &&
+ con->request.request->ptr[1] == '\n') {
+ /* we are in keep-alive and might get \r\n after a previous POST request.*/
+
+ #ifdef __COVERITY__
+ if (buffer_string_length(con->request.request) < 2) {
+ return 0;
+ }
+ #endif
+ /* coverity[overflow_sink : FALSE] */
+ buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, buffer_string_length(con->request.request) - 2);
+ } else if (con->request_count > 0 &&
+ con->request.request->ptr[1] == '\n') {
+ /* we are in keep-alive and might get \n after a previous POST request.*/
+ if (http_header_strict) {
+ http_request_missing_CR_before_LF(srv, con);
+ return 0;
+ }
+ #ifdef __COVERITY__
+ if (buffer_string_length(con->request.request) < 1) {
+ return 0;
+ }
+ #endif
+ /* coverity[overflow_sink : FALSE] */
+ buffer_copy_string_len(con->parse_request, con->request.request->ptr + 1, buffer_string_length(con->request.request) - 1);
+ } else {
+ /* fill the local request buffer */
+ buffer_copy_buffer(con->parse_request, con->request.request);
+ }
+
+ /* parse the first line of the request
+ *
+ * should be:
+ *
+ * <method> <uri> <protocol>\r\n
+ * */
+ ilen = buffer_string_length(con->parse_request);
+ for (i = 0, first = 0; i < ilen && line == 0; i++) {
+ switch(con->parse_request->ptr[i]) {
+ case '\r':
+ if (con->parse_request->ptr[i+1] != '\n') break;
+ /* fall through */
+ case '\n':
+ {
+ http_method_t r;
+ char *nuri = NULL;
+ size_t j, jlen;
+
+ buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
+
+ /* \r\n -> \0\0 */
+ if (con->parse_request->ptr[i] == '\r') {
+ con->parse_request->ptr[i] = '\0';
+ ++i;
+ } else if (http_header_strict) { /* '\n' */
+ http_request_missing_CR_before_LF(srv, con);
+ return 0;
+ }
+ con->parse_request->ptr[i] = '\0';
+
+ if (request_line_stage != 2) {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ return 0;
+ }
+
+ proto = con->parse_request->ptr + first;
+
+ *(uri - 1) = '\0';
+ *(proto - 1) = '\0';
+
+ /* we got the first one :) */
+ if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
+ con->http_status = 501;
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ return 0;
+ }
+
+ con->request.http_method = r;
+
+ /*
+ * RFC2616 says:
+ *
+ * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+ *
+ * */
+ if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
+ char * major = proto + sizeof("HTTP/") - 1;
+ char * minor = strchr(major, '.');
+ char *err = NULL;
+ int major_num = 0, minor_num = 0;
+
+ int invalid_version = 0;
+
+ if (NULL == minor || /* no dot */
+ minor == major || /* no major */
+ *(minor + 1) == '\0' /* no minor */) {
+ invalid_version = 1;
+ } else {
+ *minor = '\0';
+ major_num = strtol(major, &err, 10);
+
+ if (*err != '\0') invalid_version = 1;
+
+ *minor++ = '.';
+ minor_num = strtol(minor, &err, 10);
+
+ if (*err != '\0') invalid_version = 1;
+ }
+
+ if (invalid_version) {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ return 0;
+ }
+
+ if (major_num == 1 && minor_num == 1) {
+ con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
+ } else if (major_num == 1 && minor_num == 0) {
+ con->request.http_version = HTTP_VERSION_1_0;
+ } else {
+ con->http_status = 505;
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ return 0;
+ }
+ } else {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ return 0;
+ }
+
+ if (*uri == '/') {
+ /* (common case) */
+ buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
+ } else if (0 == buffer_caseless_compare(uri, 7, "http://", 7) &&
+ NULL != (nuri = strchr(uri + 7, '/'))) {
+ state->reqline_host = uri + 7;
+ state->reqline_hostlen = nuri - state->reqline_host;
+
+ buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
+ } else if (0 == buffer_caseless_compare(uri, 8, "https://", 8) &&
+ NULL != (nuri = strchr(uri + 8, '/'))) {
+ state->reqline_host = uri + 8;
+ state->reqline_hostlen = nuri - state->reqline_host;
+
+ buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
+ } else if (!http_header_strict
+ || (HTTP_METHOD_CONNECT == con->request.http_method && (uri[0] == ':' || light_isdigit(uri[0])))
+ || (HTTP_METHOD_OPTIONS == con->request.http_method && uri[0] == '*' && uri[1] == '\0')) {
+ /* everything looks good so far */
+ buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "request-URI parse error -> 400 for:", uri);
+ return 0;
+ }
+
+ /* check uri for invalid characters */
+ jlen = buffer_string_length(con->request.uri);
+ if ((con->conf.http_parseopts & HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT)) {
+ j = jlen; /* URI will be checked in http_response_prepare() */
+ } else if (http_header_strict) {
+ for (j = 0; j < jlen && request_uri_is_valid_char(con->request.uri->ptr[j]); j++) ;
+ } else {
+ char *z = memchr(con->request.uri->ptr, '\0', jlen);
+ j = (NULL == z) ? jlen : (size_t)(z - con->request.uri->ptr);
+ }
+ if (j < jlen) {
+ if (srv->srvconf.log_request_header_on_error) {
+ unsigned char buf[2];
+ buf[0] = con->request.uri->ptr[j];
+ buf[1] = '\0';
+
+ if (con->request.uri->ptr[j] > 32 &&
+ con->request.uri->ptr[j] != 127) {
+ /* the character is printable -> print it */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "invalid character in URI -> 400",
+ buf);
+ } else {
+ /* a control-character, print ascii-code */
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "invalid character in URI -> 400",
+ con->request.uri->ptr[j]);
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ return 0;
+ }
+
+ buffer_copy_buffer(con->request.orig_uri, con->request.uri);
+
+ con->http_status = 0;
+
+ line++;
+ first = i+1;
+ }
+ break;
+ case ' ':
+ switch(request_line_stage) {
+ case 0:
+ /* GET|POST|... */
+ method = con->parse_request->ptr + first;
+ first = i + 1;
+ break;
+ case 1:
+ /* /foobar/... */
+ uri = con->parse_request->ptr + first;
+ first = i + 1;
+ break;
+ default:
+ /* ERROR, one space to much */
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ return 0;
+ }
+
+ request_line_stage++;
+ break;
+ }
+ }
+
+ if (buffer_string_is_empty(con->request.uri)) {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ return 0;
+ }
+
+ if (state->reqline_host) {
+ /* Insert as host header */
+ if (state->reqline_hostlen >= 1024) { /*(expecting < 256)*/
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "uri-authority too long -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n", con->request.request);
+ }
+ return 0;
+ }
+ http_header_request_set(con, HTTP_HEADER_HOST, CONST_STR_LEN("Host"), state->reqline_host, state->reqline_hostlen);
+ con->request.http_host = http_header_request_get(con, HTTP_HEADER_HOST, CONST_STR_LEN("Host"));
+ }
+
+ return i;
+}
+
+int http_request_parse(server *srv, connection *con) {
+ char *value = NULL;
+ size_t i, first, ilen;
+ const unsigned int http_header_strict = (con->conf.http_parseopts & HTTP_PARSEOPT_HEADER_STRICT);
+
+ parse_header_state state;
+ init_parse_header_state(&state);
+
+ i = first = http_request_parse_reqline(srv, con, &state);
+ if (0 == i) goto failure;
+
+ if (con->parse_request->ptr[i] == ' ' || con->parse_request->ptr[i] == '\t') {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request);
+ }
+ goto failure;
+ }
+
+ ilen = buffer_string_length(con->parse_request);
+ for (int is_key = 1, key_len = 0, done = 0; i <= ilen && !done; ++i) {
+ char *cur = con->parse_request->ptr + i;
+
+ if (is_key) {
+ /**
+ * 1*<any CHAR except CTLs or separators>
+ * CTLs == 0-31 + 127, CHAR = 7-bit ascii (0..127)
+ *
+ */
+ switch(*cur) {
+ case ' ':
+ case '\t':
+ /* skip every thing up to the : */
+ do { ++cur; } while (*cur == ' ' || *cur == '\t');
+ if (*cur != ':') {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ goto failure;
+ }
+ /* fall through */
+ case ':':
+ is_key = 0;
+ key_len = i - first;
+ value = cur + 1;
+ i = cur - con->parse_request->ptr;
+ break;
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case '\\':
+ case '\"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ case '{':
+ case '}':
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsds",
+ "invalid character in key", con->request.request, cur, *cur, "-> 400");
+
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ goto failure;
+ case '\r':
+ if (con->parse_request->ptr[i+1] == '\n' && i == first) {
+ /* End of Header */
+ con->parse_request->ptr[i] = '\0';
+ con->parse_request->ptr[i+1] = '\0';
+
+ i++;
+
+ done = 1;
+ } else {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ goto failure;
+ }
+ break;
+ case '\n':
+ if (http_header_strict) {
+ http_request_missing_CR_before_LF(srv, con);
+ goto failure;
+ } else if (i == first) {
+ con->parse_request->ptr[i] = '\0';
+ done = 1;
+ break;
+ }
+ /* fall through */
+ default:
+ if (http_header_strict ? (*cur < 32 || ((unsigned char)*cur) >= 127) : *cur == '\0') {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsds",
+ "invalid character in key", con->request.request, cur, *cur, "-> 400");
+
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ goto failure;
+ }
+ /* ok */
+ break;
+ }
+ } else {
+ switch(*cur) {
+ case '\r':
+ if (cur[1] != '\n') {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "CR without LF", con->request.request, "-> 400");
+ }
+
+ goto failure;
+ }
+ if (cur[2] == ' ' || cur[2] == '\t') { /* header line folding */
+ cur[0] = ' ';
+ cur[1] = ' ';
+ i += 2;
+ continue;
+ }
+ ++i;
+ /* fall through */
+ case '\n':
+ if (*cur == '\n') {
+ if (http_header_strict) {
+ http_request_missing_CR_before_LF(srv, con);
+ goto failure;
+ }
+ if (cur[1] == ' ' || cur[1] == '\t') { /* header line folding */
+ cur[0] = ' ';
+ i += 1;
+ continue;
+ }
+ }
+
+ /* End of Headerline */
+ *cur = '\0'; /*(for if value is further parsed and '\0' is expected at end of string)*/
+
+ if (!parse_single_header(srv, con, &state, con->parse_request->ptr + first, key_len, value, cur - value)) {
+ /* parse_single_header should already have logged it */
+ goto failure;
+ }
+
+ first = i+1;
+ is_key = 1;
+ value = NULL;
+ break;
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (http_header_strict ? (*cur >= 0 && *cur < 32) : *cur == '\0') {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "invalid char in header", (int)*cur, "-> 400");
+ }
+
+ goto failure;
+ }
+ break;
+ }
+ }
+ }
+
+ con->header_len = i;
+
+ /* do some post-processing */
+
+ if (con->request.http_version == HTTP_VERSION_1_1) {
+ if (state.keep_alive_set != HTTP_CONNECTION_CLOSE) {
+ /* no Connection-Header sent */
+
+ /* HTTP/1.1 -> keep-alive default TRUE */
+ con->keep_alive = 1;
+ } else {
+ con->keep_alive = 0;
+ }
+
+ /* RFC 2616, 14.23 */
+ if (con->request.http_host == NULL ||
+ buffer_string_is_empty(con->request.http_host)) {
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+ goto failure;
+ }
+ } else {
+ if (state.keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
+ /* no Connection-Header sent */
+
+ /* HTTP/1.0 -> keep-alive default FALSE */
+ con->keep_alive = 1;
+ } else {
+ con->keep_alive = 0;
+ }
+ }
+
+ /* check hostname field if it is set */
+ if (!buffer_is_empty(con->request.http_host) &&
+ 0 != http_request_host_policy(con, con->request.http_host, con->proto)) {
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Invalid Hostname -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ goto failure;
+ }
+
+ if (con->request.htags & HTTP_HEADER_TRANSFER_ENCODING) {
+ buffer *vb = http_header_request_get(con, HTTP_HEADER_TRANSFER_ENCODING, CONST_STR_LEN("Transfer-Encoding"));
+ if (NULL != vb) {
+ if (con->request.http_version == HTTP_VERSION_1_0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "HTTP/1.0 with Transfer-Encoding (bad HTTP/1.0 proxy?) -> 400");
+ goto failure;
+ }
+
+ if (0 != strcasecmp(vb->ptr, "chunked")) {
+ /* Transfer-Encoding might contain additional encodings,
+ * which are not currently supported by lighttpd */
+ con->http_status = 501; /* Not Implemented */
+ goto failure;
+ }
+
+ /* reset value for Transfer-Encoding, a hop-by-hop header,
+ * which must not be blindly forwarded to backends */
+ http_header_request_unset(con, HTTP_HEADER_TRANSFER_ENCODING, CONST_STR_LEN("Transfer-Encoding"));
+
+ /*(note: ignore whether or not Content-Length was provided)*/
+ if (con->request.htags & HTTP_HEADER_CONTENT_LENGTH) {
+ http_header_request_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
+ }
+
+ state.con_length_set = 1;
+ con->request.content_length = -1;
+ }
+ }
+ else if (con->request.htags & HTTP_HEADER_CONTENT_LENGTH) {
+ state.con_length_set = 1;
+ }
+
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_HEAD:
+ /* content-length is forbidden for those */
+ if (state.con_length_set && con->request.content_length != 0) {
+ /* content-length is missing */
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "GET/HEAD with content-length -> 400");
+
+ goto failure;
+ }
+ break;
+ case HTTP_METHOD_POST:
+ /* content-length is required for them */
+ if (!state.con_length_set) {
+ /* content-length is missing */
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "POST-request, but content-length missing -> 411");
+
+ con->http_status = 411;
+ goto failure;
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ /* check if we have read post data */
+ if (state.con_length_set) {
+ /* we have content */
+ if (con->request.content_length != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+
+failure:
+ con->keep_alive = 0;
+ con->response.keep_alive = 0;
+ if (!con->http_status) con->http_status = 400;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/request.h b/data/lighttpd/lighttpd-1.4.53/src/request.h
new file mode 100644
index 000000000..ac5f1a14f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/request.h
@@ -0,0 +1,12 @@
+#ifndef _REQUEST_H_
+#define _REQUEST_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+int http_request_parse(server *srv, connection *con);
+int http_request_host_normalize(buffer *b, int scheme_port);
+int http_request_host_policy(connection *con, buffer *b, const buffer *scheme);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/response.c b/data/lighttpd/lighttpd-1.4.53/src/response.c
new file mode 100644
index 000000000..09ab8d23b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/response.c
@@ -0,0 +1,702 @@
+#include "first.h"
+
+#include "response.h"
+#include "base.h"
+#include "burl.h"
+#include "fdevent.h"
+#include "http_header.h"
+#include "http_kv.h"
+#include "log.h"
+#include "stat_cache.h"
+#include "chunk.h"
+
+#include "configfile.h"
+
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int http_response_write_header(server *srv, connection *con) {
+ buffer * const b = chunkqueue_prepend_buffer_open(con->write_queue);
+
+ if (con->request.http_version == HTTP_VERSION_1_1) {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
+ } else {
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
+ }
+ http_status_append(b, con->http_status);
+
+ /* disable keep-alive if requested */
+ if (con->request_count > con->conf.max_keep_alive_requests || 0 == con->conf.max_keep_alive_idle) {
+ con->keep_alive = 0;
+ } else if (0 != con->request.content_length
+ && con->request.content_length != con->request_content_queue->bytes_in
+ && (con->mode == DIRECT || 0 == con->conf.stream_request_body)) {
+ con->keep_alive = 0;
+ } else {
+ con->keep_alive_idle = con->conf.max_keep_alive_idle;
+ }
+
+ if ((con->response.htags & HTTP_HEADER_UPGRADE) && con->request.http_version == HTTP_VERSION_1_1) {
+ http_header_response_set(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("upgrade"));
+ } else if (0 == con->keep_alive) {
+ http_header_response_set(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
+ } else if (con->request.http_version == HTTP_VERSION_1_0) {/*(&& con->keep_alive != 0)*/
+ http_header_response_set(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
+ }
+
+ if (304 == con->http_status && (con->response.htags & HTTP_HEADER_CONTENT_ENCODING)) {
+ http_header_response_unset(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"));
+ }
+
+ /* add all headers */
+ for (size_t i = 0; i < con->response.headers->used; ++i) {
+ const data_string * const ds = (data_string *)con->response.headers->data[i];
+
+ if (buffer_string_is_empty(ds->value) || buffer_string_is_empty(ds->key)) continue;
+ if ((ds->key->ptr[0] & 0xdf) == 'X') {
+ if (0 == strncasecmp(ds->key->ptr, CONST_STR_LEN("X-Sendfile"))) continue;
+ if (0 == strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-"))) {
+ if (0 == strncasecmp(ds->key->ptr+sizeof("X-LIGHTTPD-")-1, CONST_STR_LEN("KBytes-per-second"))) {
+ /* "X-LIGHTTPD-KBytes-per-second" */
+ long limit = strtol(ds->value->ptr, NULL, 10);
+ if (limit > 0
+ && (limit < con->conf.kbytes_per_second
+ || 0 == con->conf.kbytes_per_second)) {
+ if (limit > USHRT_MAX) limit= USHRT_MAX;
+ con->conf.kbytes_per_second = limit;
+ }
+ }
+ continue;
+ }
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+ buffer_append_string_buffer(b, ds->key);
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
+ buffer_append_string_buffer(b, ds->value);
+ }
+
+ if (!(con->response.htags & HTTP_HEADER_DATE)) {
+ /* HTTP/1.1 requires a Date: header */
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: "));
+
+ /* cache the generated timestamp */
+ if (srv->cur_ts != srv->last_generated_date_ts) {
+ buffer_clear(srv->ts_date_str);
+ buffer_append_strftime(srv->ts_date_str, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
+ srv->last_generated_date_ts = srv->cur_ts;
+ }
+
+ buffer_append_string_buffer(b, srv->ts_date_str);
+ }
+
+ if (!(con->response.htags & HTTP_HEADER_SERVER)) {
+ if (!buffer_string_is_empty(con->conf.server_tag)) {
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: "));
+ buffer_append_string_len(b, CONST_BUF_LEN(con->conf.server_tag));
+ }
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+ con->bytes_header = buffer_string_length(b);
+
+ if (con->conf.log_response_header) {
+ log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
+ }
+
+ chunkqueue_prepend_buffer_commit(con->write_queue);
+ return 0;
+}
+
+static handler_t http_response_physical_path_check(server *srv, connection *con) {
+ stat_cache_entry *sce = NULL;
+
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ /* file exists */
+ } else {
+ char *pathinfo = NULL;
+ switch (errno) {
+ case EACCES:
+ con->http_status = 403;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ case ENAMETOOLONG:
+ /* file name to be read was too long. return 404 */
+ case ENOENT:
+ con->http_status = 404;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- file not found");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ case ENOTDIR:
+ /* PATH_INFO ! :) */
+ break;
+ default:
+ /* we have no idea what happend. let's tell the user so. */
+ con->http_status = 500;
+ buffer_reset(con->physical.path);
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsb",
+ "file not found ... or so: ", strerror(errno),
+ con->uri.path,
+ "->", con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ /* not found, perhaps PATHINFO */
+
+ {
+ /*(might check at startup that s->document_root does not end in '/')*/
+ size_t len = buffer_string_length(con->physical.basedir);
+ if (len > 0 && '/' == con->physical.basedir->ptr[len-1]) --len;
+ pathinfo = con->physical.path->ptr + len;
+ if ('/' != *pathinfo) {
+ pathinfo = NULL;
+ }
+ else if (pathinfo == con->physical.path->ptr) { /*(basedir is "/")*/
+ pathinfo = strchr(pathinfo+1, '/');
+ }
+ }
+
+ for (char *pprev = pathinfo; pathinfo; pprev = pathinfo, pathinfo = strchr(pathinfo+1, '/')) {
+ stat_cache_entry *nsce = NULL;
+ buffer_copy_string_len(srv->tmp_buf, con->physical.path->ptr, pathinfo - con->physical.path->ptr);
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &nsce)) {
+ pathinfo = pathinfo != pprev ? pprev : NULL;
+ break;
+ }
+ sce = nsce;
+ if (!S_ISDIR(sce->st.st_mode)) break;
+ }
+
+ if (NULL == pathinfo || !S_ISREG(sce->st.st_mode)) {
+ /* no it really doesn't exists */
+ con->http_status = 404;
+
+ if (con->conf.log_file_not_found) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "file not found:", con->uri.path,
+ "->", con->physical.path);
+ }
+
+ buffer_reset(con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we have a PATHINFO */
+ if (pathinfo) {
+ size_t len = strlen(pathinfo), reqlen;
+ if (con->conf.force_lowercase_filenames
+ && len <= (reqlen = buffer_string_length(con->request.uri))
+ && 0 == strncasecmp(con->request.uri->ptr + reqlen - len, pathinfo, len)) {
+ /* attempt to preserve case-insensitive PATH_INFO
+ * (works in common case where mod_alias, mod_magnet, and other modules
+ * have not modified the PATH_INFO portion of request URI, or did so
+ * with exactly the PATH_INFO desired) */
+ buffer_copy_string_len(con->request.pathinfo, con->request.uri->ptr + reqlen - len, len);
+ } else {
+ buffer_copy_string_len(con->request.pathinfo, pathinfo, len);
+ }
+
+ /*
+ * shorten uri.path
+ */
+
+ buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - len);
+ buffer_string_set_length(con->physical.path, (size_t)(pathinfo - con->physical.path->ptr));
+ }
+ }
+
+#ifdef HAVE_LSTAT
+ if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
+ con->http_status = 403;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ };
+#endif
+ if (S_ISDIR(sce->st.st_mode)) {
+ if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') {
+ /* redirect to .../ */
+
+ http_response_redirect_to_directory(srv, con);
+
+ return HANDLER_FINISHED;
+ }
+#ifdef HAVE_LSTAT
+ } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
+#else
+ } else if (!S_ISREG(sce->st.st_mode)) {
+#endif
+ /* any special handling of non-reg files ?*/
+ }
+
+ return HANDLER_GO_ON;
+}
+
+handler_t http_response_prepare(server *srv, connection *con) {
+ handler_t r;
+
+ /* looks like someone has already done a decision */
+ if (con->mode == DIRECT &&
+ (con->http_status != 0 && con->http_status != 200)) {
+ /* remove a packets in the queue */
+ if (con->file_finished == 0) {
+ http_response_body_clear(con, 0);
+ }
+
+ return HANDLER_FINISHED;
+ }
+
+ /* no decision yet, build conf->filename */
+ if (con->mode == DIRECT && buffer_is_empty(con->physical.path)) {
+
+ /* we only come here when we have the parse the full request again
+ *
+ * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
+ * problem here as mod_setenv might get called multiple times
+ *
+ * fastcgi-auth might lead to a COMEBACK too
+ * fastcgi again dead server too
+ *
+ * mod_compress might add headers twice too
+ *
+ * */
+
+ if (!con->async_callback) {
+
+ config_cond_cache_reset(srv, con);
+ config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */
+
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
+ }
+
+ /**
+ * prepare strings
+ *
+ * - uri.path_raw
+ * - uri.path
+ * - uri.query
+ *
+ */
+
+ /**
+ * Name according to RFC 2396
+ *
+ * - scheme
+ * - authority
+ * - path
+ * - query
+ *
+ * (scheme)://(authority)(path)?(query)#fragment
+ *
+ *
+ */
+
+ /* take initial scheme value from connection-level state
+ * (request con->uri.scheme can be overwritten for later,
+ * for example by mod_extforward or mod_magnet) */
+ buffer_copy_buffer(con->uri.scheme, con->proto);
+ buffer_copy_buffer(con->uri.authority, con->request.http_host);
+ buffer_to_lower(con->uri.authority);
+
+ if (con->request.http_method == HTTP_METHOD_CONNECT
+ || (con->request.http_method == HTTP_METHOD_OPTIONS
+ && con->request.uri->ptr[0] == '*'
+ && con->request.uri->ptr[1] == '\0')) {
+ /* CONNECT ... (or) OPTIONS * ... */
+ buffer_copy_buffer(con->uri.path_raw, con->request.uri);
+ buffer_copy_buffer(con->uri.path, con->uri.path_raw);
+ buffer_reset(con->uri.query);
+ } else {
+ char *qstr;
+ if (con->conf.http_parseopts & HTTP_PARSEOPT_URL_NORMALIZE) {
+ /*size_t len = buffer_string_length(con->request.uri);*/
+ int qs = burl_normalize(con->request.uri, srv->tmp_buf, con->conf.http_parseopts);
+ if (-2 == qs) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid character in URI -> 400",
+ con->request.uri);
+ con->keep_alive = 0;
+ con->http_status = 400; /* Bad Request */
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ }
+ qstr = (-1 == qs) ? NULL : con->request.uri->ptr+qs;
+ #if 0 /* future: might enable here, or below for all requests */
+ /* (Note: total header size not recalculated on HANDLER_COMEBACK
+ * even if other request headers changed during processing)
+ * (If (0 != con->loops_per_request), then the generated request
+ * is too large. Should a different error be returned?) */
+ con->header_len -= len;
+ len = buffer_string_length(con->request.uri);
+ con->header_len += len;
+ if (len > MAX_HTTP_REQUEST_URI) {
+ con->keep_alive = 0;
+ con->http_status = 414; /* Request-URI Too Long */
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ }
+ if (con->header_len > MAX_HTTP_REQUEST_HEADER) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "request header fields too large:", con->header_len, "-> 431");
+ con->keep_alive = 0;
+ con->http_status = 431; /* Request Header Fields Too Large */
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ }
+ #endif
+ } else {
+ qstr = strchr(con->request.uri->ptr, '#');/* discard fragment */
+ if (qstr) buffer_string_set_length(con->request.uri, qstr - con->request.uri->ptr);
+ qstr = strchr(con->request.uri->ptr, '?');
+ }
+
+ /** extract query string from request.uri */
+ if (NULL != qstr) {
+ const char * const pstr = con->request.uri->ptr;
+ const size_t plen = (size_t)(qstr - pstr);
+ const size_t rlen = buffer_string_length(con->request.uri);
+ buffer_copy_string_len(con->uri.query, qstr + 1, rlen - plen - 1);
+ buffer_copy_string_len(con->uri.path_raw, pstr, plen);
+ } else {
+ buffer_reset(con->uri.query);
+ buffer_copy_buffer(con->uri.path_raw, con->request.uri);
+ }
+
+ /* decode url to path
+ *
+ * - decode url-encodings (e.g. %20 -> ' ')
+ * - remove path-modifiers (e.g. /../)
+ */
+
+ buffer_copy_buffer(con->uri.path, con->uri.path_raw);
+ buffer_urldecode_path(con->uri.path);
+ buffer_path_simplify(con->uri.path, con->uri.path);
+ if (buffer_string_is_empty(con->uri.path) || con->uri.path->ptr[0] != '/') {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "uri-path does not begin with '/':", con->uri.path, "-> 400");
+ con->keep_alive = 0;
+ con->http_status = 400;
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ }
+ }
+
+ con->conditional_is_valid[COMP_SERVER_SOCKET] = 1; /* SERVERsocket */
+ con->conditional_is_valid[COMP_HTTP_SCHEME] = 1; /* Scheme: */
+ con->conditional_is_valid[COMP_HTTP_HOST] = 1; /* Host: */
+ con->conditional_is_valid[COMP_HTTP_REMOTE_IP] = 1; /* Client-IP */
+ con->conditional_is_valid[COMP_HTTP_REQUEST_METHOD] = 1; /* REQUEST_METHOD */
+ con->conditional_is_valid[COMP_HTTP_URL] = 1; /* HTTPurl */
+ con->conditional_is_valid[COMP_HTTP_QUERY_STRING] = 1; /* HTTPqs */
+ con->conditional_is_valid[COMP_HTTP_REQUEST_HEADER] = 1; /* HTTP request header */
+ config_patch_connection(srv, con);
+
+ /* do we have to downgrade to 1.0 ? */
+ if (!con->conf.allow_http11) {
+ con->request.http_version = HTTP_VERSION_1_0;
+ }
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- splitting Request-URI");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Request-URI : ", con->request.uri);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI-scheme : ", con->uri.scheme);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI-authority : ", con->uri.authority);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (raw) : ", con->uri.path_raw);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (clean): ", con->uri.path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query);
+ }
+
+ /* con->conf.max_request_size is in kBytes */
+ if (0 != con->conf.max_request_size &&
+ (off_t)con->request.content_length > ((off_t)con->conf.max_request_size << 10)) {
+ log_error_write(srv, __FILE__, __LINE__, "sos",
+ "request-size too long:", (off_t) con->request.content_length, "-> 413");
+ con->keep_alive = 0;
+ con->http_status = 413;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+
+ }
+ con->async_callback = 0; /* reset */
+
+
+ /**
+ *
+ * call plugins
+ *
+ * - based on the raw URL
+ *
+ */
+
+ switch(r = plugins_call_handle_uri_raw(srv, con)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ case HANDLER_COMEBACK:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_ERROR:
+ return r;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r);
+ break;
+ }
+
+ /**
+ *
+ * call plugins
+ *
+ * - based on the clean URL
+ *
+ */
+
+ switch(r = plugins_call_handle_uri_clean(srv, con)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ case HANDLER_COMEBACK:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_ERROR:
+ return r;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "");
+ break;
+ }
+
+ if (con->request.http_method == HTTP_METHOD_OPTIONS &&
+ con->uri.path->ptr[0] == '*' && con->uri.path->ptr[1] == '\0') {
+ /* option requests are handled directly without checking of the path */
+
+ http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
+
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+ if (con->request.http_method == HTTP_METHOD_CONNECT && con->mode == DIRECT) {
+ con->keep_alive = 0;
+ con->http_status = 405; /* Method Not Allowed */
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ }
+
+ /***
+ *
+ * border
+ *
+ * logical filename (URI) becomes a physical filename here
+ *
+ *
+ *
+ */
+
+
+
+
+ /* 1. stat()
+ * ... ISREG() -> ok, go on
+ * ... ISDIR() -> index-file -> redirect
+ *
+ * 2. pathinfo()
+ * ... ISREG()
+ *
+ * 3. -> 404
+ *
+ */
+
+ /*
+ * SEARCH DOCUMENT ROOT
+ */
+
+ /* set a default */
+
+ buffer_copy_buffer(con->physical.doc_root, con->conf.document_root);
+ buffer_copy_buffer(con->physical.rel_path, con->uri.path);
+
+#if defined(__WIN32) || defined(__CYGWIN__)
+ /* strip dots from the end and spaces
+ *
+ * windows/dos handle those filenames as the same file
+ *
+ * foo == foo. == foo..... == "foo... " == "foo.. ./"
+ *
+ * This will affect in some cases PATHINFO
+ *
+ * on native windows we could prepend the filename with \\?\ to circumvent
+ * this behaviour. I have no idea how to push this through cygwin
+ *
+ * */
+
+ if (con->physical.rel_path->used > 1) {
+ buffer *b = con->physical.rel_path;
+ size_t len = buffer_string_length(b);
+
+ /* strip trailing " /" or "./" once */
+ if (len > 1 &&
+ b->ptr[len - 1] == '/' &&
+ (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) {
+ len -= 2;
+ }
+ /* strip all trailing " " and "." */
+ while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len;
+ buffer_string_set_length(b, len);
+ }
+#endif
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+ /* the docroot plugin should set the doc_root and might also set the physical.path
+ * for us (all vhost-plugins are supposed to set the doc_root)
+ * */
+ switch(r = plugins_call_handle_docroot(srv, con)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ case HANDLER_COMEBACK:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_ERROR:
+ return r;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "");
+ break;
+ }
+
+ /* MacOS X and Windows can't distiguish between upper and lower-case
+ *
+ * convert to lower-case
+ */
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(con->physical.rel_path);
+ }
+
+ /* the docroot plugins might set the servername, if they don't we take http-host */
+ if (buffer_string_is_empty(con->server_name)) {
+ buffer_copy_buffer(con->server_name, con->uri.authority);
+ }
+
+ /**
+ * create physical filename
+ * -> physical.path = docroot + rel_path
+ *
+ */
+
+ buffer_copy_buffer(con->physical.basedir, con->physical.doc_root);
+ buffer_copy_buffer(con->physical.path, con->physical.doc_root);
+ buffer_append_path_len(con->physical.path, CONST_BUF_LEN(con->physical.rel_path));
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ if (con->request.http_method == HTTP_METHOD_CONNECT) {
+ /* do not permit CONNECT requests to hit filesystem hooks
+ * since the CONNECT URI bypassed path normalization */
+ /* (This check is located here so that con->physical.path
+ * is filled in above to avoid repeating work next time
+ * http_response_prepare() is called while processing request) */
+ } else
+ switch(r = plugins_call_handle_physical(srv, con)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ case HANDLER_COMEBACK:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_ERROR:
+ return r;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "");
+ break;
+ }
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Basedir :", con->physical.basedir);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+ }
+
+ /*
+ * Noone catched away the file from normal path of execution yet (like mod_access)
+ *
+ * Go on and check of the file exists at all
+ */
+
+ if (con->mode == DIRECT) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ r = http_response_physical_path_check(srv, con);
+ if (HANDLER_GO_ON != r) return r;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
+ }
+
+ /* call the handlers */
+ r = plugins_call_handle_subrequest_start(srv, con);
+ if (HANDLER_GO_ON != r) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
+ }
+ return r;
+ }
+
+ /* if we are still here, no one wanted the file, status 403 is ok I think */
+ if (con->mode == DIRECT && con->http_status == 0) {
+ con->http_status = (con->request.http_method != HTTP_METHOD_OPTIONS) ? 403 : 200;
+ return HANDLER_FINISHED;
+ }
+
+ }
+
+ r = plugins_call_handle_subrequest(srv, con);
+ if (HANDLER_GO_ON == r) r = HANDLER_FINISHED; /* request was not handled, looks like we are done */
+ return r;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/response.h b/data/lighttpd/lighttpd-1.4.53/src/response.h
new file mode 100644
index 000000000..288f4f6f8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/response.h
@@ -0,0 +1,57 @@
+#ifndef _RESPONSE_H_
+#define _RESPONSE_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+#include "array.h"
+
+#include <time.h>
+
+int http_response_parse(server *srv, connection *con);
+int http_response_write_header(server *srv, connection *con);
+
+typedef struct http_cgi_opts_t {
+ int authorizer;
+ int break_scriptfilename_for_php;
+ buffer *docroot;
+ buffer *strip_request_uri;
+} http_cgi_opts;
+
+enum {
+ BACKEND_UNSET = 0,
+ BACKEND_PROXY,
+ BACKEND_CGI,
+ BACKEND_FASTCGI,
+ BACKEND_SCGI
+};
+
+typedef struct http_response_opts_t {
+ int fdfmt;
+ int backend;
+ int authorizer;
+ unsigned short local_redir;
+ unsigned short xsendfile_allow;
+ array *xsendfile_docroot;
+ void *pdata;
+ handler_t(*parse)(server *, connection *, struct http_response_opts_t *, buffer *, size_t);
+ handler_t(*headers)(server *, connection *, struct http_response_opts_t *);
+} http_response_opts;
+
+typedef int (*http_cgi_header_append_cb)(void *vdata, const char *k, size_t klen, const char *v, size_t vlen);
+int http_cgi_headers(server *srv, connection *con, http_cgi_opts *opts, http_cgi_header_append_cb cb, void *vdata);
+
+handler_t http_response_parse_headers(server *srv, connection *con, http_response_opts *opts, buffer *hdrs);
+handler_t http_response_read(server *srv, connection *con, http_response_opts *opts, buffer *b, int fd, int *fde_ndx);
+handler_t http_response_prepare(server *srv, connection *con);
+int http_response_buffer_append_authority(server *srv, connection *con, buffer *b);
+int http_response_redirect_to_directory(server *srv, connection *con);
+int http_response_handle_cachable(server *srv, connection *con, buffer * mtime);
+void http_response_body_clear(connection *con, int preserve_length);
+void http_response_send_file (server *srv, connection *con, buffer *path);
+void http_response_backend_done (server *srv, connection *con);
+void http_response_backend_error (server *srv, connection *con);
+void http_response_upgrade_read_body_unknown(server *srv, connection *con);
+
+buffer * strftime_cache_get(server *srv, time_t last_mod);
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/safe_memclear.c b/data/lighttpd/lighttpd-1.4.53/src/safe_memclear.c
new file mode 100644
index 000000000..0e1c9dfde
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/safe_memclear.c
@@ -0,0 +1,47 @@
+#include "first.h"
+
+#include "safe_memclear.h"
+
+#include <string.h>
+
+#if !defined(HAVE_MEMSET_S) && !defined(HAVE_EXPLICIT_BZERO)
+
+# if defined(HAVE_WEAK_SYMBOLS)
+/* it seems weak functions are never inlined, even for static builds */
+__attribute__((weak)) void __li_safe_memset_hook(void *buf, size_t len);
+
+void __li_safe_memset_hook(void *buf, size_t len)
+{
+ UNUSED(buf);
+ UNUSED(len);
+}
+# endif /* HAVE_WEAK_SYMBOLS */
+
+static void* safe_memset(void *s, int c, size_t n)
+{
+ if (n > 0) {
+ volatile unsigned volatile_zero = 0;
+ volatile unsigned char *vs = (volatile unsigned char*)s;
+
+ do {
+ memset(s, c, n);
+ } while (vs[volatile_zero] != (unsigned char)c);
+# if defined(HAVE_WEAK_SYMBOLS)
+ __li_safe_memset_hook(s, n);
+# endif /* HAVE_WEAK_SYMBOLS */
+ }
+
+ return s;
+}
+#endif /* !defined(HAVE_MEMSET_S) && !defined(HAVE_EXPLICIT_BZERO) */
+
+
+void safe_memclear(void *s, size_t n) {
+#if defined(HAVE_MEMSET_S)
+ memset_s(s, n, 0, n);
+#elif defined(HAVE_EXPLICIT_BZERO)
+ explicit_bzero(s, n);
+#else
+ safe_memset(s, 0, n);
+#endif
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/safe_memclear.h b/data/lighttpd/lighttpd-1.4.53/src/safe_memclear.h
new file mode 100644
index 000000000..9fd256364
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/safe_memclear.h
@@ -0,0 +1,7 @@
+#ifndef _SAFE_MEMCLEAR_H_
+#define _SAFE_MEMCLEAR_H_
+#include "first.h"
+
+void safe_memclear(void *s, size_t n);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/server.c b/data/lighttpd/lighttpd-1.4.53/src/server.c
new file mode 100644
index 000000000..1be67c305
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/server.c
@@ -0,0 +1,2119 @@
+#include "first.h"
+
+#include "server.h"
+#include "buffer.h"
+#include "burl.h"
+#include "network.h"
+#include "log.h"
+#include "rand.h"
+#include "chunk.h"
+#include "http_auth.h"
+#include "http_vhostdb.h"
+#include "fdevent.h"
+#include "connections.h"
+#include "sock_addr.h"
+#include "stat_cache.h"
+#include "configfile.h"
+#include "plugin.h"
+#include "joblist.h"
+#include "network_write.h"
+
+#ifdef HAVE_VERSIONSTAMP_H
+# include "versionstamp.h"
+#else
+# define REPO_VERSION ""
+#endif
+
+#define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#include <locale.h>
+
+#include <stdio.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#ifdef HAVE_VALGRIND_VALGRIND_H
+# include <valgrind/valgrind.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifdef HAVE_PWD_H
+# include <grp.h>
+# include <pwd.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#ifdef HAVE_SYS_PRCTL_H
+# include <sys/prctl.h>
+#endif
+
+#include "sys-crypto.h"
+#ifdef USE_OPENSSL_CRYPTO
+#define USE_SSL
+#define TEXT_SSL " (ssl)"
+#else
+#define TEXT_SSL
+#endif
+
+#ifndef __sgi
+/* IRIX doesn't like the alarm based time() optimization */
+/* #define USE_ALARM */
+#endif
+
+static int oneshot_fd = 0;
+static volatile int pid_fd = -2;
+static server_socket_array graceful_sockets;
+static server_socket_array inherited_sockets;
+static volatile sig_atomic_t graceful_restart = 0;
+static volatile sig_atomic_t graceful_shutdown = 0;
+static volatile sig_atomic_t srv_shutdown = 0;
+static volatile sig_atomic_t handle_sig_child = 0;
+static volatile sig_atomic_t handle_sig_alarm = 1;
+static volatile sig_atomic_t handle_sig_hup = 0;
+
+#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
+static volatile siginfo_t last_sigterm_info;
+static volatile siginfo_t last_sighup_info;
+
+static void sigaction_handler(int sig, siginfo_t *si, void *context) {
+ static const siginfo_t empty_siginfo;
+ UNUSED(context);
+
+ if (!si) *(const siginfo_t **)&si = &empty_siginfo;
+
+ switch (sig) {
+ case SIGTERM:
+ srv_shutdown = 1;
+ last_sigterm_info = *si;
+ break;
+ case SIGUSR1:
+ if (!graceful_shutdown) {
+ graceful_restart = 1;
+ graceful_shutdown = 1;
+ last_sigterm_info = *si;
+ }
+ break;
+ case SIGINT:
+ if (graceful_shutdown) {
+ if (2 == graceful_restart)
+ graceful_restart = 1;
+ else
+ srv_shutdown = 1;
+ } else {
+ graceful_shutdown = 1;
+ }
+ last_sigterm_info = *si;
+
+ break;
+ case SIGALRM:
+ handle_sig_alarm = 1;
+ break;
+ case SIGHUP:
+ handle_sig_hup = 1;
+ last_sighup_info = *si;
+ break;
+ case SIGCHLD:
+ handle_sig_child = 1;
+ break;
+ }
+}
+#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
+static void signal_handler(int sig) {
+ switch (sig) {
+ case SIGTERM: srv_shutdown = 1; break;
+ case SIGUSR1:
+ if (!graceful_shutdown) {
+ graceful_restart = 1;
+ graceful_shutdown = 1;
+ }
+ break;
+ case SIGINT:
+ if (graceful_shutdown) {
+ if (2 == graceful_restart)
+ graceful_restart = 1;
+ else
+ srv_shutdown = 1;
+ } else {
+ graceful_shutdown = 1;
+ }
+ break;
+ case SIGALRM: handle_sig_alarm = 1; break;
+ case SIGHUP: handle_sig_hup = 1; break;
+ case SIGCHLD: handle_sig_child = 1; break;
+ }
+}
+#endif
+
+#ifdef HAVE_FORK
+static int daemonize(void) {
+ int pipefd[2];
+ pid_t pid;
+#ifdef SIGTTOU
+ signal(SIGTTOU, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_IGN);
+#endif
+
+ if (pipe(pipefd) < 0) exit(-1);
+
+ if (0 > (pid = fork())) exit(-1);
+
+ if (0 < pid) {
+ char buf;
+ ssize_t bytes;
+
+ close(pipefd[1]);
+ /* parent waits for grandchild to be ready */
+ do {
+ bytes = read(pipefd[0], &buf, sizeof(buf));
+ } while (bytes < 0 && EINTR == errno);
+ close(pipefd[0]);
+
+ if (bytes <= 0) {
+ /* closed fd (without writing) == failure in grandchild */
+ fputs("daemonized server failed to start; check error log for details\n", stderr);
+ exit(-1);
+ }
+
+ exit(0);
+ }
+
+ close(pipefd[0]);
+
+ if (-1 == setsid()) exit(0);
+
+ signal(SIGHUP, SIG_IGN);
+
+ if (0 != fork()) exit(0);
+
+ if (0 != chdir("/")) exit(0);
+
+ fdevent_setfd_cloexec(pipefd[1]);
+ return pipefd[1];
+}
+#endif
+
+static server *server_init(void) {
+ int i;
+ server *srv = calloc(1, sizeof(*srv));
+ force_assert(srv);
+#define CLEAN(x) \
+ srv->x = buffer_init();
+
+ CLEAN(response_header);
+ CLEAN(parse_full_path);
+ CLEAN(ts_debug_str);
+ CLEAN(ts_date_str);
+ CLEAN(errorlog_buf);
+ CLEAN(response_range);
+ CLEAN(tmp_buf);
+ srv->empty_string = buffer_init_string("");
+ CLEAN(cond_check_buf);
+
+ CLEAN(srvconf.errorlog_file);
+ CLEAN(srvconf.breakagelog_file);
+ CLEAN(srvconf.groupname);
+ CLEAN(srvconf.username);
+ CLEAN(srvconf.changeroot);
+ CLEAN(srvconf.bindhost);
+ CLEAN(srvconf.event_handler);
+ CLEAN(srvconf.pid_file);
+ CLEAN(srvconf.syslog_facility);
+
+ CLEAN(tmp_chunk_len);
+#undef CLEAN
+
+#define CLEAN(x) \
+ srv->x = array_init();
+
+ CLEAN(config_context);
+ CLEAN(config_touched);
+ CLEAN(status);
+#undef CLEAN
+
+ for (i = 0; i < FILE_CACHE_MAX; i++) {
+ srv->mtime_cache[i].mtime = (time_t)-1;
+ srv->mtime_cache[i].str = buffer_init();
+ }
+
+ li_rand_reseed();
+
+ srv->cur_ts = time(NULL);
+ srv->startup_ts = srv->cur_ts;
+
+ srv->conns = calloc(1, sizeof(*srv->conns));
+ force_assert(srv->conns);
+
+ srv->joblist = calloc(1, sizeof(*srv->joblist));
+ force_assert(srv->joblist);
+
+ srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
+ force_assert(srv->fdwaitqueue);
+
+ srv->srvconf.modules = array_init();
+ srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
+ srv->srvconf.network_backend = buffer_init();
+ srv->srvconf.upload_tempdirs = array_init();
+ srv->srvconf.reject_expect_100_with_417 = 1;
+ srv->srvconf.xattr_name = buffer_init_string("Content-Type");
+ srv->srvconf.http_header_strict = 1;
+ srv->srvconf.http_host_strict = 1; /*(implies http_host_normalize)*/
+ srv->srvconf.http_host_normalize = 0;
+ #if 0
+ srv->srvconf.http_url_normalize = HTTP_PARSEOPT_URL_NORMALIZE
+ | HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED
+ | HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT
+ | HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS
+ | HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
+ | HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE;
+ #endif
+ srv->srvconf.http_url_normalize = 0; /* temporary; change in future */
+ srv->srvconf.high_precision_timestamps = 0;
+ srv->srvconf.max_request_field_size = 8192;
+ srv->srvconf.loadavg[0] = 0.0;
+ srv->srvconf.loadavg[1] = 0.0;
+ srv->srvconf.loadavg[2] = 0.0;
+ srv->srvconf.compat_module_load = 1;
+ srv->srvconf.systemd_socket_activation = 0;
+
+ /* use syslog */
+ srv->errorlog_fd = STDERR_FILENO;
+ srv->errorlog_mode = ERRORLOG_FD;
+
+ srv->split_vals = array_init();
+ srv->request_env = plugins_call_handle_request_env;
+
+ return srv;
+}
+
+static void server_free(server *srv) {
+ size_t i;
+
+ for (i = 0; i < FILE_CACHE_MAX; i++) {
+ buffer_free(srv->mtime_cache[i].str);
+ }
+
+ if (oneshot_fd > 0) {
+ close(oneshot_fd);
+ }
+
+#define CLEAN(x) \
+ buffer_free(srv->x);
+
+ CLEAN(response_header);
+ CLEAN(parse_full_path);
+ CLEAN(ts_debug_str);
+ CLEAN(ts_date_str);
+ CLEAN(errorlog_buf);
+ CLEAN(response_range);
+ CLEAN(tmp_buf);
+ CLEAN(empty_string);
+ CLEAN(cond_check_buf);
+
+ CLEAN(srvconf.errorlog_file);
+ CLEAN(srvconf.breakagelog_file);
+ CLEAN(srvconf.groupname);
+ CLEAN(srvconf.username);
+ CLEAN(srvconf.changeroot);
+ CLEAN(srvconf.bindhost);
+ CLEAN(srvconf.event_handler);
+ CLEAN(srvconf.pid_file);
+ CLEAN(srvconf.modules_dir);
+ CLEAN(srvconf.network_backend);
+ CLEAN(srvconf.xattr_name);
+ CLEAN(srvconf.syslog_facility);
+
+ CLEAN(tmp_chunk_len);
+#undef CLEAN
+
+#if 0
+ fdevent_unregister(srv->ev, srv->fd);
+#endif
+ fdevent_free(srv->ev);
+
+ free(srv->conns);
+
+ if (srv->config_storage) {
+ for (i = 0; i < srv->config_context->used; i++) {
+ specific_config *s = srv->config_storage[i];
+
+ if (!s) continue;
+
+ buffer_free(s->document_root);
+ buffer_free(s->server_name);
+ buffer_free(s->server_tag);
+ buffer_free(s->error_handler);
+ buffer_free(s->error_handler_404);
+ buffer_free(s->errorfile_prefix);
+ buffer_free(s->socket_perms);
+ array_free(s->mimetypes);
+ free(s);
+ }
+ free(srv->config_storage);
+ srv->config_storage = NULL;
+ }
+
+#define CLEAN(x) \
+ array_free(srv->x);
+
+ CLEAN(config_context);
+ CLEAN(config_touched);
+ CLEAN(status);
+ CLEAN(srvconf.upload_tempdirs);
+#undef CLEAN
+
+ joblist_free(srv, srv->joblist);
+ fdwaitqueue_free(srv, srv->fdwaitqueue);
+
+ if (srv->stat_cache) {
+ stat_cache_free(srv->stat_cache);
+ }
+
+ array_free(srv->srvconf.modules);
+ array_free(srv->split_vals);
+
+ li_rand_cleanup();
+ chunkqueue_chunk_pool_free();
+
+ free(srv);
+}
+
+static void remove_pid_file(server *srv) {
+ if (pid_fd <= -2) return;
+ if (!buffer_string_is_empty(srv->srvconf.pid_file) && 0 <= pid_fd) {
+ if (0 != ftruncate(pid_fd, 0)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbds",
+ "ftruncate failed for:",
+ srv->srvconf.pid_file,
+ errno,
+ strerror(errno));
+ }
+ }
+ if (0 <= pid_fd) {
+ close(pid_fd);
+ pid_fd = -1;
+ }
+ if (!buffer_string_is_empty(srv->srvconf.pid_file) &&
+ buffer_string_is_empty(srv->srvconf.changeroot)) {
+ if (0 != unlink(srv->srvconf.pid_file->ptr)) {
+ if (errno != EACCES && errno != EPERM) {
+ log_error_write(srv, __FILE__, __LINE__, "sbds",
+ "unlink failed for:",
+ srv->srvconf.pid_file,
+ errno,
+ strerror(errno));
+ }
+ }
+ }
+}
+
+
+static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
+ server_socket *srv_socket, *srv_socket_wild = NULL;
+ size_t i;
+ for (i = 0; i < srv->srv_sockets.used; ++i) {
+ srv_socket = srv->srv_sockets.ptr[i];
+ if (!sock_addr_is_port_eq(&srv_socket->addr,cnt_addr)) continue;
+ if (sock_addr_is_addr_eq(&srv_socket->addr,cnt_addr)) return srv_socket;
+
+ if (NULL != srv_socket_wild) continue;
+ if (sock_addr_is_addr_wildcard(&srv_socket->addr)) {
+ srv_socket_wild = srv_socket;
+ }
+ }
+
+ if (NULL != srv_socket_wild) {
+ return srv_socket_wild;
+ } else if (srv->srv_sockets.used) {
+ return srv->srv_sockets.ptr[0];
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "s", "no sockets configured");
+ return NULL;
+ }
+}
+
+
+static int server_oneshot_init(server *srv, int fd) {
+ /* Note: does not work with netcat due to requirement that fd be socket.
+ * STDOUT_FILENO was not saved earlier in startup, and that is to where
+ * netcat expects output to be sent. Since lighttpd expects connections
+ * to be sockets, con->fd is where output is sent; separate fds are not
+ * stored for input and output, but netcat has different fds for stdin
+ * and * stdout. To support netcat, would additionally need to avoid
+ * S_ISSOCK(), getsockname(), and getpeername() below, reconstructing
+ * addresses from environment variables:
+ * NCAT_LOCAL_ADDR NCAT_LOCAL_PORT
+ * NCAT_REMOTE_ADDR NCAT_REMOTE_PORT
+ * NCAT_PROTO
+ */
+ connection *con;
+ server_socket *srv_socket;
+ sock_addr cnt_addr;
+ socklen_t cnt_len;
+ struct stat st;
+
+ if (0 != fstat(fd, &st)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fstat:", strerror(errno));
+ return 0;
+ }
+
+ if (!S_ISSOCK(st.st_mode)) {
+ /* require that fd is a socket
+ * (modules might expect STDIN_FILENO and STDOUT_FILENO opened to /dev/null) */
+ log_error_write(srv, __FILE__, __LINE__, "s", "lighttpd -1 stdin is not a socket");
+ return 0;
+ }
+
+ cnt_len = sizeof(cnt_addr);
+ if (0 != getsockname(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "getsockname:", strerror(errno));
+ return 0;
+ }
+
+ srv_socket = server_oneshot_getsock(srv, &cnt_addr);
+ if (NULL == srv_socket) return 0;
+
+ cnt_len = sizeof(cnt_addr);
+ if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "getpeername:", strerror(errno));
+ return 0;
+ }
+
+ /*(must set flags; fd did not pass through fdevent accept() logic)*/
+ if (-1 == fdevent_fcntl_set_nb_cloexec(srv->ev, fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl:", strerror(errno));
+ return 0;
+ }
+
+ if (sock_addr_get_family(&cnt_addr) != AF_UNIX) {
+ network_accept_tcp_nagle_disable(fd);
+ }
+
+ con = connection_accepted(srv, srv_socket, &cnt_addr, fd);
+ if (NULL == con) return 0;
+
+ connection_state_machine(srv, con);
+ return 1;
+}
+
+
+static void show_version (void) {
+ char *b = PACKAGE_DESC TEXT_SSL \
+" - a light and fast webserver\n"
+#ifdef NONREPRODUCIBLE_BUILD
+"Build-Date: " __DATE__ " " __TIME__ "\n";
+#endif
+;
+ write_all(STDOUT_FILENO, b, strlen(b));
+}
+
+static void show_features (void) {
+ static const char features[] =
+ "\nFeatures:\n\n"
+#ifdef HAVE_IPV6
+ "\t+ IPv6 support\n"
+#else
+ "\t- IPv6 support\n"
+#endif
+#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
+ "\t+ zlib support\n"
+#else
+ "\t- zlib support\n"
+#endif
+#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
+ "\t+ bzip2 support\n"
+#else
+ "\t- bzip2 support\n"
+#endif
+#if defined(HAVE_CRYPT) || defined(HAVE_CRYPT_R) || defined(HAVE_LIBCRYPT)
+ "\t+ crypt support\n"
+#else
+ "\t- crypt support\n"
+#endif
+#ifdef USE_SSL
+ "\t+ SSL support\n"
+#else
+ "\t- SSL support\n"
+#endif
+#ifdef HAVE_LIBPCRE
+ "\t+ PCRE support\n"
+#else
+ "\t- PCRE support\n"
+#endif
+#ifdef HAVE_MYSQL
+ "\t+ MySQL support\n"
+#else
+ "\t- MySQL support\n"
+#endif
+#ifdef HAVE_PGSQL
+ "\t+ PgSQL support\n"
+#else
+ "\t- PgSQL support\n"
+#endif
+#ifdef HAVE_DBI
+ "\t+ DBI support\n"
+#else
+ "\t- DBI support\n"
+#endif
+#ifdef HAVE_KRB5
+ "\t+ Kerberos support\n"
+#else
+ "\t- Kerberos support\n"
+#endif
+#if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
+ "\t+ LDAP support\n"
+#else
+ "\t- LDAP support\n"
+#endif
+#ifdef HAVE_PAM
+ "\t+ PAM support\n"
+#else
+ "\t- PAM support\n"
+#endif
+#ifdef USE_MEMCACHED
+ "\t+ memcached support\n"
+#else
+ "\t- memcached support\n"
+#endif
+#ifdef HAVE_FAM_H
+ "\t+ FAM support\n"
+#else
+ "\t- FAM support\n"
+#endif
+#ifdef HAVE_LUA_H
+ "\t+ LUA support\n"
+#else
+ "\t- LUA support\n"
+#endif
+#ifdef HAVE_LIBXML_H
+ "\t+ xml support\n"
+#else
+ "\t- xml support\n"
+#endif
+#ifdef HAVE_SQLITE3_H
+ "\t+ SQLite support\n"
+#else
+ "\t- SQLite support\n"
+#endif
+#ifdef HAVE_GDBM_H
+ "\t+ GDBM support\n"
+#else
+ "\t- GDBM support\n"
+#endif
+ ;
+ show_version();
+ printf("%s%s%s\n", fdevent_show_event_handlers(), network_write_show_handlers(), features);
+}
+
+static void show_help (void) {
+ char *b = PACKAGE_DESC TEXT_SSL
+#ifdef NONREPRODUCIBLE_BUILD
+" ("__DATE__ " " __TIME__ ")"
+#endif
+" - a light and fast webserver\n" \
+"usage:\n" \
+" -f <name> filename of the config-file\n" \
+" -m <name> module directory (default: "LIBRARY_DIR")\n" \
+" -i <secs> graceful shutdown after <secs> of inactivity\n" \
+" -1 process single (one) request on stdin socket, then exit\n" \
+" -p print the parsed config-file in internal form, and exit\n" \
+" -t test config-file syntax, then exit\n" \
+" -tt test config-file syntax, load and init modules, then exit\n" \
+" -D don't go to background (default: go to background)\n" \
+" -v show version\n" \
+" -V show compile-time features\n" \
+" -h show this help\n" \
+"\n"
+;
+ write_all(STDOUT_FILENO, b, strlen(b));
+}
+
+/**
+ * open the errorlog
+ *
+ * we have 4 possibilities:
+ * - stderr (default)
+ * - syslog
+ * - logfile
+ * - pipe
+ *
+ */
+
+static int log_error_open(server *srv) {
+ int errfd;
+ #ifdef HAVE_SYSLOG_H
+ /* perhaps someone wants to use syslog() */
+ int facility = -1;
+ if (!buffer_string_is_empty(srv->srvconf.syslog_facility)) {
+ static const struct facility_name_st {
+ const char *name;
+ int val;
+ } facility_names[] = {
+ { "auth", LOG_AUTH }
+ #ifdef LOG_AUTHPRIV
+ ,{ "authpriv", LOG_AUTHPRIV }
+ #endif
+ #ifdef LOG_CRON
+ ,{ "cron", LOG_CRON }
+ #endif
+ ,{ "daemon", LOG_DAEMON }
+ #ifdef LOG_FTP
+ ,{ "ftp", LOG_FTP }
+ #endif
+ #ifdef LOG_KERN
+ ,{ "kern", LOG_KERN }
+ #endif
+ #ifdef LOG_LPR
+ ,{ "lpr", LOG_LPR }
+ #endif
+ #ifdef LOG_MAIL
+ ,{ "mail", LOG_MAIL }
+ #endif
+ #ifdef LOG_NEWS
+ ,{ "news", LOG_NEWS }
+ #endif
+ ,{ "security", LOG_AUTH } /* DEPRECATED */
+ #ifdef LOG_SYSLOG
+ ,{ "syslog", LOG_SYSLOG }
+ #endif
+ #ifdef LOG_USER
+ ,{ "user", LOG_USER }
+ #endif
+ #ifdef LOG_UUCP
+ ,{ "uucp", LOG_UUCP }
+ #endif
+ ,{ "local0", LOG_LOCAL0 }
+ ,{ "local1", LOG_LOCAL1 }
+ ,{ "local2", LOG_LOCAL2 }
+ ,{ "local3", LOG_LOCAL3 }
+ ,{ "local4", LOG_LOCAL4 }
+ ,{ "local5", LOG_LOCAL5 }
+ ,{ "local6", LOG_LOCAL6 }
+ ,{ "local7", LOG_LOCAL7 }
+ };
+ unsigned int i;
+ for (i = 0; i < sizeof(facility_names)/sizeof(facility_names[0]); ++i) {
+ const struct facility_name_st *f = facility_names+i;
+ if (0 == strcmp(srv->srvconf.syslog_facility->ptr, f->name)) {
+ facility = f->val;
+ break;
+ }
+ }
+ if (-1 == facility) {
+ log_error_write(srv, __FILE__, __LINE__, "SBS",
+ "unrecognized server.syslog-facility: \"",
+ srv->srvconf.syslog_facility,
+ "\"; defaulting to \"daemon\" facility");
+ }
+ }
+ openlog("lighttpd", LOG_CONS|LOG_PID, -1==facility ? LOG_DAEMON : facility);
+ #endif
+
+ srv->errorlog_mode = ERRORLOG_FD;
+ srv->errorlog_fd = STDERR_FILENO;
+
+ if (srv->srvconf.errorlog_use_syslog) {
+ srv->errorlog_mode = ERRORLOG_SYSLOG;
+ }
+ else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) {
+ const char *logfile = srv->srvconf.errorlog_file->ptr;
+ int fd = fdevent_open_logger(logfile);
+ if (-1 == fd) {
+ log_error_write(srv, __FILE__, __LINE__, "SSSS",
+ "opening errorlog '", logfile,
+ "' failed: ", strerror(errno));
+ return -1;
+ }
+ srv->errorlog_fd = fd;
+ srv->errorlog_mode = logfile[0] == '|' ? ERRORLOG_PIPE : ERRORLOG_FILE;
+ }
+
+ if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
+ /* We can only log to stderr in dont-daemonize mode;
+ * if we do daemonize and no errorlog file is specified,
+ * we log into /dev/null
+ */
+ srv->errorlog_fd = -1;
+ }
+
+ if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) {
+ const char *logfile = srv->srvconf.breakagelog_file->ptr;
+
+ if (srv->errorlog_mode == ERRORLOG_FD) {
+ srv->errorlog_fd = dup(STDERR_FILENO);
+ fdevent_setfd_cloexec(srv->errorlog_fd);
+ }
+
+ if (-1 == (errfd = fdevent_open_logger(logfile))) {
+ log_error_write(srv, __FILE__, __LINE__, "SSSS",
+ "opening errorlog '", logfile,
+ "' failed: ", strerror(errno));
+ return -1;
+ }
+
+ if (*logfile == '|') fdevent_breakagelog_logger_pipe(errfd);
+ }
+ else if (!srv->srvconf.dont_daemonize) {
+ /* move STDERR_FILENO to /dev/null */
+ if (-1 == (errfd = fdevent_open_devnull())) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "opening /dev/null failed:", strerror(errno));
+ return -1;
+ }
+ }
+ else {
+ /*(leave STDERR_FILENO as-is)*/
+ errfd = -1;
+ }
+
+ if (0 != fdevent_set_stdin_stdout_stderr(-1, -1, errfd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "setting stderr failed:", strerror(errno));
+ #ifdef FD_CLOEXEC
+ if (-1 != errfd) close(errfd);
+ #endif
+ return -1;
+ }
+ #ifdef FD_CLOEXEC
+ if (-1 != errfd) close(errfd);
+ #endif
+
+ return 0;
+}
+
+/**
+ * cycle the errorlog
+ *
+ */
+
+static int log_error_cycle(server *srv) {
+ /* cycle only if the error log is a file */
+
+ if (srv->errorlog_mode == ERRORLOG_FILE) {
+ const char *logfile = srv->srvconf.errorlog_file->ptr;
+ if (-1 == fdevent_cycle_logger(logfile, &srv->errorlog_fd)) {
+ /* write to old log */
+ log_error_write(srv, __FILE__, __LINE__, "SSSS",
+ "cycling errorlog '", logfile,
+ "' failed: ", strerror(errno));
+ }
+ }
+
+ return 0;
+}
+
+static int log_error_close(server *srv) {
+ switch(srv->errorlog_mode) {
+ case ERRORLOG_PIPE:
+ case ERRORLOG_FILE:
+ case ERRORLOG_FD:
+ if (-1 != srv->errorlog_fd) {
+ /* don't close STDERR */
+ /* fdevent_close_logger_pipes() closes ERRORLOG_PIPE */
+ if (STDERR_FILENO != srv->errorlog_fd
+ && srv->errorlog_mode != ERRORLOG_PIPE) {
+ close(srv->errorlog_fd);
+ }
+ srv->errorlog_fd = -1;
+ }
+ break;
+ case ERRORLOG_SYSLOG:
+ #ifdef HAVE_SYSLOG_H
+ closelog();
+ #endif
+ break;
+ }
+
+ return 0;
+}
+
+static void server_sockets_save (server *srv) { /* graceful_restart */
+ memcpy(&graceful_sockets, &srv->srv_sockets, sizeof(server_socket_array));
+ memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
+ memcpy(&inherited_sockets, &srv->srv_sockets_inherited, sizeof(server_socket_array));
+ memset(&srv->srv_sockets_inherited, 0, sizeof(server_socket_array));
+}
+
+static void server_sockets_restore (server *srv) { /* graceful_restart */
+ memcpy(&srv->srv_sockets, &graceful_sockets, sizeof(server_socket_array));
+ memset(&graceful_sockets, 0, sizeof(server_socket_array));
+ memcpy(&srv->srv_sockets_inherited, &inherited_sockets, sizeof(server_socket_array));
+ memset(&inherited_sockets, 0, sizeof(server_socket_array));
+}
+
+static int server_sockets_set_nb_cloexec (server *srv) {
+ if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
+ for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+ if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv->ev, srv_socket->fd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "fcntl failed:", strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void server_sockets_set_event (server *srv, int event) {
+ for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+ fdevent_event_set(srv->ev,&(srv_socket->fde_ndx),srv_socket->fd,event);
+ }
+}
+
+static void server_sockets_unregister (server *srv) {
+ for (size_t i = 0; i < srv->srv_sockets.used; ++i)
+ network_unregister_sock(srv, srv->srv_sockets.ptr[i]);
+}
+
+static void server_sockets_close (server *srv) {
+ /* closing socket right away will make it possible for the next lighttpd
+ * to take over (old-style graceful restart), but only if backends
+ * (e.g. fastcgi, scgi, etc) are independent from lighttpd, rather
+ * than started by lighttpd via "bin-path")
+ */
+ for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+ if (-1 == srv_socket->fd) continue;
+ network_unregister_sock(srv, srv_socket);
+ close(srv_socket->fd);
+ srv_socket->fd = -1;
+ /* network_close() will cleanup after us */
+ }
+}
+
+static void server_graceful_shutdown_maint (server *srv) {
+ connections *conns = srv->conns;
+ for (size_t ndx = 0; ndx < conns->used; ++ndx) {
+ connection * const con = conns->ptr[ndx];
+ int changed = 0;
+
+ if (con->state == CON_STATE_CLOSE) {
+ /* reduce remaining linger timeout to be
+ * (from zero) *up to* one more second, but no more */
+ if (HTTP_LINGER_TIMEOUT > 1)
+ con->close_timeout_ts -= (HTTP_LINGER_TIMEOUT - 1);
+ if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT)
+ changed = 1;
+ }
+ else if (con->state == CON_STATE_READ && con->request_count > 1
+ && chunkqueue_is_empty(con->read_queue)) {
+ /* close connections in keep-alive waiting for next request */
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ changed = 1;
+ }
+
+ con->keep_alive = 0; /* disable keep-alive */
+
+ con->conf.kbytes_per_second = 0; /* disable rate limit */
+ con->conf.global_kbytes_per_second = 0; /* disable rate limit */
+ if (con->traffic_limit_reached) {
+ con->traffic_limit_reached = 0;
+ changed = 1;
+ }
+
+ if (changed) {
+ connection_state_machine(srv, con);
+ }
+ }
+}
+
+static void server_graceful_state (server *srv) {
+
+ if (!srv_shutdown) server_graceful_shutdown_maint(srv);
+
+ if (!oneshot_fd) {
+ if (0==srv->srv_sockets.used || -1 == srv->srv_sockets.ptr[0]->fde_ndx)
+ return;
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "[note] graceful shutdown started");
+
+ /* no graceful restart if chroot()ed, if oneshot mode, or if idle timeout */
+ if (!buffer_string_is_empty(srv->srvconf.changeroot)
+ || oneshot_fd || 2 == graceful_shutdown)
+ graceful_restart = 0;
+
+ if (graceful_restart) {
+ server_sockets_unregister(srv);
+ if (pid_fd > 0) pid_fd = -pid_fd; /*(flag to skip removing pid file)*/
+ }
+ else {
+ server_sockets_close(srv);
+ remove_pid_file(srv);
+ buffer_clear(srv->srvconf.pid_file); /*(prevent more removal attempts)*/
+ }
+}
+
+static int server_main (server * const srv, int argc, char **argv) {
+ int print_config = 0;
+ int test_config = 0;
+ int i_am_root = 0;
+ int o;
+#ifdef HAVE_FORK
+ int num_childs = 0;
+#endif
+ size_t i;
+ time_t idle_limit = 0, last_active_ts = time(NULL);
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+#endif
+
+#ifdef HAVE_FORK
+ int parent_pipe_fd = -1;
+#endif
+ int stdin_fd = -1;
+
+#ifdef HAVE_GETUID
+ i_am_root = (0 == getuid());
+#endif
+
+ /* initialize globals (including file-scoped static globals) */
+ oneshot_fd = 0;
+ srv_shutdown = 0;
+ graceful_shutdown = 0;
+ handle_sig_alarm = 1;
+ handle_sig_hup = 0;
+ chunkqueue_set_tempdirs_default_reset();
+ http_auth_dumbdata_reset();
+ http_vhostdb_dumbdata_reset();
+ /*graceful_restart = 0;*//*(reset below to avoid further daemonizing)*/
+ /*(intentionally preserved)*/
+ /*memset(graceful_sockets, 0, sizeof(graceful_sockets));*/
+ /*memset(inherited_sockets, 0, sizeof(inherited_sockets));*/
+ /*pid_fd = -1;*/
+
+ srv->srvconf.port = 0;
+ srv->srvconf.dont_daemonize = 0;
+ srv->srvconf.preflight_check = 0;
+
+ while(-1 != (o = getopt(argc, argv, "f:m:i:hvVD1pt"))) {
+ switch(o) {
+ case 'f':
+ if (srv->config_storage) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Can only read one config file. Use the include command to use multiple config files.");
+ return -1;
+ }
+ if (config_read(srv, optarg)) {
+ return -1;
+ }
+ break;
+ case 'm':
+ buffer_copy_string(srv->srvconf.modules_dir, optarg);
+ break;
+ case 'i': {
+ char *endptr;
+ long timeout = strtol(optarg, &endptr, 0);
+ if (!*optarg || *endptr || timeout < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "Invalid idle timeout value:", optarg);
+ return -1;
+ }
+ idle_limit = (time_t)timeout;
+ break;
+ }
+ case 'p': print_config = 1; break;
+ case 't': ++test_config; break;
+ case '1': if (0 == oneshot_fd) oneshot_fd = dup(STDIN_FILENO);
+ break;
+ case 'D': srv->srvconf.dont_daemonize = 1; break;
+ case 'v': show_version(); return 0;
+ case 'V': show_features(); return 0;
+ case 'h': show_help(); return 0;
+ default:
+ show_help();
+ return -1;
+ }
+ }
+
+ #ifdef __CYGWIN__
+ if (!srv->config_storage && NULL != getenv("NSSM_SERVICE_NAME")) {
+ char *dir = getenv("NSSM_SERVICE_DIR");
+ if (NULL != dir && 0 != chdir(dir)) {
+ log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", dir, strerror(errno));
+ return -1;
+ }
+ srv->srvconf.dont_daemonize = 1;
+ buffer_copy_string_len(srv->srvconf.modules_dir, CONST_STR_LEN("modules"));
+ if (config_read(srv, "conf/lighttpd.conf")) return -1;
+ }
+ #endif
+
+ if (!srv->config_storage) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "No configuration available. Try using -f option.");
+ return -1;
+ }
+
+ if (print_config) {
+ data_unset *dc = srv->config_context->data[0];
+ if (dc) {
+ dc->fn->print(dc, 0);
+ fprintf(stdout, "\n");
+ } else {
+ /* shouldn't happend */
+ fprintf(stderr, "global config not found\n");
+ }
+ }
+
+ if (test_config) {
+ buffer_clear(srv->srvconf.pid_file);
+ if (1 == test_config) {
+ printf("Syntax OK\n");
+ } else { /*(test_config > 1)*/
+ test_config = 0;
+ srv->srvconf.preflight_check = 1;
+ srv->srvconf.dont_daemonize = 1;
+ }
+ }
+
+ if (test_config || print_config) {
+ return 0;
+ }
+
+ if (oneshot_fd) {
+ if (oneshot_fd <= STDERR_FILENO) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Invalid fds at startup with lighttpd -1");
+ return -1;
+ }
+ graceful_shutdown = 1;
+ srv->sockets_disabled = 1;
+ srv->srvconf.dont_daemonize = 1;
+ buffer_clear(srv->srvconf.pid_file);
+ if (srv->srvconf.max_worker) {
+ srv->srvconf.max_worker = 0;
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "server one-shot command line option disables server.max-worker config file option.");
+ }
+ }
+
+ if (buffer_is_equal_string(srv->srvconf.bindhost, CONST_STR_LEN("/dev/stdin"))) {
+ stdin_fd = dup(STDIN_FILENO);
+ if (stdin_fd <= STDERR_FILENO) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Invalid fds at startup");
+ return -1;
+ }
+ }
+
+ /* close stdin and stdout, as they are not needed */
+ {
+ struct stat st;
+ int devnull;
+ int errfd;
+ do {
+ /* coverity[overwrite_var : FALSE] */
+ devnull = fdevent_open_devnull();
+ #ifdef __COVERITY__
+ __coverity_escape__(devnull);
+ #endif
+ } while (-1 != devnull && devnull <= STDERR_FILENO);
+ if (-1 == devnull) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "opening /dev/null failed:", strerror(errno));
+ return -1;
+ }
+ errfd = (0 == fstat(STDERR_FILENO, &st)) ? -1 : devnull;
+ if (0 != fdevent_set_stdin_stdout_stderr(devnull, devnull, errfd)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "setting default fds failed:", strerror(errno));
+ #ifdef FD_CLOEXEC
+ if (-1 != errfd) close(errfd);
+ if (devnull != errfd) close(devnull);
+ #endif
+ return -1;
+ }
+ #ifdef FD_CLOEXEC
+ if (-1 != errfd) close(errfd);
+ if (devnull != errfd) close(devnull);
+ #endif
+ }
+
+ if (0 != config_set_defaults(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "setting default values failed");
+ return -1;
+ }
+
+ /* check document-root */
+ if (buffer_string_is_empty(srv->config_storage[0]->document_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "document-root is not set\n");
+ return -1;
+ }
+
+ if (plugins_load(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "loading plugins finally failed");
+ return -1;
+ }
+
+ if (HANDLER_GO_ON != plugins_call_init(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
+ return -1;
+ }
+
+ /* mod_indexfile should be listed in server.modules prior to dynamic handlers */
+ i = 0;
+ for (buffer *pname = NULL; i < srv->plugins.used; ++i) {
+ plugin *p = ((plugin **)srv->plugins.ptr)[i];
+ if (buffer_is_equal_string(p->name, CONST_STR_LEN("indexfile"))) {
+ if (pname) {
+ log_error_write(srv, __FILE__, __LINE__, "SB",
+ "Warning: mod_indexfile should be listed in server.modules prior to mod_", pname);
+ }
+ break;
+ }
+ if (p->handle_subrequest_start && p->handle_subrequest) {
+ if (!pname) pname = p->name;
+ }
+ }
+
+ /* open pid file BEFORE chroot */
+ if (-2 == pid_fd) pid_fd = -1; /*(initial startup state)*/
+ if (-1 == pid_fd && !buffer_string_is_empty(srv->srvconf.pid_file)) {
+ if (-1 == (pid_fd = fdevent_open_cloexec(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
+ struct stat st;
+ if (errno != EEXIST) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
+ return -1;
+ }
+
+ if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
+ return -1;
+ }
+
+ if (-1 == (pid_fd = fdevent_open_cloexec(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
+ return -1;
+ }
+ }
+ }
+
+ {
+#ifdef HAVE_GETRLIMIT
+ struct rlimit rlim;
+ int use_rlimit = 1;
+#ifdef HAVE_VALGRIND_VALGRIND_H
+ if (RUNNING_ON_VALGRIND) use_rlimit = 0;
+#endif
+
+ if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "ss", "couldn't get 'max filedescriptors'",
+ strerror(errno));
+ return -1;
+ }
+
+ /**
+ * if we are not root can can't increase the fd-limit above rlim_max, but we can reduce it
+ */
+ if (use_rlimit && srv->srvconf.max_fds
+ && (i_am_root || srv->srvconf.max_fds <= rlim.rlim_max)) {
+ /* set rlimits */
+
+ rlim.rlim_cur = srv->srvconf.max_fds;
+ if (i_am_root) rlim.rlim_max = srv->srvconf.max_fds;
+
+ if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "ss", "couldn't set 'max filedescriptors'",
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ srv->max_fds = rlim.rlim_cur;
+ /*(default upper limit of 4k if server.max-fds not specified)*/
+ if (i_am_root && 0 == srv->srvconf.max_fds && rlim.rlim_cur > 4096)
+ srv->max_fds = 4096;
+
+ /* set core file rlimit, if enable_cores is set */
+ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
+#endif
+ }
+
+ /* we need root-perms for port < 1024 */
+ if (0 != network_init(srv, stdin_fd)) {
+ return -1;
+ }
+
+ if (i_am_root) {
+#ifdef HAVE_PWD_H
+ /* set user and group */
+ struct group *grp = NULL;
+ struct passwd *pwd = NULL;
+
+ if (!buffer_string_is_empty(srv->srvconf.groupname)) {
+ if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "can't find groupname", srv->srvconf.groupname);
+ return -1;
+ }
+ }
+
+ if (!buffer_string_is_empty(srv->srvconf.username)) {
+ if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "can't find username", srv->srvconf.username);
+ return -1;
+ }
+
+ if (pwd->pw_uid == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "I will not set uid to 0\n");
+ return -1;
+ }
+
+ if (NULL == grp && NULL == (grp = getgrgid(pwd->pw_gid))) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "can't find group id", pwd->pw_gid);
+ return -1;
+ }
+ }
+
+ if (NULL != grp) {
+ if (grp->gr_gid == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "I will not set gid to 0\n");
+ return -1;
+ }
+ }
+
+ /*
+ * Change group before chroot, when we have access
+ * to /etc/group
+ * */
+ if (NULL != grp) {
+ if (-1 == setgid(grp->gr_gid)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setgid failed: ", strerror(errno));
+ return -1;
+ }
+ if (-1 == setgroups(0, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setgroups failed: ", strerror(errno));
+ return -1;
+ }
+ if (!buffer_string_is_empty(srv->srvconf.username)) {
+ initgroups(srv->srvconf.username->ptr, grp->gr_gid);
+ }
+ }
+#endif
+#ifdef HAVE_CHROOT
+ if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
+ tzset();
+
+ if (-1 == chroot(srv->srvconf.changeroot->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno));
+ return -1;
+ }
+ if (-1 == chdir("/")) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno));
+ return -1;
+ }
+ }
+#endif
+#ifdef HAVE_PWD_H
+ /* drop root privs */
+ if (NULL != pwd) {
+ if (-1 == setuid(pwd->pw_uid)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "setuid failed: ", strerror(errno));
+ return -1;
+ }
+ }
+#endif
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
+ /**
+ * on IRIX 6.5.30 they have prctl() but no DUMPABLE
+ */
+ if (srv->srvconf.enable_cores) {
+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ }
+#endif
+ }
+
+ /* set max-conns */
+ if (srv->srvconf.max_conns > srv->max_fds/2) {
+ /* we can't have more connections than max-fds/2 */
+ log_error_write(srv, __FILE__, __LINE__, "sdd", "can't have more connections than fds/2: ", srv->srvconf.max_conns, srv->max_fds);
+ srv->max_conns = srv->max_fds/2;
+ } else if (srv->srvconf.max_conns) {
+ /* otherwise respect the wishes of the user */
+ srv->max_conns = srv->srvconf.max_conns;
+ } else {
+ /* or use the default: we really don't want to hit max-fds */
+ srv->max_conns = srv->max_fds/3;
+ }
+
+#ifdef HAVE_FORK
+ /* network is up, let's daemonize ourself */
+ if (0 == srv->srvconf.dont_daemonize && 0 == graceful_restart) {
+ parent_pipe_fd = daemonize();
+ }
+#endif
+ graceful_restart = 0;/*(reset here after avoiding further daemonizing)*/
+ if (0 == oneshot_fd) graceful_shutdown = 0;
+
+
+#ifdef HAVE_SIGACTION
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+# if defined(SA_SIGINFO)
+ last_sighup_info.si_uid = 0,
+ last_sighup_info.si_pid = 0;
+ last_sigterm_info.si_uid = 0,
+ last_sigterm_info.si_pid = 0;
+ act.sa_sigaction = sigaction_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+# else
+ act.sa_handler = signal_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+# endif
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGALRM, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+
+ /* it should be safe to restart syscalls after SIGCHLD */
+ act.sa_flags |= SA_RESTART | SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &act, NULL);
+
+#elif defined(HAVE_SIGNAL)
+ /* ignore the SIGPIPE from sendfile() */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGALRM, signal_handler);
+ signal(SIGTERM, signal_handler);
+ signal(SIGHUP, signal_handler);
+ signal(SIGCHLD, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGUSR1, signal_handler);
+#endif
+
+
+ srv->gid = getgid();
+ srv->uid = getuid();
+ srv->pid = getpid();
+
+ /* write pid file */
+ if (pid_fd > 2) {
+ buffer_copy_int(srv->tmp_buf, srv->pid);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
+ if (-1 == write_all(pid_fd, CONST_BUF_LEN(srv->tmp_buf))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't write pid file:", strerror(errno));
+ close(pid_fd);
+ pid_fd = -1;
+ return -1;
+ }
+ } else if (pid_fd < -2) {
+ pid_fd = -pid_fd;
+ }
+
+ /* Close stderr ASAP in the child process to make sure that nothing
+ * is being written to that fd which may not be valid anymore. */
+ if (!srv->srvconf.preflight_check) {
+ if (-1 == log_error_open(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down.");
+ return -1;
+ }
+ log_error_write(srv, __FILE__, __LINE__, "s", "server started (" PACKAGE_DESC ")");
+ }
+
+ if (buffer_is_empty(srv->config_storage[0]->server_tag)) {
+ buffer_copy_string_len(srv->config_storage[0]->server_tag, CONST_STR_LEN(PACKAGE_DESC));
+ }
+
+ if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
+ return -1;
+ }
+
+ /* settings might be enabled during module config set defaults */
+ srv->config_storage[0]->high_precision_timestamps = srv->srvconf.high_precision_timestamps;
+
+ /* dump unused config-keys */
+ for (i = 0; i < srv->config_context->used; i++) {
+ array *config = ((data_config *)srv->config_context->data[i])->value;
+ size_t j;
+
+ for (j = 0; config && j < config->used; j++) {
+ data_unset *du = config->data[j];
+
+ /* all var.* is known as user defined variable */
+ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
+ continue;
+ }
+
+ if (NULL == array_get_element_klen(srv->config_touched, CONST_BUF_LEN(du->key))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "WARNING: unknown config-key:",
+ du->key,
+ "(ignored)");
+ }
+ }
+ }
+
+ if (srv->config_unsupported) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Configuration contains unsupported keys. Going down.");
+ }
+
+ if (srv->config_deprecated) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Configuration contains deprecated keys. Going down.");
+ }
+
+ if (srv->config_unsupported || srv->config_deprecated) {
+ return -1;
+ }
+
+ if (srv->srvconf.preflight_check) {
+ /*printf("Preflight OK");*//*(stdout reopened to /dev/null)*/
+ return 0;
+ }
+
+
+#ifdef HAVE_FORK
+ /**
+ * notify daemonize-grandparent of successful startup
+ * do this before any further forking is done (workers)
+ */
+ if (0 == srv->srvconf.dont_daemonize && -1 != parent_pipe_fd) {
+ if (0 > write(parent_pipe_fd, "", 1)) return -1;
+ close(parent_pipe_fd);
+ }
+
+ if (idle_limit && srv->srvconf.max_worker) {
+ srv->srvconf.max_worker = 0;
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "server idle time limit command line option disables server.max-worker config file option.");
+ }
+
+ /* start watcher and workers */
+ num_childs = srv->srvconf.max_worker;
+ if (num_childs > 0) {
+ pid_t pids[num_childs];
+ pid_t pid;
+ const int npids = num_childs;
+ int child = 0;
+ unsigned int timer = 0;
+ for (int n = 0; n < npids; ++n) pids[n] = -1;
+ while (!child && !srv_shutdown && !graceful_shutdown) {
+ if (num_childs > 0) {
+ switch ((pid = fork())) {
+ case -1:
+ return -1;
+ case 0:
+ child = 1;
+ alarm(0);
+ break;
+ default:
+ num_childs--;
+ for (int n = 0; n < npids; ++n) {
+ if (-1 == pids[n]) {
+ pids[n] = pid;
+ break;
+ }
+ }
+ break;
+ }
+ } else {
+ int status;
+
+ if (-1 != (pid = wait(&status))) {
+ srv->cur_ts = time(NULL);
+ if (plugins_call_handle_waitpid(srv, pid, status) != HANDLER_GO_ON) {
+ if (!timer) alarm((timer = 5));
+ continue;
+ }
+ switch (fdevent_reaped_logger_pipe(pid)) {
+ default: break;
+ case -1: if (!timer) alarm((timer = 5));
+ /* fall through */
+ case 1: continue;
+ }
+ /**
+ * check if one of our workers went away
+ */
+ for (int n = 0; n < npids; ++n) {
+ if (pid == pids[n]) {
+ pids[n] = -1;
+ num_childs++;
+ break;
+ }
+ }
+ } else {
+ switch (errno) {
+ case EINTR:
+ srv->cur_ts = time(NULL);
+ /**
+ * if we receive a SIGHUP we have to close our logs ourself as we don't
+ * have the mainloop who can help us here
+ */
+ if (handle_sig_hup) {
+ handle_sig_hup = 0;
+
+ log_error_cycle(srv);
+
+ /* forward SIGHUP to workers */
+ for (int n = 0; n < npids; ++n) {
+ if (pids[n] > 0) kill(pids[n], SIGHUP);
+ }
+ }
+ if (handle_sig_alarm) {
+ handle_sig_alarm = 0;
+ timer = 0;
+ plugins_call_handle_trigger(srv);
+ fdevent_restart_logger_pipes(srv->cur_ts);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * for the parent this is the exit-point
+ */
+ if (!child) {
+ /**
+ * kill all children too
+ */
+ if (graceful_shutdown || graceful_restart) {
+ /* flag to ignore one SIGINT if graceful_restart */
+ if (graceful_restart) graceful_restart = 2;
+ kill(0, SIGINT);
+ server_graceful_state(srv);
+ } else if (srv_shutdown) {
+ kill(0, SIGTERM);
+ }
+
+ return 0;
+ }
+
+ /* ignore SIGUSR1 in workers; only parent directs graceful restart */
+ #ifdef HAVE_SIGACTION
+ {
+ struct sigaction actignore;
+ memset(&actignore, 0, sizeof(actignore));
+ actignore.sa_handler = SIG_IGN;
+ sigaction(SIGUSR1, &actignore, NULL);
+ }
+ #elif defined(HAVE_SIGNAL)
+ signal(SIGUSR1, SIG_IGN);
+ #endif
+
+ /**
+ * make sure workers do not muck with pid-file
+ */
+ if (0 <= pid_fd) {
+ close(pid_fd);
+ pid_fd = -1;
+ }
+ buffer_clear(srv->srvconf.pid_file);
+
+ fdevent_clr_logger_pipe_pids();
+ srv->pid = getpid();
+ li_rand_reseed();
+ }
+#endif
+
+ if (NULL == (srv->ev = fdevent_init(srv))) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "s", "fdevent_init failed");
+ return -1;
+ }
+
+ /* libev backend overwrites our SIGCHLD handler and calls waitpid on SIGCHLD; we want our own SIGCHLD handling. */
+#ifdef HAVE_SIGACTION
+ sigaction(SIGCHLD, &act, NULL);
+#elif defined(HAVE_SIGNAL)
+ signal(SIGCHLD, signal_handler);
+#endif
+
+ /*
+ * kqueue() is called here, select resets its internals,
+ * all server sockets get their handlers
+ *
+ * */
+ if (0 != network_register_fdevents(srv)) {
+ return -1;
+ }
+
+ /* might fail if user is using fam (not gamin) and famd isn't running */
+ if (NULL == (srv->stat_cache = stat_cache_init(srv))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "stat-cache could not be setup, dieing.");
+ return -1;
+ }
+
+#ifdef USE_ALARM
+ {
+ /* setup periodic timer (1 second) */
+ struct itimerval interval;
+ interval.it_interval.tv_sec = 1;
+ interval.it_interval.tv_usec = 0;
+ interval.it_value.tv_sec = 1;
+ interval.it_value.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &interval, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
+ return -1;
+ }
+ }
+#endif
+
+
+ /* get the current number of FDs */
+ {
+ int fd = fdevent_open_devnull();
+ if (fd >= 0) {
+ srv->cur_fds = fd;
+ close(fd);
+ }
+ }
+
+ if (0 != server_sockets_set_nb_cloexec(srv)) {
+ return -1;
+ }
+
+ if (oneshot_fd && server_oneshot_init(srv, oneshot_fd)) {
+ oneshot_fd = -1;
+ }
+
+ /* main-loop */
+ while (!srv_shutdown) {
+ int n;
+ size_t ndx;
+ time_t min_ts;
+
+ if (handle_sig_hup) {
+ handler_t r;
+
+ /* reset notification */
+ handle_sig_hup = 0;
+
+
+ /* cycle logfiles */
+
+ switch(r = plugins_call_handle_sighup(srv)) {
+ case HANDLER_GO_ON:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
+ break;
+ }
+
+ if (-1 == log_error_cycle(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
+
+ return -1;
+ } else {
+#ifdef HAVE_SIGACTION
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "logfiles cycled UID =",
+ last_sighup_info.si_uid,
+ "PID =",
+ last_sighup_info.si_pid);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "logfiles cycled");
+#endif
+ }
+ }
+
+ if (handle_sig_alarm) {
+ /* a new second */
+
+#ifdef USE_ALARM
+ /* reset notification */
+ handle_sig_alarm = 0;
+#endif
+
+ /* get current time */
+ min_ts = time(NULL);
+
+ if (min_ts != srv->cur_ts) {
+#ifdef DEBUG_CONNECTION_STATES
+ int cs = 0;
+#endif
+ connections *conns = srv->conns;
+ handler_t r;
+
+ switch(r = plugins_call_handle_trigger(srv)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_ERROR:
+ log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "d", r);
+ break;
+ }
+
+ srv->cur_ts = min_ts;
+
+ /* check idle time limit, if enabled */
+ if (idle_limit && idle_limit < min_ts - last_active_ts && !graceful_shutdown) {
+ log_error_write(srv, __FILE__, __LINE__, "sDs", "[note] idle timeout", (int)idle_limit,
+ "s exceeded, initiating graceful shutdown");
+ graceful_shutdown = 2; /* value 2 indicates idle timeout */
+ if (graceful_restart) {
+ graceful_restart = 0;
+ if (pid_fd < -2) pid_fd = -pid_fd;
+ server_sockets_close(srv);
+ }
+ }
+
+ #ifdef HAVE_GETLOADAVG
+ /* refresh loadavg data every 30 seconds */
+ if (srv->srvconf.loadts + 30 < min_ts) {
+ if (-1 != getloadavg(srv->srvconf.loadavg, 3)) {
+ srv->srvconf.loadts = min_ts;
+ }
+ }
+ #endif
+
+ /* free excess chunkqueue buffers every 64 seconds */
+ if (0 == (min_ts & 0x3f)) chunkqueue_chunk_pool_clear();
+ /* cleanup stat-cache */
+ stat_cache_trigger_cleanup(srv);
+ /* reset global/aggregate rate limit counters */
+ for (i = 0; i < srv->config_context->used; ++i) {
+ srv->config_storage[i]->global_bytes_per_second_cnt = 0;
+ }
+ /* if graceful_shutdown, accelerate cleanup of recently completed request/responses */
+ if (graceful_shutdown && !srv_shutdown) server_graceful_shutdown_maint(srv);
+ /**
+ * check all connections for timeouts
+ *
+ */
+ for (ndx = 0; ndx < conns->used; ndx++) {
+ connection * const con = conns->ptr[ndx];
+ const int waitevents = fdevent_event_get_interest(srv->ev, con->fd);
+ int changed = 0;
+ int t_diff;
+
+ if (con->state == CON_STATE_CLOSE) {
+ if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) {
+ changed = 1;
+ }
+ } else if (waitevents & FDEVENT_IN) {
+ if (con->request_count == 1 || con->state != CON_STATE_READ) { /* e.g. CON_STATE_READ_POST || CON_STATE_WRITE */
+ if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
+ /* time - out */
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "connection closed - read timeout:", con->fd);
+ }
+
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ changed = 1;
+ }
+ } else {
+ if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) {
+ /* time - out */
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "connection closed - keep-alive timeout:", con->fd);
+ }
+
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ changed = 1;
+ }
+ }
+ }
+
+ /* max_write_idle timeout currently functions as backend timeout,
+ * too, after response has been started.
+ * future: have separate backend timeout, and then change this
+ * to check for write interest before checking for timeout */
+ /*if (waitevents & FDEVENT_OUT)*/
+ if ((con->state == CON_STATE_WRITE) &&
+ (con->write_request_ts != 0)) {
+#if 0
+ if (srv->cur_ts - con->write_request_ts > 60) {
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
+ "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
+ }
+#endif
+
+ if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
+ /* time - out */
+ if (con->conf.log_timeouts) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsosds",
+ "NOTE: a request from",
+ con->dst_addr_buf,
+ "for",
+ con->request.uri,
+ "timed out after writing",
+ con->bytes_written,
+ "bytes. We waited",
+ (int)con->conf.max_write_idle,
+ "seconds. If this a problem increase server.max-write-idle");
+ }
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ changed = 1;
+ }
+ }
+
+ /* we don't like div by zero */
+ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
+
+ if (con->traffic_limit_reached &&
+ (con->conf.kbytes_per_second == 0 ||
+ ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
+ /* enable connection again */
+ con->traffic_limit_reached = 0;
+
+ changed = 1;
+ }
+
+ con->bytes_written_cur_second = 0;
+
+ if (changed) {
+ connection_state_machine(srv, con);
+ }
+
+#if DEBUG_CONNECTION_STATES
+ if (cs == 0) {
+ fprintf(stderr, "connection-state: ");
+ cs = 1;
+ }
+
+ fprintf(stderr, "c[%d,%d]: %s ",
+ con->fd,
+ con->fcgi.fd,
+ connection_get_state(con->state));
+#endif
+ }
+
+#ifdef DEBUG_CONNECTION_STATES
+ if (cs == 1) fprintf(stderr, "\n");
+#endif
+ }
+ }
+
+ if (handle_sig_child) {
+ pid_t pid;
+ handle_sig_child = 0;
+ do {
+ int status;
+ pid = waitpid(-1, &status, WNOHANG);
+ if (pid > 0) {
+ if (plugins_call_handle_waitpid(srv, pid, status) != HANDLER_GO_ON) {
+ continue;
+ }
+ if (0 == srv->srvconf.max_worker) {
+ /* check piped-loggers and restart, even if shutting down */
+ if (fdevent_waitpid_logger_pipe_pid(pid, srv->cur_ts)) {
+ continue;
+ }
+ }
+ }
+ } while (pid > 0 || (-1 == pid && errno == EINTR));
+ }
+
+ if (graceful_shutdown) {
+ server_graceful_state(srv);
+ srv->sockets_disabled = 1;
+ } else if (srv->sockets_disabled) {
+ /* our server sockets are disabled, why ? */
+
+ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 8 / 10) && /* we have enough unused fds */
+ (srv->conns->used <= srv->max_conns * 9 / 10)) {
+ server_sockets_set_event(srv, FDEVENT_IN);
+ log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
+
+ srv->sockets_disabled = 0;
+ }
+ } else {
+ if ((srv->cur_fds + srv->want_fds > srv->max_fds * 9 / 10) || /* out of fds */
+ (srv->conns->used >= srv->max_conns)) { /* out of connections */
+ /* disable server-fds */
+ server_sockets_set_event(srv, 0);
+
+ if (srv->conns->used >= srv->max_conns) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
+ }
+
+ srv->sockets_disabled = 1;
+ }
+ }
+
+ if (graceful_shutdown && srv->conns->used == 0) {
+ /* we are in graceful shutdown phase and all connections are closed
+ * we are ready to terminate without harming anyone */
+ srv_shutdown = 1;
+ break;
+ }
+
+ /* we still have some fds to share */
+ if (srv->want_fds) {
+ /* check the fdwaitqueue for waiting fds */
+ int free_fds = srv->max_fds - srv->cur_fds - 16;
+ connection *con;
+
+ for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
+ connection_state_machine(srv, con);
+
+ srv->want_fds--;
+ }
+ }
+
+ if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
+ /* n is the number of events */
+ int fd;
+ int revents;
+ int fd_ndx;
+ last_active_ts = srv->cur_ts;
+ fd_ndx = -1;
+ do {
+ fdevent_handler handler;
+ void *context;
+
+ fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx);
+ if (-1 == fd_ndx) break; /* not all fdevent handlers know how many fds got an event */
+
+ revents = fdevent_event_get_revent (srv->ev, fd_ndx);
+ fd = fdevent_event_get_fd (srv->ev, fd_ndx);
+ handler = fdevent_get_handler(srv->ev, fd);
+ context = fdevent_get_context(srv->ev, fd);
+ if (NULL != handler) {
+ (*handler)(srv, context, revents);
+ }
+ } while (--n > 0);
+ } else if (n < 0 && errno != EINTR) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "fdevent_poll failed:",
+ strerror(errno));
+ }
+
+ if (n >= 0) fdevent_sched_run(srv, srv->ev);
+
+ for (ndx = 0; ndx < srv->joblist->used; ndx++) {
+ connection *con = srv->joblist->ptr[ndx];
+ connection_state_machine(srv, con);
+ }
+
+ srv->joblist->used = 0;
+ }
+
+ if (graceful_shutdown || graceful_restart) {
+ server_graceful_state(srv);
+ }
+
+ if (2 == graceful_shutdown) { /* value 2 indicates idle timeout */
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "server stopped after idle timeout");
+ } else {
+#ifdef HAVE_SIGACTION
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "server stopped by UID =",
+ last_sigterm_info.si_uid,
+ "PID =",
+ last_sigterm_info.si_pid);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "server stopped");
+#endif
+ }
+
+ return 0;
+}
+
+int main (int argc, char **argv) {
+ int rc;
+
+ #ifdef HAVE_GETUID
+ #ifndef HAVE_ISSETUGID
+ #define issetugid() (geteuid() != getuid() || getegid() != getgid())
+ #endif
+ if (0 != getuid() && issetugid()) { /*check as early as possible in main()*/
+ fprintf(stderr,
+ "Are you nuts ? Don't apply a SUID bit to this binary\n");
+ return -1;
+ }
+ #endif
+
+ /* for nice %b handling in strftime() */
+ setlocale(LC_TIME, "C");
+
+ do {
+ server * const srv = server_init();
+
+ if (graceful_restart) {
+ server_sockets_restore(srv);
+ optind = 1;
+ }
+
+ rc = server_main(srv, argc, argv);
+
+ /* clean-up */
+ remove_pid_file(srv);
+ log_error_close(srv);
+ fdevent_close_logger_pipes();
+ if (graceful_restart)
+ server_sockets_save(srv);
+ else
+ network_close(srv);
+ connections_free(srv);
+ plugins_free(srv);
+ server_free(srv);
+
+ if (0 != rc || !graceful_restart) break;
+
+ /* wait for all children to exit before graceful restart */
+ while (waitpid(-1, NULL, 0) > 0) ;
+ } while (graceful_restart);
+
+ return rc;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/server.h b/data/lighttpd/lighttpd-1.4.53/src/server.h
new file mode 100644
index 000000000..d0c6f9bdd
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/server.h
@@ -0,0 +1,7 @@
+#ifndef _SERVER_H_
+#define _SERVER_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/settings.h b/data/lighttpd/lighttpd-1.4.53/src/settings.h
new file mode 100644
index 000000000..a28cf7754
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/settings.h
@@ -0,0 +1,29 @@
+#ifndef _LIGHTTPD_SETTINGS_H_
+#define _LIGHTTPD_SETTINGS_H_
+#include "first.h"
+
+#define FILE_CACHE_MAX 16
+
+/**
+ * max size of a buffer which will just be reset
+ * to ->used = 0 instead of really freeing the buffer
+ *
+ * 64kB (no real reason, just a guess)
+ */
+#define BUFFER_MAX_REUSE_SIZE (4 * 1024)
+
+/* both should be way smaller than SSIZE_MAX :) */
+#define MAX_READ_LIMIT (256*1024)
+#define MAX_WRITE_LIMIT (256*1024)
+
+/**
+ * max size of the HTTP request header
+ *
+ * 32k should be enough for everything (just a guess)
+ *
+ */
+#define MAX_HTTP_REQUEST_HEADER (32 * 1024)
+
+#define HTTP_LINGER_TIMEOUT 5
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sock_addr.c b/data/lighttpd/lighttpd-1.4.53/src/sock_addr.c
new file mode 100644
index 000000000..cc15086c6
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sock_addr.c
@@ -0,0 +1,689 @@
+#include "first.h"
+
+#include "sock_addr.h"
+
+#include "sys-socket.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#ifndef _WIN32
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#include "base.h"
+#include "log.h"
+
+
+unsigned short sock_addr_get_port (const sock_addr *saddr)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ return ntohs(saddr->ipv4.sin_port);
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return ntohs(saddr->ipv6.sin6_port);
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ /*case AF_UNIX:*/
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_is_addr_wildcard (const sock_addr *saddr)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ return (saddr->ipv4.sin_addr.s_addr == INADDR_ANY); /*(htonl(0x0))*/
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return !memcmp(&saddr->ipv6.sin6_addr,&in6addr_any,sizeof(in6addr_any));
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ /*case AF_UNIX:*/
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_is_family_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ return saddr1->plain.sa_family == saddr2->plain.sa_family;
+}
+
+
+int sock_addr_is_port_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
+ switch (saddr1->plain.sa_family) {
+ case AF_INET:
+ return saddr1->ipv4.sin_port == saddr2->ipv4.sin_port;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return saddr1->ipv6.sin6_port == saddr2->ipv6.sin6_port;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return 1;
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_is_addr_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
+ switch (saddr1->plain.sa_family) {
+ case AF_INET:
+ return saddr1->ipv4.sin_addr.s_addr == saddr2->ipv4.sin_addr.s_addr;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return 0 == memcmp(&saddr1->ipv6.sin6_addr, &saddr2->ipv6.sin6_addr,
+ sizeof(struct in6_addr));
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return 0 == strcmp(saddr1->un.sun_path, saddr2->un.sun_path);
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+#if 0
+int sock_addr_is_addr_port_eq (const sock_addr *saddr1, const sock_addr *saddr2)
+{
+ if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
+ switch (saddr1->plain.sa_family) {
+ case AF_INET:
+ return saddr1->ipv4.sin_port == saddr2->ipv4.sin_port
+ && saddr1->ipv4.sin_addr.s_addr == saddr2->ipv4.sin_addr.s_addr;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return saddr1->ipv6.sin6_port == saddr2->ipv6.sin6_port
+ && 0 == memcmp(&saddr1->ipv6.sin6_addr, &saddr2->ipv6.sin6_addr,
+ sizeof(struct in6_addr));
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return 0 == strcmp(saddr1->un.sun_path, saddr2->un.sun_path);
+ #endif
+ default:
+ return 0;
+ }
+}
+#endif
+
+
+int sock_addr_is_addr_eq_bits(const sock_addr *a, const sock_addr *b, int bits) {
+ switch (a->plain.sa_family) {
+ case AF_INET:
+ {
+ uint32_t nm; /* build netmask */
+ if (bits > 32) bits = 32;
+ nm = htonl(~((1u << (32 - (0 != bits ? bits : 32))) - 1));
+ if (b->plain.sa_family == AF_INET) {
+ return
+ (a->ipv4.sin_addr.s_addr & nm) == (b->ipv4.sin_addr.s_addr & nm);
+ }
+ #ifdef HAVE_IPV6
+ else if (b->plain.sa_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED(&b->ipv6.sin6_addr)) {
+ #ifdef s6_addr32
+ in_addr_t x = b->ipv6.sin6_addr.s6_addr32[3];
+ #else
+ in_addr_t x;
+ memcpy(&x, b->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
+ #endif
+ return ((a->ipv4.sin_addr.s_addr & nm) == (x & nm));
+ }
+ #endif
+ return 0;
+ }
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ if (bits > 128) bits = 128;
+ if (b->plain.sa_family == AF_INET6) {
+ uint8_t *c = (uint8_t *)&a->ipv6.sin6_addr.s6_addr[0];
+ uint8_t *d = (uint8_t *)&b->ipv6.sin6_addr.s6_addr[0];
+ int match;
+ do {
+ match = (bits >= 8)
+ ? *c++ == *d++
+ : (*c >> (8 - bits)) == (*d >> (8 - bits));
+ } while (match && (bits -= 8) > 0);
+ return match;
+ }
+ else if (b->plain.sa_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED(&a->ipv6.sin6_addr)) {
+ uint32_t nm = bits < 128
+ ? htonl(~(~0u >> (bits > 96 ? bits - 96 : 0)))
+ : ~0u;
+ #ifdef s6_addr32
+ in_addr_t x = a->ipv6.sin6_addr.s6_addr32[3];
+ #else
+ in_addr_t x;
+ memcpy(&x, a->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
+ #endif
+ return ((x & nm) == (b->ipv4.sin_addr.s_addr & nm));
+ }
+ return 0;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ /*case AF_UNIX:*/
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_assign (sock_addr *saddr, int family, unsigned short nport, const void *naddr)
+{
+ switch (family) {
+ case AF_INET:
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = nport;
+ memcpy(&saddr->ipv4.sin_addr, naddr, 4);
+ return 0;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
+ saddr->ipv6.sin6_family = AF_INET6;
+ saddr->ipv6.sin6_port = nport;
+ memcpy(&saddr->ipv6.sin6_addr, naddr, 16);
+ return 0;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ {
+ size_t len = strlen((char *)naddr) + 1;
+ if (len > sizeof(saddr->un.sun_path)) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memset(&saddr->un, 0, sizeof(struct sockaddr_un));
+ saddr->un.sun_family = AF_UNIX;
+ memcpy(saddr->un.sun_path, naddr, len);
+ return 0;
+ }
+ #endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
+
+
+int sock_addr_inet_pton(sock_addr *saddr, const char *str,
+ int family, unsigned short port)
+{
+ switch (family) {
+ case AF_INET:
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = htons(port);
+ #if defined(HAVE_INET_ATON) /*(Windows does not provide inet_aton())*/
+ return (0 != inet_aton(str, &saddr->ipv4.sin_addr));
+ #else
+ return ((saddr->ipv4.sin_addr.s_addr = inet_addr(str)) != INADDR_NONE);
+ #endif
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
+ saddr->ipv6.sin6_family = AF_INET6;
+ saddr->ipv6.sin6_port = htons(port);
+ return inet_pton(AF_INET6, str, &saddr->ipv6.sin6_addr);
+ #endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
+
+
+const char * sock_addr_inet_ntop(const sock_addr *saddr, char *buf, socklen_t sz)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ #if defined(HAVE_INET_PTON) /*(expect inet_ntop if inet_pton)*/
+ return inet_ntop(AF_INET,(const void *)&saddr->ipv4.sin_addr,buf,sz);
+ #else /*(inet_ntoa() not thread-safe)*/
+ return inet_ntoa(saddr->ipv4.sin_addr);
+ #endif
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ return inet_ntop(AF_INET6,(const void *)&saddr->ipv6.sin6_addr,buf,sz);
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return saddr->un.sun_path;
+ #endif
+ default:
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+}
+
+
+int sock_addr_inet_ntop_copy_buffer(buffer *b, const sock_addr *saddr)
+{
+ /*(incur cost of extra copy to avoid potential extra memory allocation)*/
+ char buf[UNIX_PATH_MAX];
+ const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
+ if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
+ buffer_copy_string(b, s);
+ return 0;
+}
+
+
+int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *saddr)
+{
+ /*(incur cost of extra copy to avoid potential extra memory allocation)*/
+ char buf[UNIX_PATH_MAX];
+ const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
+ if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
+ buffer_append_string(b, s);
+ return 0;
+}
+
+int sock_addr_stringify_append_buffer(buffer *b, const sock_addr *saddr)
+{
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) return -1;
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_int(b, ntohs(saddr->ipv4.sin_port));
+ return 0;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) {
+ #ifdef __COVERITY__
+ force_assert(buffer_string_length(b) > 0); /*(appended "[")*/
+ #endif
+ /* coverity[overflow_sink : FALSE] */
+ buffer_string_set_length(b, buffer_string_length(b)-1);
+ return -1;
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
+ buffer_append_int(b, ntohs(saddr->ipv6.sin6_port));
+ return 0;
+ #endif
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ buffer_append_string(b, saddr->un.sun_path);
+ return 0;
+ #endif
+ default:
+ return 0;
+ }
+}
+
+
+int sock_addr_nameinfo_append_buffer(server *srv, buffer *b, const sock_addr *saddr)
+{
+ /*(this routine originates from
+ * http-header-glue.c:http_response_redirect_to_directory())*/
+ /*(note: name resolution here is *blocking*)*/
+ switch (saddr->plain.sa_family) {
+ case AF_INET:
+ {
+ struct hostent *he = gethostbyaddr((char *)&saddr->ipv4.sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (NULL == he) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "SdS", "NOTICE: gethostbyaddr failed: ",
+ h_errno, ", using ip-address instead");
+
+ sock_addr_inet_ntop_append_buffer(b, saddr);
+ } else {
+ buffer_append_string(b, he->h_name);
+ }
+ return 0;
+ }
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ char hbuf[256];
+ if (0 != getnameinfo((const struct sockaddr *)(&saddr->ipv6),
+ sizeof(saddr->ipv6),
+ hbuf, sizeof(hbuf), NULL, 0, 0)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "SSS", "NOTICE: getnameinfo failed: ",
+ strerror(errno), ", using ip-address instead");
+
+ buffer_append_string_len(b, CONST_STR_LEN("["));
+ sock_addr_inet_ntop_append_buffer(b, saddr);
+ buffer_append_string_len(b, CONST_STR_LEN("]"));
+ } else {
+ buffer_append_string(b, hbuf);
+ }
+ return 0;
+ }
+ #endif
+ default:
+ log_error_write(srv, __FILE__, __LINE__,
+ "S", "ERROR: unsupported address-type");
+ return -1;
+ }
+}
+
+
+int sock_addr_from_str_hints(server *srv, sock_addr *saddr, socklen_t *len, const char *str, int family, unsigned short port)
+{
+ /*(note: name resolution here is *blocking*)*/
+ switch(family) {
+ case AF_UNSPEC:
+ if (0 == strcmp(str, "localhost")) {
+ /*(special-case "localhost" to IPv4 127.0.0.1)*/
+ memset(saddr, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ return 1;
+ }
+ #ifdef HAVE_IPV6
+ else {
+ struct addrinfo hints, *res;
+ int r;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if (0 != (r = getaddrinfo(str, NULL, &hints, &res))) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "sssss", "getaddrinfo failed: ",
+ gai_strerror(r), "'", str, "'");
+ return 0;
+ }
+
+ memcpy(saddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ if (AF_INET6 == saddr->plain.sa_family) {
+ saddr->ipv6.sin6_port = htons(port);
+ *len = sizeof(struct sockaddr_in6);
+ }
+ else { /* AF_INET */
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ }
+ return 1;
+ }
+ #else
+ /* fall through */
+ #endif
+ #ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(saddr, 0, sizeof(struct sockaddr_in6));
+ saddr->ipv6.sin6_family = AF_INET6;
+ if (0 == strcmp(str, "::")) {
+ saddr->ipv6.sin6_addr = in6addr_any;
+ }
+ else if (0 == strcmp(str, "::1")) {
+ saddr->ipv6.sin6_addr = in6addr_loopback;
+ }
+ else {
+ struct addrinfo hints, *res;
+ int r;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if (0 != (r = getaddrinfo(str, NULL, &hints, &res))) {
+ hints.ai_family = AF_INET;
+ if (
+ #ifdef EAI_ADDRFAMILY
+ EAI_ADDRFAMILY == r &&
+ #endif
+ 0 == getaddrinfo(str, NULL, &hints, &res)) {
+ memcpy(saddr, res->ai_addr, res->ai_addrlen);
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ /*assert(*len == res->ai_addrlen);*/
+ freeaddrinfo(res);
+ return 1;
+ }
+
+ log_error_write(srv, __FILE__, __LINE__,
+ "sssss", "getaddrinfo failed: ",
+ gai_strerror(r), "'", str, "'");
+
+ return 0;
+ }
+
+ memcpy(saddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ }
+ saddr->ipv6.sin6_port = htons(port);
+ *len = sizeof(struct sockaddr_in6);
+ return 1;
+ #endif
+ case AF_INET:
+ memset(saddr, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ if (0 == strcmp(str, "0.0.0.0")) {
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else if (0 == strcmp(str, "127.0.0.1")) {
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ }
+ else {
+ #ifdef HAVE_INET_PTON
+ /*(reuse HAVE_INET_PTON for presence of getaddrinfo())*/
+ struct addrinfo hints, *res;
+ int r;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if (0 != (r = getaddrinfo(str, NULL, &hints, &res))) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "sssss", "getaddrinfo failed: ",
+ gai_strerror(r), "'", str, "'");
+ return 0;
+ }
+
+ memcpy(saddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ #else
+ struct hostent *he = gethostbyname(str);
+ if (NULL == he) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "gethostbyname failed:", h_errno, str);
+ return 0;
+ }
+
+ if (he->h_addrtype != AF_INET) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "addr-type != AF_INET:", he->h_addrtype);
+ return 0;
+ }
+
+ if (he->h_length != sizeof(struct in_addr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "addr-length != sizeof(in_addr):",he->h_length);
+ return 0;
+ }
+
+ memcpy(&saddr->ipv4.sin_addr.s_addr,
+ he->h_addr_list[0], he->h_length);
+ #endif
+ }
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ return 1;
+ #ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ memset(saddr, 0, sizeof(struct sockaddr_un));
+ saddr->un.sun_family = AF_UNIX;
+ {
+ size_t hostlen = strlen(str) + 1;
+ if (hostlen > sizeof(saddr->un.sun_path)) {
+ log_error_write(srv, __FILE__, __LINE__, "sS",
+ "unix socket filename too long:", str);
+ /*errno = ENAMETOOLONG;*/
+ return 0;
+ }
+ memcpy(saddr->un.sun_path, str, hostlen);
+ #if defined(SUN_LEN)
+ *len = SUN_LEN(&saddr->un);
+ #else
+ /* stevens says: */
+ *len = hostlen + sizeof(saddr->un.sun_family);
+ #endif
+ }
+ return 1;
+ #else
+ case AF_UNIX:
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unix domain sockets are not supported.");
+ return 0;
+ #endif
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "address family unsupported:", family);
+ /*errno = EAFNOSUPPORT;*/
+ return 0;
+ }
+}
+
+
+int sock_addr_from_str_numeric(server *srv, sock_addr *saddr, const char *str)
+{
+ /*(note: does not handle port if getaddrinfo() is not available)*/
+ /*(note: getaddrinfo() is stricter than inet_aton() in what is accepted)*/
+ /*(this routine originates from mod_extforward.c:ipstr_to_sockaddr()*/
+ #ifdef HAVE_IPV6
+ struct addrinfo hints, *addrlist = NULL;
+ int result;
+
+ /**
+ * quoting $ man getaddrinfo
+ *
+ * NOTES
+ * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
+ * AI_NUMERICSERV is available since glibc 2.3.4.
+ */
+ #ifndef AI_NUMERICSERV
+ #define AI_NUMERICSERV 0
+ #endif
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+ errno = 0;
+ result = getaddrinfo(str, NULL, &hints, &addrlist);
+
+ if (result != 0) {
+ log_error_write(srv, __FILE__, __LINE__, "SSSs(S)",
+ "could not parse ip address ", str, " because ",
+ gai_strerror(result), strerror(errno));
+ } else if (addrlist == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "Problem in parsing ip address ", str,
+ ": succeeded, but no information returned");
+ result = -1;
+ } else switch (addrlist->ai_family) {
+ case AF_INET:
+ memcpy(&saddr->ipv4, addrlist->ai_addr, sizeof(saddr->ipv4));
+ force_assert(AF_INET == saddr->plain.sa_family);
+ break;
+ case AF_INET6:
+ memcpy(&saddr->ipv6, addrlist->ai_addr, sizeof(saddr->ipv6));
+ force_assert(AF_INET6 == saddr->plain.sa_family);
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "Problem in parsing ip address ", str,
+ ": succeeded, but unknown family");
+ result = -1;
+ break;
+ }
+
+ freeaddrinfo(addrlist);
+ return (0 == result);
+ #else
+ UNUSED(srv);
+ saddr->ipv4.sin_addr.s_addr = inet_addr(str);
+ saddr->plain.sa_family = AF_INET;
+ return (saddr->ipv4.sin_addr.s_addr != 0xFFFFFFFF);
+ #endif
+}
+
+
+int sock_addr_from_buffer_hints_numeric(server *srv, sock_addr *saddr, socklen_t *len, const buffer *b, int family, unsigned short port)
+{
+ /*(this routine originates from mod_fastcgi.c and mod_scgi.c)*/
+ if (buffer_string_is_empty(b)) {
+ /*(preserve existing behavior (for now))*/
+ /*(would be better if initialized default when reading config)*/
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ return 1;
+ }
+ else if (1 == sock_addr_inet_pton(saddr, b->ptr, family, port)) {
+ *len = (family == AF_INET)
+ ? sizeof(struct sockaddr_in) /* family == AF_INET */
+ : sizeof(struct sockaddr_in6); /* family == AF_INET6 */
+ return 1;
+ }
+ #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+ else if (family == AF_INET6) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid IPv6 address literal:", b);
+ return 0;
+ }
+ #endif
+ #ifndef HAVE_INET_PTON /*(preserve existing behavior (for now))*/
+ else {
+ struct hostent *he = gethostbyname(b->ptr);
+ if (NULL == he) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "gethostbyname failed:", h_errno, b);
+ return 0;
+ }
+
+ if (he->h_addrtype != AF_INET) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "addr-type != AF_INET:", he->h_addrtype);
+ return 0;
+ }
+
+ if (he->h_length != sizeof(struct in_addr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "addr-length != sizeof(in_addr):",he->h_length);
+ return 0;
+ }
+
+ memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
+ memcpy(&saddr->ipv4.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
+ saddr->ipv4.sin_family = AF_INET;
+ saddr->ipv4.sin_port = htons(port);
+ *len = sizeof(struct sockaddr_in);
+ }
+ #else
+ UNUSED(srv);
+ #endif
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sock_addr.h b/data/lighttpd/lighttpd-1.4.53/src/sock_addr.h
new file mode 100644
index 000000000..e949e7ef9
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sock_addr.h
@@ -0,0 +1,51 @@
+#ifndef INCLUDED_SOCK_ADDR_H
+#define INCLUDED_SOCK_ADDR_H
+#include "first.h"
+
+#include <sys/types.h>
+#include "sys-socket.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+
+
+union sock_addr {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+#endif
+ struct sockaddr_in ipv4;
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un un;
+#endif
+ struct sockaddr plain;
+};
+
+
+static inline int sock_addr_get_family (const sock_addr *saddr);
+static inline int sock_addr_get_family (const sock_addr *saddr) {
+ return saddr->plain.sa_family;
+}
+
+unsigned short sock_addr_get_port (const sock_addr *saddr);
+int sock_addr_is_addr_wildcard (const sock_addr *saddr);
+int sock_addr_is_family_eq (const sock_addr *saddr1, const sock_addr *saddr2);
+int sock_addr_is_port_eq (const sock_addr *saddr1, const sock_addr *saddr2);
+int sock_addr_is_addr_eq (const sock_addr *saddr1, const sock_addr *saddr2);
+/*int sock_addr_is_addr_port_eq (const sock_addr *saddr1, const sock_addr *saddr2);*/
+int sock_addr_is_addr_eq_bits(const sock_addr *a, const sock_addr *b, int bits);
+int sock_addr_assign (sock_addr *saddr, int family, unsigned short nport, const void *naddr);
+
+int sock_addr_inet_pton(sock_addr *saddr, const char *str, int family, unsigned short port);
+
+const char * sock_addr_inet_ntop(const sock_addr *saddr, char *buf, socklen_t sz);
+int sock_addr_inet_ntop_copy_buffer(buffer *b, const sock_addr *saddr);
+int sock_addr_inet_ntop_append_buffer(buffer *b, const sock_addr *saddr);
+int sock_addr_stringify_append_buffer(buffer *b, const sock_addr *saddr);
+int sock_addr_nameinfo_append_buffer(server *srv, buffer *b, const sock_addr *saddr);
+
+int sock_addr_from_buffer_hints_numeric(server *srv, sock_addr *saddr, socklen_t *len, const buffer *b, int family, unsigned short port);
+int sock_addr_from_str_hints(server *srv, sock_addr *saddr, socklen_t *len, const char *str, int family, unsigned short port);
+int sock_addr_from_str_numeric(server *srv, sock_addr *saddr, const char *str);
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/splaytree.c b/data/lighttpd/lighttpd-1.4.53/src/splaytree.c
new file mode 100644
index 000000000..51aa0ca7b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/splaytree.c
@@ -0,0 +1,209 @@
+/*
+ An implementation of top-down splaying with sizes
+ D. Sleator <sleator@cs.cmu.edu>, January 1994.
+
+ This extends top-down-splay.c to maintain a size field in each node.
+ This is the number of nodes in the subtree rooted there. This makes
+ it possible to efficiently compute the rank of a key. (The rank is
+ the number of nodes to the left of the given key.) It it also
+ possible to quickly find the node of a given rank. Both of these
+ operations are illustrated in the code below. The remainder of this
+ introduction is taken from top-down-splay.c.
+
+ "Splay trees", or "self-adjusting search trees" are a simple and
+ efficient data structure for storing an ordered set. The data
+ structure consists of a binary tree, with no additional fields. It
+ allows searching, insertion, deletion, deletemin, deletemax,
+ splitting, joining, and many other operations, all with amortized
+ logarithmic performance. Since the trees adapt to the sequence of
+ requests, their performance on real access patterns is typically even
+ better. Splay trees are described in a number of texts and papers
+ [1,2,3,4].
+
+ The code here is adapted from simple top-down splay, at the bottom of
+ page 669 of [2]. It can be obtained via anonymous ftp from
+ spade.pc.cs.cmu.edu in directory /usr/sleator/public.
+
+ The chief modification here is that the splay operation works even if the
+ item being splayed is not in the tree, and even if the tree root of the
+ tree is NULL. So the line:
+
+ t = splay(i, t);
+
+ causes it to search for item with key i in the tree rooted at t. If it's
+ there, it is splayed to the root. If it isn't there, then the node put
+ at the root is the last one before NULL that would have been reached in a
+ normal binary search for i. (It's a neighbor of i in the tree.) This
+ allows many other operations to be easily implemented, as shown below.
+
+ [1] "Data Structures and Their Algorithms", Lewis and Denenberg,
+ Harper Collins, 1991, pp 243-251.
+ [2] "Self-adjusting Binary Search Trees" Sleator and Tarjan,
+ JACM Volume 32, No 3, July 1985, pp 652-686.
+ [3] "Data Structure and Algorithm Analysis", Mark Weiss,
+ Benjamin Cummins, 1992, pp 119-130.
+ [4] "Data Structures, Algorithms, and Performance", Derick Wood,
+ Addison-Wesley, 1993, pp 367-375
+*/
+
+#include "splaytree.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#define compare(i,j) ((i)-(j))
+/* This is the comparison. */
+/* Returns <0 if i<j, =0 if i=j, and >0 if i>j */
+
+#define node_size splaytree_size
+
+/* Splay using the key i (which may or may not be in the tree.)
+ * The starting root is t, and the tree used is defined by rat
+ * size fields are maintained */
+splay_tree * splaytree_splay (splay_tree *t, int i) {
+ splay_tree N, *l, *r, *y;
+ int comp, l_size, r_size;
+
+ if (t == NULL) return t;
+ N.left = N.right = NULL;
+ l = r = &N;
+ l_size = r_size = 0;
+
+ for (;;) {
+ comp = compare(i, t->key);
+ if (comp < 0) {
+ if (t->left == NULL) break;
+ if (compare(i, t->left->key) < 0) {
+ y = t->left; /* rotate right */
+ t->left = y->right;
+ y->right = t;
+ t->size = node_size(t->left) + node_size(t->right) + 1;
+ t = y;
+ if (t->left == NULL) break;
+ }
+ r->left = t; /* link right */
+ r = t;
+ t = t->left;
+ r_size += 1+node_size(r->right);
+ } else if (comp > 0) {
+ if (t->right == NULL) break;
+ if (compare(i, t->right->key) > 0) {
+ y = t->right; /* rotate left */
+ t->right = y->left;
+ y->left = t;
+ t->size = node_size(t->left) + node_size(t->right) + 1;
+ t = y;
+ if (t->right == NULL) break;
+ }
+ l->right = t; /* link left */
+ l = t;
+ t = t->right;
+ l_size += 1+node_size(l->left);
+ } else {
+ break;
+ }
+ }
+ l_size += node_size(t->left); /* Now l_size and r_size are the sizes of */
+ r_size += node_size(t->right); /* the left and right trees we just built.*/
+ t->size = l_size + r_size + 1;
+
+ l->right = r->left = NULL;
+
+ /* The following two loops correct the size fields of the right path */
+ /* from the left child of the root and the right path from the left */
+ /* child of the root. */
+ for (y = N.right; y != NULL; y = y->right) {
+ y->size = l_size;
+ l_size -= 1+node_size(y->left);
+ }
+ for (y = N.left; y != NULL; y = y->left) {
+ y->size = r_size;
+ r_size -= 1+node_size(y->right);
+ }
+
+ l->right = t->left; /* assemble */
+ r->left = t->right;
+ t->left = N.right;
+ t->right = N.left;
+
+ return t;
+}
+
+splay_tree * splaytree_insert(splay_tree * t, int i, void *data) {
+/* Insert key i into the tree t, if it is not already there. */
+/* Return a pointer to the resulting tree. */
+ splay_tree * new;
+
+ if (t != NULL) {
+ t = splaytree_splay(t, i);
+ if (compare(i, t->key)==0) {
+ return t; /* it's already there */
+ }
+ }
+ new = (splay_tree *) malloc (sizeof (splay_tree));
+ assert(new);
+ if (t == NULL) {
+ new->left = new->right = NULL;
+ } else if (compare(i, t->key) < 0) {
+ new->left = t->left;
+ new->right = t;
+ t->left = NULL;
+ t->size = 1+node_size(t->right);
+ } else {
+ new->right = t->right;
+ new->left = t;
+ t->right = NULL;
+ t->size = 1+node_size(t->left);
+ }
+ new->key = i;
+ new->data = data;
+ new->size = 1 + node_size(new->left) + node_size(new->right);
+ return new;
+}
+
+splay_tree * splaytree_delete(splay_tree *t, int i) {
+/* Deletes i from the tree if it's there. */
+/* Return a pointer to the resulting tree. */
+ splay_tree * x;
+ int tsize;
+
+ if (t==NULL) return NULL;
+ tsize = t->size;
+ t = splaytree_splay(t, i);
+ if (compare(i, t->key) == 0) { /* found it */
+ if (t->left == NULL) {
+ x = t->right;
+ } else {
+ x = splaytree_splay(t->left, i);
+ x->right = t->right;
+ }
+ free(t);
+ if (x != NULL) {
+ x->size = tsize-1;
+ }
+ return x;
+ } else {
+ return t; /* It wasn't there */
+ }
+}
+
+#if 0
+static splay_tree *find_rank(int r, splay_tree *t) {
+/* Returns a pointer to the node in the tree with the given rank. */
+/* Returns NULL if there is no such node. */
+/* Does not change the tree. To guarantee logarithmic behavior, */
+/* the node found here should be splayed to the root. */
+ int lsize;
+ if ((r < 0) || (r >= node_size(t))) return NULL;
+ for (;;) {
+ lsize = node_size(t->left);
+ if (r < lsize) {
+ t = t->left;
+ } else if (r > lsize) {
+ r = r - lsize -1;
+ t = t->right;
+ } else {
+ return t;
+ }
+ }
+}
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/splaytree.h b/data/lighttpd/lighttpd-1.4.53/src/splaytree.h
new file mode 100644
index 000000000..cc5fe9b1c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/splaytree.h
@@ -0,0 +1,25 @@
+#ifndef _SPLAY_TREE_H_
+#define _SPLAY_TREE_H_
+#include "first.h"
+
+typedef struct tree_node {
+ struct tree_node * left, * right;
+ int key;
+ int size; /* maintained to be the number of nodes rooted here */
+
+ void *data;
+} splay_tree;
+
+
+splay_tree * splaytree_splay (splay_tree *t, int key);
+splay_tree * splaytree_insert(splay_tree *t, int key, void *data);
+splay_tree * splaytree_delete(splay_tree *t, int key);
+splay_tree * splaytree_size(splay_tree *t);
+
+#define splaytree_size(x) (((x)==NULL) ? 0 : ((x)->size))
+/* This macro returns the size of a node. Unlike "x->size", */
+/* it works even if x=NULL. The test could be avoided by using */
+/* a special version of NULL which was a real node with size 0. */
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/stat_cache.c b/data/lighttpd/lighttpd-1.4.53/src/stat_cache.c
new file mode 100644
index 000000000..d470b2817
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/stat_cache.c
@@ -0,0 +1,859 @@
+#include "first.h"
+
+#include "stat_cache.h"
+#include "base.h"
+#include "log.h"
+#include "fdevent.h"
+#include "etag.h"
+#include "splaytree.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_ATTR_ATTRIBUTES_H
+# include <attr/attributes.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+# include <sys/extattr.h>
+#endif
+
+#ifndef HAVE_LSTAT
+# define lstat stat
+#endif
+
+/*
+ * stat-cache
+ *
+ * we cache the stat() calls in our own storage
+ * the directories are cached in FAM
+ *
+ * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
+ *
+ * if the stat()-cache is queried we check if the version id for the directory is the
+ * same and return immediatly.
+ *
+ *
+ * What we need:
+ *
+ * - for each stat-cache entry we need a fast indirect lookup on the directory name
+ * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
+ *
+ * stat <<-> directory <-> FAMRequest
+ *
+ * if file is deleted, directory is dirty, file is rechecked ...
+ * if directory is deleted, directory mapping is removed
+ *
+ * */
+
+/* the directory name is too long to always compare on it
+ * - we need a hash
+ * - the hash-key is used as sorting criteria for a tree
+ * - a splay-tree is used as we can use the caching effect of it
+ */
+
+/* we want to cleanup the stat-cache every few seconds, let's say 10
+ *
+ * - remove entries which are outdated since 30s
+ * - remove entries which are fresh but havn't been used since 60s
+ * - if we don't have a stat-cache entry for a directory, release it from the monitor
+ */
+
+
+enum {
+ STAT_CACHE_ENGINE_UNSET,
+ STAT_CACHE_ENGINE_NONE,
+ STAT_CACHE_ENGINE_SIMPLE,
+ STAT_CACHE_ENGINE_FAM
+};
+
+#ifdef HAVE_FAM_H
+struct stat_cache_fam;
+#endif
+
+typedef struct stat_cache {
+ splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
+ #ifdef HAVE_FAM_H
+ struct stat_cache_fam *scf;
+ #endif
+} stat_cache;
+
+
+/* the famous DJB hash function for strings */
+static uint32_t hashme(const char *str, int z) {
+ uint32_t hash = 5381;
+ for (const unsigned char *s = (const unsigned char *)str; *s; ++s) {
+ hash = ((hash << 5) + hash) ^ *s;
+ }
+
+ /* customizations */
+
+ /* (differentiate hash values with and w/o con->conf.follow_symlink) */
+ hash = ((hash << 5) + hash) ^ (z ? '1' : '0');
+
+ hash &= ~(((uint32_t)1) << 31); /* strip the highest bit */
+
+ return hash;
+}
+
+
+#ifdef HAVE_FAM_H
+
+#include <fam.h>
+
+typedef struct {
+ FAMRequest *req;
+ buffer *name;
+ int version;
+} fam_dir_entry;
+
+typedef struct stat_cache_fam {
+ splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
+
+ FAMConnection fam;
+ int fam_fcce_ndx;
+
+ int dir_ndx;
+ fam_dir_entry *fam_dir;
+ buffer *dir_name; /* for building the dirname from the filename */
+} stat_cache_fam;
+
+static fam_dir_entry * fam_dir_entry_init(void) {
+ fam_dir_entry *fam_dir = NULL;
+
+ fam_dir = calloc(1, sizeof(*fam_dir));
+ force_assert(NULL != fam_dir);
+
+ fam_dir->name = buffer_init();
+
+ return fam_dir;
+}
+
+static void fam_dir_entry_free(FAMConnection *fc, void *data) {
+ fam_dir_entry *fam_dir = data;
+
+ if (!fam_dir) return;
+
+ FAMCancelMonitor(fc, fam_dir->req);
+
+ buffer_free(fam_dir->name);
+ free(fam_dir->req);
+
+ free(fam_dir);
+}
+
+static handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent) {
+ size_t i;
+ stat_cache_fam *scf = srv->stat_cache->scf;
+ size_t events;
+
+ UNUSED(_fce);
+ /* */
+
+ if (revent & FDEVENT_IN) {
+ events = FAMPending(&scf->fam);
+
+ for (i = 0; i < events; i++) {
+ FAMEvent fe;
+ fam_dir_entry *fam_dir;
+ splay_tree *node;
+ int ndx, j;
+
+ FAMNextEvent(&scf->fam, &fe);
+
+ /* handle event */
+
+ switch(fe.code) {
+ case FAMChanged:
+ case FAMDeleted:
+ case FAMMoved:
+ /* if the filename is a directory remove the entry */
+
+ fam_dir = fe.userdata;
+ fam_dir->version++;
+
+ /* file/dir is still here */
+ if (fe.code == FAMChanged) break;
+
+ /* we have 2 versions, follow and no-follow-symlink */
+
+ for (j = 0; j < 2; j++) {
+
+ ndx = hashme(fe.filename, j);
+
+ scf->dirs = splaytree_splay(scf->dirs, ndx);
+ node = scf->dirs;
+
+ if (node && (node->key == ndx)) {
+ int osize = splaytree_size(scf->dirs);
+
+ fam_dir_entry_free(&scf->fam, node->data);
+ scf->dirs = splaytree_delete(scf->dirs, ndx);
+
+ force_assert(osize - 1 == splaytree_size(scf->dirs));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (revent & (FDEVENT_HUP|FDEVENT_RDHUP)) {
+ /* fam closed the connection */
+ fdevent_event_del(srv->ev, &(scf->fam_fcce_ndx), FAMCONNECTION_GETFD(&scf->fam));
+ fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(&scf->fam));
+
+ FAMClose(&scf->fam);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static stat_cache_fam * stat_cache_init_fam(server *srv) {
+ stat_cache_fam *scf = calloc(1, sizeof(*scf));
+ scf->fam_fcce_ndx = -1;
+ scf->dir_name = buffer_init();
+
+ /* setup FAM */
+ if (0 != FAMOpen2(&scf->fam, "lighttpd")) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "could not open a fam connection, dieing.");
+ return NULL;
+ }
+ #ifdef HAVE_FAMNOEXISTS
+ FAMNoExists(&scf->fam);
+ #endif
+
+ fdevent_setfd_cloexec(FAMCONNECTION_GETFD(&scf->fam));
+ fdevent_register(srv->ev, FAMCONNECTION_GETFD(&scf->fam), stat_cache_handle_fdevent, NULL);
+ fdevent_event_set(srv->ev, &(scf->fam_fcce_ndx), FAMCONNECTION_GETFD(&scf->fam), FDEVENT_IN | FDEVENT_RDHUP);
+
+ return scf;
+}
+
+static void stat_cache_free_fam(stat_cache_fam *scf) {
+ if (NULL == scf) return;
+ buffer_free(scf->dir_name);
+
+ while (scf->dirs) {
+ int osize;
+ splay_tree *node = scf->dirs;
+
+ osize = scf->dirs->size;
+
+ fam_dir_entry_free(&scf->fam, node->data);
+ scf->dirs = splaytree_delete(scf->dirs, node->key);
+
+ if (osize == 1) {
+ force_assert(NULL == scf->dirs);
+ } else {
+ force_assert(osize == (scf->dirs->size + 1));
+ }
+ }
+
+ if (-1 != scf->fam_fcce_ndx) {
+ /* fd events already gone */
+ scf->fam_fcce_ndx = -1;
+
+ FAMClose(&scf->fam);
+ }
+
+ free(scf);
+}
+
+static int buffer_copy_dirname(buffer *dst, const buffer *file) {
+ size_t i;
+
+ if (buffer_string_is_empty(file)) return -1;
+
+ for (i = buffer_string_length(file); i > 0; i--) {
+ if (file->ptr[i] == '/') {
+ buffer_copy_string_len(dst, file->ptr, i);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static handler_t stat_cache_fam_dir_check(server *srv, stat_cache_fam *scf, stat_cache_entry *sce, const buffer *name, unsigned int follow_symlink) {
+ if (0 != buffer_copy_dirname(scf->dir_name, name)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "no '/' found in filename:", name);
+ return HANDLER_ERROR;
+ }
+
+ scf->dir_ndx = hashme(scf->dir_name->ptr, follow_symlink);
+
+ scf->dirs = splaytree_splay(scf->dirs, scf->dir_ndx);
+
+ if ((NULL != scf->dirs) && (scf->dirs->key == scf->dir_ndx)) {
+ scf->fam_dir = scf->dirs->data;
+
+ /* check whether we got a collision */
+ if (buffer_is_equal(scf->dir_name, scf->fam_dir->name)) {
+ /* test whether a found file cache entry is still ok */
+ if ((NULL != sce) && (scf->fam_dir->version == sce->dir_version)) {
+ /* the stat()-cache entry is still ok */
+ return HANDLER_FINISHED;
+ }
+ } else {
+ /* hash collision, forget about the entry */
+ scf->fam_dir = NULL;
+ }
+ } else {
+ scf->fam_dir = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+static void stat_cache_fam_dir_monitor(server *srv, stat_cache_fam *scf, stat_cache_entry *sce, const buffer *name) {
+ /* is this directory already registered ? */
+ fam_dir_entry *fam_dir = scf->fam_dir;
+ if (NULL == fam_dir) {
+ fam_dir = fam_dir_entry_init();
+
+ buffer_copy_buffer(fam_dir->name, scf->dir_name);
+
+ fam_dir->version = 1;
+
+ fam_dir->req = calloc(1, sizeof(FAMRequest));
+ force_assert(NULL != fam_dir);
+
+ if (0 != FAMMonitorDirectory(&scf->fam, fam_dir->name->ptr,
+ fam_dir->req, fam_dir)) {
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs",
+ "monitoring dir failed:",
+ fam_dir->name,
+ "file:", name,
+ FamErrlist[FAMErrno]);
+
+ fam_dir_entry_free(&scf->fam, fam_dir);
+ fam_dir = NULL;
+ } else {
+ int osize = splaytree_size(scf->dirs);
+
+ /* already splayed scf->dir_ndx */
+ if ((NULL != scf->dirs) && (scf->dirs->key == scf->dir_ndx)) {
+ /* hash collision: replace old entry */
+ fam_dir_entry_free(&scf->fam, scf->dirs->data);
+ scf->dirs->data = fam_dir;
+ } else {
+ scf->dirs = splaytree_insert(scf->dirs, scf->dir_ndx, fam_dir);
+ force_assert(osize == (splaytree_size(scf->dirs) - 1));
+ }
+
+ force_assert(scf->dirs);
+ force_assert(scf->dirs->data == fam_dir);
+ scf->fam_dir = fam_dir;
+ }
+ }
+
+ /* bind the fam_fc to the stat() cache entry */
+
+ if (fam_dir) {
+ sce->dir_version = fam_dir->version;
+ }
+}
+
+#endif
+
+
+stat_cache *stat_cache_init(server *srv) {
+ stat_cache *sc = NULL;
+ UNUSED(srv);
+
+ sc = calloc(1, sizeof(*sc));
+ force_assert(NULL != sc);
+
+#ifdef HAVE_FAM_H
+ if (STAT_CACHE_ENGINE_FAM == srv->srvconf.stat_cache_engine) {
+ sc->scf = stat_cache_init_fam(srv);
+ if (NULL == sc->scf) {
+ free(sc);
+ return NULL;
+ }
+ }
+#endif
+
+ return sc;
+}
+
+static stat_cache_entry * stat_cache_entry_init(void) {
+ stat_cache_entry *sce = NULL;
+
+ sce = calloc(1, sizeof(*sce));
+ force_assert(NULL != sce);
+
+ sce->name = buffer_init();
+ sce->etag = buffer_init();
+ sce->content_type = buffer_init();
+
+ return sce;
+}
+
+static void stat_cache_entry_free(void *data) {
+ stat_cache_entry *sce = data;
+ if (!sce) return;
+
+ buffer_free(sce->etag);
+ buffer_free(sce->name);
+ buffer_free(sce->content_type);
+
+ free(sce);
+}
+
+void stat_cache_free(stat_cache *sc) {
+ while (sc->files) {
+ int osize;
+ splay_tree *node = sc->files;
+
+ osize = sc->files->size;
+
+ stat_cache_entry_free(node->data);
+ sc->files = splaytree_delete(sc->files, node->key);
+
+ force_assert(osize - 1 == splaytree_size(sc->files));
+ }
+
+#ifdef HAVE_FAM_H
+ stat_cache_free_fam(sc->scf);
+#endif
+ free(sc);
+}
+
+int stat_cache_choose_engine (server *srv, const buffer *stat_cache_string) {
+ if (buffer_string_is_empty(stat_cache_string)) {
+ srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+ } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
+ srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+#ifdef HAVE_FAM_H
+ } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
+ srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
+#endif
+ } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
+ srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.stat-cache-engine can be one of \"disable\", \"simple\","
+#ifdef HAVE_FAM_H
+ " \"fam\","
+#endif
+ " but not:", stat_cache_string);
+ return -1;
+ }
+ return 0;
+}
+
+#if defined(HAVE_XATTR)
+static int stat_cache_attr_get(buffer *buf, char *name, char *xattrname) {
+ int attrlen;
+ int ret;
+
+ buffer_string_prepare_copy(buf, 1023);
+ attrlen = buf->size - 1;
+ if(0 == (ret = attr_get(name, xattrname, buf->ptr, &attrlen, 0))) {
+ buffer_commit(buf, attrlen);
+ }
+ return ret;
+}
+#elif defined(HAVE_EXTATTR)
+static int stat_cache_attr_get(buffer *buf, char *name, char *xattrname) {
+ ssize_t attrlen;
+
+ buffer_string_prepare_copy(buf, 1023);
+
+ if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, xattrname, buf->ptr, buf->size - 1))) {
+ buf->used = attrlen + 1;
+ buf->ptr[attrlen] = '\0';
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+const buffer * stat_cache_mimetype_by_ext(const connection *con, const char *name, size_t nlen)
+{
+ const char *end = name + nlen; /*(end of string)*/
+ const size_t used = con->conf.mimetypes->used;
+ if (used < 16) {
+ for (size_t i = 0; i < used; ++i) {
+ /* suffix match */
+ const data_string *ds = (data_string *)con->conf.mimetypes->data[i];
+ const size_t klen = buffer_string_length(ds->key);
+ if (klen <= nlen && 0 == strncasecmp(end-klen, ds->key->ptr, klen))
+ return ds->value;
+ }
+ }
+ else {
+ const char *s;
+ const data_string *ds;
+ if (nlen) {
+ for (s = end-1; s != name && *s != '/'; --s) ; /*(like memrchr())*/
+ if (*s == '/') ++s;
+ }
+ else {
+ s = name;
+ }
+ /* search for basename, then longest .ext2.ext1, then .ext1, then "" */
+ ds = (data_string *)array_get_element_klen(con->conf.mimetypes, s, end - s);
+ if (NULL != ds) return ds->value;
+ while (++s < end) {
+ while (*s != '.' && ++s != end) ;
+ if (s == end) break;
+ /* search ".ext" then "ext" */
+ ds = (data_string *)array_get_element_klen(con->conf.mimetypes, s, end - s);
+ if (NULL != ds) return ds->value;
+ /* repeat search without leading '.' to handle situation where
+ * admin configured mimetype.assign keys without leading '.' */
+ if (++s < end) {
+ if (*s == '.') { --s; continue; }
+ ds = (data_string *)array_get_element_klen(con->conf.mimetypes, s, end - s);
+ if (NULL != ds) return ds->value;
+ }
+ }
+ /* search for ""; catchall */
+ ds = (data_string *)array_get_element(con->conf.mimetypes, "");
+ if (NULL != ds) return ds->value;
+ }
+
+ return NULL;
+}
+
+const buffer * stat_cache_content_type_get(server *srv, connection *con, const buffer *name, stat_cache_entry *sce)
+{
+ /*(invalid caching if user config has multiple, different
+ * con->conf.mimetypes for same extension (not expected))*/
+ if (!buffer_string_is_empty(sce->content_type)) return sce->content_type;
+
+ if (S_ISREG(sce->st.st_mode)) {
+ /* determine mimetype */
+ buffer_clear(sce->content_type);
+ #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ if (con->conf.use_xattr) {
+ stat_cache_attr_get(sce->content_type, name->ptr, srv->srvconf.xattr_name->ptr);
+ }
+ #else
+ UNUSED(srv);
+ #endif
+ /* xattr did not set a content-type. ask the config */
+ if (buffer_string_is_empty(sce->content_type)) {
+ const buffer *type = stat_cache_mimetype_by_ext(con, CONST_BUF_LEN(name));
+ if (NULL != type) {
+ buffer_copy_buffer(sce->content_type, type);
+ }
+ }
+ return sce->content_type;
+ }
+
+ return NULL;
+}
+
+const buffer * stat_cache_etag_get(stat_cache_entry *sce, etag_flags_t flags) {
+ /*(invalid caching if user config has multiple, different con->etag_flags
+ * for same path (not expected, since etag flags should be by filesystem))*/
+ if (!buffer_string_is_empty(sce->etag)) return sce->etag;
+
+ if (S_ISREG(sce->st.st_mode) || S_ISDIR(sce->st.st_mode)) {
+ etag_create(sce->etag, &sce->st, flags);
+ return sce->etag;
+ }
+
+ return NULL;
+}
+
+#ifdef HAVE_LSTAT
+static int stat_cache_lstat(server *srv, buffer *dname, struct stat *lst) {
+ if (lstat(dname->ptr, lst) == 0) {
+ return S_ISLNK(lst->st_mode) ? 0 : 1;
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "lstat failed for:",
+ dname, strerror(errno));
+ };
+ return -1;
+}
+#endif
+
+/***
+ *
+ *
+ *
+ * returns:
+ * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
+ * - HANDLER_ERROR on stat() failed -> see errno for problem
+ */
+
+handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce) {
+ stat_cache_entry *sce = NULL;
+ stat_cache *sc;
+ struct stat st;
+ int fd;
+ const int follow_symlink = con->conf.follow_symlink;
+ struct stat lst;
+ int file_ndx;
+
+ *ret_sce = NULL;
+
+ /*
+ * check if the directory for this file has changed
+ */
+
+ sc = srv->stat_cache;
+
+ file_ndx = hashme(name->ptr, follow_symlink);
+ sc->files = splaytree_splay(sc->files, file_ndx);
+
+ if (sc->files && (sc->files->key == file_ndx)) {
+ /* we have seen this file already and
+ * don't stat() it again in the same second */
+
+ sce = sc->files->data;
+
+ /* check if the name is the same, we might have a collision */
+
+ if (buffer_is_equal(name, sce->name)) {
+ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
+ if (sce->stat_ts == srv->cur_ts && follow_symlink) {
+ *ret_sce = sce;
+ return HANDLER_GO_ON;
+ }
+ }
+ } else {
+ /* collision, forget about the entry */
+ sce = NULL;
+ }
+ }
+
+#ifdef HAVE_FAM_H
+ /* dir-check */
+ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
+ switch (stat_cache_fam_dir_check(srv, sc->scf, sce, name, follow_symlink)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ *ret_sce = sce;
+ return HANDLER_GO_ON;
+ case HANDLER_ERROR:
+ default:
+ return HANDLER_ERROR;
+ }
+ }
+#endif
+
+ /*
+ * *lol*
+ * - open() + fstat() on a named-pipe results in a (intended) hang.
+ * - stat() if regular file + open() to see if we can read from it is better
+ *
+ * */
+ if (-1 == stat(name->ptr, &st)) {
+ return HANDLER_ERROR;
+ }
+
+
+ if (S_ISREG(st.st_mode)) {
+ /* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */
+ if (name->ptr[buffer_string_length(name) - 1] == '/') {
+ errno = ENOTDIR;
+ return HANDLER_ERROR;
+ }
+
+ /* try to open the file to check if we can read it */
+ if (-1 == (fd = open(name->ptr, O_RDONLY))) {
+ return HANDLER_ERROR;
+ }
+ close(fd);
+ }
+
+ if (NULL == sce) {
+
+ sce = stat_cache_entry_init();
+ buffer_copy_buffer(sce->name, name);
+
+ /* already splayed file_ndx */
+ if ((NULL != sc->files) && (sc->files->key == file_ndx)) {
+ /* hash collision: replace old entry */
+ stat_cache_entry_free(sc->files->data);
+ sc->files->data = sce;
+ } else {
+ int osize = splaytree_size(sc->files);
+
+ sc->files = splaytree_insert(sc->files, file_ndx, sce);
+ force_assert(osize + 1 == splaytree_size(sc->files));
+ }
+ force_assert(sc->files);
+ force_assert(sc->files->data == sce);
+
+ } else {
+
+ buffer_clear(sce->etag);
+ #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
+ buffer_clear(sce->content_type);
+ #endif
+
+ }
+
+ sce->st = st;
+ sce->stat_ts = srv->cur_ts;
+
+ /* catch the obvious symlinks
+ *
+ * this is not a secure check as we still have a race-condition between
+ * the stat() and the open. We can only solve this by
+ * 1. open() the file
+ * 2. fstat() the fd
+ *
+ * and keeping the file open for the rest of the time. But this can
+ * only be done at network level.
+ *
+ * per default it is not a symlink
+ * */
+#ifdef HAVE_LSTAT
+ sce->is_symlink = 0;
+
+ /* we want to only check for symlinks if we should block symlinks.
+ */
+ if (!follow_symlink) {
+ if (stat_cache_lstat(srv, name, &lst) == 0) {
+ sce->is_symlink = 1;
+ }
+
+ /*
+ * we assume "/" can not be symlink, so
+ * skip the symlink stuff if our path is /
+ **/
+ else if (buffer_string_length(name) > 1) {
+ buffer *dname;
+ char *s_cur;
+
+ dname = buffer_init();
+ buffer_copy_buffer(dname, name);
+
+ while ((s_cur = strrchr(dname->ptr, '/'))) {
+ buffer_string_set_length(dname, s_cur - dname->ptr);
+ if (dname->ptr == s_cur) {
+ break;
+ }
+ if (stat_cache_lstat(srv, dname, &lst) == 0) {
+ sce->is_symlink = 1;
+ break;
+ };
+ };
+ buffer_free(dname);
+ };
+ }
+#endif
+
+#ifdef HAVE_FAM_H
+ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
+ stat_cache_fam_dir_monitor(srv, sc->scf, sce, name);
+ }
+#endif
+
+ *ret_sce = sce;
+
+ return HANDLER_GO_ON;
+}
+
+int stat_cache_open_rdonly_fstat (server *srv, connection *con, buffer *name, struct stat *st) {
+ /*(Note: O_NOFOLLOW affects only the final path segment, the target file,
+ * not any intermediate symlinks along the path)*/
+ #ifndef O_BINARY
+ #define O_BINARY 0
+ #endif
+ #ifndef O_LARGEFILE
+ #define O_LARGEFILE 0
+ #endif
+ #ifndef O_NOCTTY
+ #define O_NOCTTY 0
+ #endif
+ #ifndef O_NONBLOCK
+ #define O_NONBLOCK 0
+ #endif
+ #ifndef O_NOFOLLOW
+ #define O_NOFOLLOW 0
+ #endif
+ const int oflags = O_BINARY | O_LARGEFILE | O_NOCTTY | O_NONBLOCK
+ | (con->conf.follow_symlink ? 0 : O_NOFOLLOW);
+ const int fd = fdevent_open_cloexec(name->ptr, O_RDONLY | oflags, 0);
+ if (fd >= 0) {
+ if (0 == fstat(fd, st)) {
+ return fd;
+ } else {
+ close(fd);
+ }
+ }
+ UNUSED(srv); /*(might log_error_write(srv, ...) in the future)*/
+ return -1;
+}
+
+/**
+ * remove stat() from cache which havn't been stat()ed for
+ * more than 10 seconds
+ *
+ *
+ * walk though the stat-cache, collect the ids which are too old
+ * and remove them in a second loop
+ */
+
+static int stat_cache_tag_old_entries(server *srv, splay_tree *t, int *keys, size_t *ndx) {
+ stat_cache_entry *sce;
+
+ if (!t) return 0;
+
+ stat_cache_tag_old_entries(srv, t->left, keys, ndx);
+ stat_cache_tag_old_entries(srv, t->right, keys, ndx);
+
+ sce = t->data;
+
+ if (srv->cur_ts - sce->stat_ts > 2) {
+ keys[(*ndx)++] = t->key;
+ }
+
+ return 0;
+}
+
+int stat_cache_trigger_cleanup(server *srv) {
+ stat_cache *sc;
+ size_t max_ndx = 0, i;
+ int *keys;
+
+ sc = srv->stat_cache;
+
+ if (!sc->files) return 0;
+
+ keys = calloc(1, sizeof(int) * sc->files->size);
+ force_assert(NULL != keys);
+
+ stat_cache_tag_old_entries(srv, sc->files, keys, &max_ndx);
+
+ for (i = 0; i < max_ndx; i++) {
+ int ndx = keys[i];
+ splay_tree *node;
+
+ sc->files = splaytree_splay(sc->files, ndx);
+
+ node = sc->files;
+
+ if (node && (node->key == ndx)) {
+ stat_cache_entry_free(node->data);
+ sc->files = splaytree_delete(sc->files, ndx);
+ }
+ }
+
+ free(keys);
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/stat_cache.h b/data/lighttpd/lighttpd-1.4.53/src/stat_cache.h
new file mode 100644
index 000000000..e5fc2d748
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/stat_cache.h
@@ -0,0 +1,45 @@
+#ifndef _FILE_CACHE_H_
+#define _FILE_CACHE_H_
+#include "first.h"
+
+#include "base_decls.h"
+#include "buffer.h"
+#include "etag.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+struct stat_cache; /* declaration */
+
+typedef struct {
+ buffer *name;
+ buffer *etag;
+
+ struct stat st;
+
+ time_t stat_ts;
+
+#ifdef HAVE_LSTAT
+ char is_symlink;
+#endif
+
+#ifdef HAVE_FAM_H
+ int dir_version;
+#endif
+
+ buffer *content_type;
+} stat_cache_entry;
+
+int stat_cache_choose_engine (server *srv, const buffer *stat_cache_string);
+struct stat_cache *stat_cache_init(server *srv);
+void stat_cache_free(struct stat_cache *fc);
+
+const buffer * stat_cache_mimetype_by_ext(const connection *con, const char *name, size_t nlen);
+const buffer * stat_cache_content_type_get(server *srv, connection *con, const buffer *name, stat_cache_entry *sce);
+const buffer * stat_cache_etag_get(stat_cache_entry *sce, etag_flags_t flags);
+handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **sce);
+int stat_cache_open_rdonly_fstat (server *srv, connection *con, buffer *name, struct stat *st);
+
+int stat_cache_trigger_cleanup(server *srv);
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/status_counter.h b/data/lighttpd/lighttpd-1.4.53/src/status_counter.h
new file mode 100644
index 000000000..cdbd5c137
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/status_counter.h
@@ -0,0 +1,42 @@
+#ifndef _STATUS_COUNTER_H_
+#define _STATUS_COUNTER_H_
+#include "first.h"
+
+#include "base_decls.h"
+
+static inline
+int *status_counter_get_counter(server *srv, const char *s, size_t len);
+static inline
+void status_counter_inc(server *srv, const char *s, size_t len);
+static inline
+void status_counter_dec(server *srv, const char *s, size_t len);
+static inline
+void status_counter_set(server *srv, const char *s, size_t len, int val);
+
+/* inline status counter routines */
+
+#include "base.h" /* (srv->status) */
+#include "array.h"
+
+static inline
+int *status_counter_get_counter(server *srv, const char *s, size_t len) {
+ return array_get_int_ptr(srv->status, s, len);
+}
+
+static inline
+void status_counter_inc(server *srv, const char *s, size_t len) {
+ ++(*array_get_int_ptr(srv->status, s, len));
+}
+
+static inline
+void status_counter_dec(server *srv, const char *s, size_t len) {
+ --(*array_get_int_ptr(srv->status, s, len));
+}
+
+static inline
+void status_counter_set(server *srv, const char *s, size_t len, int val) {
+ *array_get_int_ptr(srv->status, s, len) = val;
+}
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/stream.c b/data/lighttpd/lighttpd-1.4.53/src/stream.c
new file mode 100644
index 000000000..9099bf67d
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/stream.c
@@ -0,0 +1,157 @@
+#include "first.h"
+
+#include "stream.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "sys-mmap.h"
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* don't want to block when open()ing a fifo */
+#if defined(O_NONBLOCK)
+# define FIFO_NONBLOCK O_NONBLOCK
+#else
+# define FIFO_NONBLOCK 0
+#endif
+
+int stream_open(stream *f, const buffer *fn) {
+
+#if !defined(__WIN32)
+
+ struct stat st;
+ int fd;
+
+ f->start = NULL;
+ f->size = 0;
+ f->mapped = 0;
+
+ if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY | FIFO_NONBLOCK))) {
+ return -1;
+ }
+
+ if (-1 == fstat(fd, &st)) {
+ close(fd);
+ return -1;
+ }
+
+ if (0 == st.st_size) {
+ /* empty file doesn't need a mapping */
+ close(fd);
+ return 0;
+ }
+
+ f->start = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+ if (MAP_FAILED == f->start) {
+ f->start = malloc((size_t)st.st_size);
+ if (NULL == f->start
+ || st.st_size != read(fd, f->start, (size_t)st.st_size)) {
+ free(f->start);
+ f->start = NULL;
+ close(fd);
+ return -1;
+ }
+ } else {
+ f->mapped = 1;
+ }
+
+ close(fd);
+
+ f->size = st.st_size;
+ return 0;
+
+#elif defined __WIN32
+
+ HANDLE *fh, *mh;
+ void *p;
+ LARGE_INTEGER fsize;
+
+ f->start = NULL;
+ f->size = 0;
+
+ fh = CreateFile(fn->ptr,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_READONLY,
+ NULL);
+
+ if (!fh) return -1;
+
+ if (0 != GetFileSizeEx(fh, &fsize)) {
+ CloseHandle(fh);
+ return -1;
+ }
+
+ if (0 == fsize) {
+ CloseHandle(fh);
+ return 0;
+ }
+
+ mh = CreateFileMapping( fh,
+ NULL,
+ PAGE_READONLY,
+ (sizeof(off_t) > 4) ? fsize >> 32 : 0,
+ fsize & 0xffffffff,
+ NULL);
+
+ if (!mh) {
+/*
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+*/
+ CloseHandle(fh);
+ return -1;
+ }
+
+ p = MapViewOfFile(mh,
+ FILE_MAP_READ,
+ 0,
+ 0,
+ 0);
+ CloseHandle(mh);
+ CloseHandle(fh);
+
+ f->start = p;
+ f->size = (off_t)fsize;
+ return 0;
+
+#endif
+
+}
+
+int stream_close(stream *f) {
+#ifdef HAVE_MMAP
+ if (f->start) {
+ if (f->mapped) {
+ f->mapped = 0;
+ munmap(f->start, f->size);
+ } else {
+ free(f->start);
+ }
+ }
+#elif defined(__WIN32)
+ if (f->start) UnmapViewOfFile(f->start);
+#endif
+
+ f->start = NULL;
+ f->size = 0;
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/stream.h b/data/lighttpd/lighttpd-1.4.53/src/stream.h
new file mode 100644
index 000000000..75b912093
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/stream.h
@@ -0,0 +1,16 @@
+#ifndef _STREAM_H_
+#define _STREAM_H_
+#include "first.h"
+
+#include "buffer.h"
+
+typedef struct {
+ char *start;
+ off_t size;
+ int mapped;
+} stream;
+
+int stream_open(stream *f, const buffer *fn);
+int stream_close(stream *f);
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sys-crypto.h b/data/lighttpd/lighttpd-1.4.53/src/sys-crypto.h
new file mode 100644
index 000000000..8158abac5
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sys-crypto.h
@@ -0,0 +1,19 @@
+#ifndef LI_SYS_CRYPTO_H
+#define LI_SYS_CRYPTO_H
+#include "first.h"
+
+#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
+#define USE_OPENSSL_CRYPTO
+#endif
+
+#ifdef HAVE_WOLFSSL_SSL_H
+#define USE_OPENSSL_CRYPTO
+/* wolfSSL needs to be built with ./configure --enable-lighty for lighttpd.
+ * Doing so defines OPENSSL_EXTRA and HAVE_LIGHTY in <wolfssl/options.h>, and
+ * these defines are necessary for wolfSSL headers to expose sufficient openssl
+ * compatibility layer for wolfSSL to be able to provide an openssl substitute
+ * for use by lighttpd */
+#include <wolfssl/options.h>
+#endif
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sys-endian.h b/data/lighttpd/lighttpd-1.4.53/src/sys-endian.h
new file mode 100644
index 000000000..7fa28eead
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sys-endian.h
@@ -0,0 +1,71 @@
+#ifndef LI_SYS_ENDIAN_H
+#define LI_SYS_ENDIAN_H
+#include "first.h"
+
+
+#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+
+
+/* copied from of plasma_endian.h
+ * https://github.com/gstrauss/plasma/blob/master/plasma_endian.h
+ * (used with permission from the author (gstrauss)) */
+#if defined(__BYTE_ORDER__) \
+ && ( defined(__ORDER_LITTLE_ENDIAN__) \
+ || defined(__ORDER_BIG_ENDIAN__) \
+ || defined(__ORDER_PDP_ENDIAN__) )
+ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ #define __LITTLE_ENDIAN__ 1
+ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ #define __BIG_ENDIAN__ 1
+ #endif
+#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+ #define __LITTLE_ENDIAN__ 1
+#elif !defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
+ #define __BIG_ENDIAN__ 1
+#elif defined(_WIN32) /* little endian on all current MS-supported platforms */
+ #define __LITTLE_ENDIAN__ 1
+#elif defined(__GLIBC__) || defined(__linux__)
+ #include <endian.h>
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
+ #define __LITTLE_ENDIAN__ 1
+ #elif __BYTE_ORDER == __BIG_ENDIAN
+ #define __BIG_ENDIAN__ 1
+ #endif
+#elif defined(__sun__) && defined(__SVR4)
+ #include <sys/isa_defs.h>
+ #if defined(_LITTLE_ENDIAN)
+ #define __LITTLE_ENDIAN__ 1
+ #elif defined(_BIG_ENDIAN)
+ #define __BIG_ENDIAN__ 1
+ #endif
+#elif defined(_AIX)
+ #include <sys/machine.h>
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ #define __LITTLE_ENDIAN__ 1
+ #elif BYTE_ORDER == BIG_ENDIAN
+ #define __BIG_ENDIAN__ 1
+ #endif
+#elif defined(__APPLE__) && defined(__MACH__)
+ #include <machine/endian.h>
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ #define __LITTLE_ENDIAN__ 1
+ #elif BYTE_ORDER == BIG_ENDIAN
+ #define __BIG_ENDIAN__ 1
+ #endif
+#elif defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__DragonFly__)
+ #include <machine/endian.h>
+ #if _BYTE_ORDER == _LITTLE_ENDIAN
+ #define __LITTLE_ENDIAN__ 1
+ #elif _BYTE_ORDER == _BIG_ENDIAN
+ #define __BIG_ENDIAN__ 1
+ #endif
+#else /*(else assume little endian)*/
+ #define __LITTLE_ENDIAN__ 1
+#endif
+
+
+#endif /* !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) */
+
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sys-mmap.h b/data/lighttpd/lighttpd-1.4.53/src/sys-mmap.h
new file mode 100644
index 000000000..51232ab55
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sys-mmap.h
@@ -0,0 +1,23 @@
+#ifndef LI_SYS_MMAP_H
+#define LI_SYS_MMAP_H
+#include "first.h"
+
+#if defined(HAVE_SYS_MMAN_H)
+# include <sys/mman.h>
+#else /* HAVE_SYS_MMAN_H */
+
+# define PROT_SHARED 0
+# define MAP_SHARED 0
+# define PROT_READ 0
+
+# define mmap(a, b, c, d, e, f) (-1)
+# define munmap(a, b) (-1)
+
+#endif /* HAVE_SYS_MMAN_H */
+
+/* NetBSD 1.3.x needs it; also make it available if mmap() is not present */
+#if !defined(MAP_FAILED)
+# define MAP_FAILED ((char*)-1)
+#endif
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sys-socket.h b/data/lighttpd/lighttpd-1.4.53/src/sys-socket.h
new file mode 100644
index 000000000..7851656be
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sys-socket.h
@@ -0,0 +1,45 @@
+#ifndef WIN32_SOCKET_H
+#define WIN32_SOCKET_H
+#include "first.h"
+
+#ifdef __WIN32
+
+#include <winsock2.h>
+
+#define ECONNRESET WSAECONNRESET
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ECONNABORTED WSAECONNABORTED
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#endif
+
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+/* for solaris 2.5 and NetBSD 1.3.x */
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/sys-strings.h b/data/lighttpd/lighttpd-1.4.53/src/sys-strings.h
new file mode 100644
index 000000000..d4ff0f31b
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/sys-strings.h
@@ -0,0 +1,20 @@
+#ifndef LI_SYS_STRINGS_H
+#define LI_SYS_STRINGS_H
+#include "first.h"
+
+#if defined(HAVE_STRINGS_H)
+
+#include <strings.h>
+
+#else /* HAVE_STRINGS_H */
+
+#ifdef _MSC_VER
+#define strcasecmp(s1,s2) _stricmp(s1,s2)
+#define strncasecmp(s1,s2,n) _strnicmp(s1,s2,n)
+#else
+/* ??? */
+#endif
+
+#endif /* HAVE_STRINGS_H */
+
+#endif
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_array.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_array.c
new file mode 100644
index 000000000..79d36ecda
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_array.c
@@ -0,0 +1,104 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "array.h"
+#include "buffer.h"
+
+static void test_array_get_int_ptr (void) {
+ data_integer *di;
+ int *i;
+ array *a = array_init();
+
+ i = array_get_int_ptr(a, CONST_STR_LEN("abc"));
+ assert(NULL != i);
+ *i = 4;
+ i = array_get_int_ptr(a, CONST_STR_LEN("abc"));
+ assert(NULL != i);
+ assert(*i == 4);
+ di = (data_integer *)array_get_element_klen(a, CONST_STR_LEN("does-not-exist"));
+ assert(NULL == di);
+ di = (data_integer *)array_get_element_klen(a, CONST_STR_LEN("abc"));
+ assert(NULL != di);
+ assert(di->value == 4);
+
+ array_free(a);
+}
+
+static void test_array_insert_value (void) {
+ data_string *ds;
+ array *a = array_init();
+
+ array_insert_value(a, CONST_STR_LEN("def"));
+ ds = (data_string *)a->data[0];
+ assert(NULL != ds);
+ assert(buffer_is_equal_string(ds->value, CONST_STR_LEN("def")));
+
+ array_free(a);
+}
+
+static void test_array_insert_key_value (void) {
+ data_string *ds;
+ array *a = array_init();
+
+ array_insert_key_value(a, CONST_STR_LEN("abc"), CONST_STR_LEN("alfrag"));
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("does-not-exist"));
+ assert(NULL == ds);
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("abc"));
+ assert(NULL != ds);
+ assert(buffer_is_equal_string(ds->key, CONST_STR_LEN("abc")));
+ assert(buffer_is_equal_string(ds->value, CONST_STR_LEN("alfrag")));
+
+ array_insert_key_value(a, CONST_STR_LEN("abc"), CONST_STR_LEN("hameplman"));
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("does-not-exist"));
+ assert(NULL == ds);
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("abc"));
+ assert(NULL != ds);
+ assert(buffer_is_equal_string(ds->key, CONST_STR_LEN("abc")));
+ assert(buffer_is_equal_string(ds->value, CONST_STR_LEN("alfrag, hameplman")));
+
+ array_insert_key_value(a, CONST_STR_LEN("123"), CONST_STR_LEN("alfrag"));
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("does-not-exist"));
+ assert(NULL == ds);
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("123"));
+ assert(NULL != ds);
+ assert(buffer_is_equal_string(ds->key, CONST_STR_LEN("123")));
+ assert(buffer_is_equal_string(ds->value, CONST_STR_LEN("alfrag")));
+
+ array_free(a);
+}
+
+static void test_array_set_key_value (void) {
+ data_string *ds;
+ array *a = array_init();
+
+ array_set_key_value(a, CONST_STR_LEN("abc"), CONST_STR_LEN("def"));
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("does-not-exist"));
+ assert(NULL == ds);
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("abc"));
+ assert(NULL != ds);
+ assert(buffer_is_equal_string(ds->key, CONST_STR_LEN("abc")));
+ assert(buffer_is_equal_string(ds->value, CONST_STR_LEN("def")));
+
+ array_set_key_value(a, CONST_STR_LEN("abc"), CONST_STR_LEN("ghi"));
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("does-not-exist"));
+ assert(NULL == ds);
+ ds = (data_string *)array_get_element_klen(a, CONST_STR_LEN("abc"));
+ assert(NULL != ds);
+ assert(buffer_is_equal_string(ds->key, CONST_STR_LEN("abc")));
+ assert(buffer_is_equal_string(ds->value, CONST_STR_LEN("ghi")));
+
+ array_free(a);
+}
+
+int main() {
+ test_array_get_int_ptr();
+ test_array_insert_value();
+ test_array_insert_key_value();
+ test_array_set_key_value();
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_base64.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_base64.c
new file mode 100644
index 000000000..71c9c7cac
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_base64.c
@@ -0,0 +1,60 @@
+#include "first.h"
+
+#include "base64.h"
+
+static const base64_charset encs[] = { BASE64_STANDARD, BASE64_URL };
+static buffer *check;
+
+inline
+static void check_base64 (char *out, const size_t out_sz, const char *in, const size_t in_len, const base64_charset enc) {
+ force_assert(out_sz == li_to_base64_no_padding(out, out_sz, (const unsigned char *)in, in_len, enc));
+
+ buffer_reset(check);
+ force_assert(NULL != buffer_append_base64_decode(check, out, out_sz, enc));
+ force_assert(buffer_is_equal_string(check, in, in_len));
+}
+
+static void check_all_len_0 (const base64_charset enc) {
+ check_base64(NULL, 0, "", 0, enc);
+}
+
+static void check_all_len_1 (const base64_charset enc) {
+ unsigned int c1;
+ for (c1 = 0; c1 < 256; ++c1) {
+ unsigned char in[] = { c1 };
+ char out[2] = { 0, 0 };
+ check_base64(out, sizeof(out), (char *)in, sizeof(in), enc);
+ }
+}
+
+static void check_all_len_2 (const base64_charset enc) {
+ unsigned int c1, c2;
+ for (c1 = 0; c1 < 256; ++c1) for (c2 = 0; c2 < 256; ++c2) {
+ unsigned char in[] = { c1, c2 };
+ char out[3] = { 0, 0, 0 };
+ check_base64(out, sizeof(out), (char *)in, sizeof(in), enc);
+ }
+}
+
+static void check_all_len_3 (const base64_charset enc) {
+ unsigned int c1, c2, c3;
+ for (c1 = 0; c1 < 256; c1+=255) for (c2 = 0; c2 < 256; ++c2) for (c3 = 0; c3 < 256; ++c3) {
+ unsigned char in[] = { c1, c2, c3 };
+ char out[4] = { 0, 0, 0, 0 };
+ check_base64(out, sizeof(out), (char *)in, sizeof(in), enc);
+ }
+}
+
+int main() {
+ check = buffer_init();
+
+ for (unsigned int enc = 0; enc < sizeof(encs)/sizeof(*encs); ++enc) {
+ check_all_len_0(encs[enc]);
+ check_all_len_1(encs[enc]);
+ check_all_len_2(encs[enc]);
+ check_all_len_3(encs[enc]);
+ }
+
+ buffer_free(check);
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_buffer.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_buffer.c
new file mode 100644
index 000000000..1dae0b41f
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_buffer.c
@@ -0,0 +1,157 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "buffer.h"
+
+static void run_buffer_path_simplify(buffer *psrc, buffer *pdest, const char *in, size_t in_len, const char *out, size_t out_len) {
+ buffer_copy_string_len(psrc, in, in_len);
+
+ buffer_path_simplify(pdest, psrc);
+
+ if (!buffer_is_equal_string(pdest, out, out_len)) {
+ fprintf(stderr,
+ "%s.%d: buffer_path_simplify('%s') failed: expected '%s', got '%s'\n",
+ __FILE__,
+ __LINE__,
+ in,
+ out,
+ pdest->ptr ? pdest->ptr : "");
+ fflush(stderr);
+ abort();
+ } else {
+ if (psrc != pdest) buffer_copy_buffer(psrc, pdest);
+ buffer_path_simplify(pdest, psrc);
+
+ if (!buffer_is_equal_string(pdest, out, out_len)) {
+ fprintf(stderr,
+ "%s.%d: buffer_path_simplify('%s') failed - not idempotent: expected '%s', got '%s'\n",
+ __FILE__,
+ __LINE__,
+ in,
+ out,
+ pdest->ptr ? pdest->ptr : "");
+ fflush(stderr);
+ abort();
+ }
+ }
+}
+
+static void test_buffer_path_simplify_with(buffer *psrc, buffer *pdest) {
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(""), CONST_STR_LEN(""));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/"), CONST_STR_LEN("/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("//"), CONST_STR_LEN("/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc"), CONST_STR_LEN("abc"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc//"), CONST_STR_LEN("abc/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/./xyz"), CONST_STR_LEN("abc/xyz"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/.//xyz"), CONST_STR_LEN("abc/xyz"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/../xyz"), CONST_STR_LEN("/xyz"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/./xyz"), CONST_STR_LEN("/abc/xyz"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc//./xyz"), CONST_STR_LEN("/abc/xyz"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/../xyz"), CONST_STR_LEN("/xyz"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/../xyz/."), CONST_STR_LEN("/xyz/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/../xyz/."), CONST_STR_LEN("/xyz/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/./xyz/.."), CONST_STR_LEN("abc/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/./xyz/.."), CONST_STR_LEN("/abc/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("."), CONST_STR_LEN(""));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".."), CONST_STR_LEN(""));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("..."), CONST_STR_LEN("..."));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("...."), CONST_STR_LEN("...."));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".../"), CONST_STR_LEN(".../"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("./xyz/.."), CONST_STR_LEN("/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".//xyz/.."), CONST_STR_LEN("/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/./xyz/.."), CONST_STR_LEN("/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".././xyz/.."), CONST_STR_LEN("/"));
+ run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/.././xyz/.."), CONST_STR_LEN("/"));
+}
+
+static void test_buffer_path_simplify(void) {
+ buffer *psrc = buffer_init();
+ buffer *pdest = buffer_init();
+
+ /* test with using the same buffer and with using different buffers */
+ test_buffer_path_simplify_with(psrc, psrc);
+ test_buffer_path_simplify_with(pdest, psrc);
+
+ buffer_free(psrc);
+ buffer_free(pdest);
+}
+
+static void test_buffer_to_lower_upper(void) {
+ buffer *psrc = buffer_init();
+
+ buffer_copy_string_len(psrc, CONST_STR_LEN("0123456789abcdefghijklmnopqrstuvwxyz"));
+ buffer_to_lower(psrc);
+ assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789abcdefghijklmnopqrstuvwxyz")));
+ buffer_to_upper(psrc);
+ assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")));
+ buffer_to_upper(psrc);
+ assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")));
+ buffer_to_lower(psrc);
+ assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789abcdefghijklmnopqrstuvwxyz")));
+
+ buffer_free(psrc);
+}
+
+static void test_buffer_string_space(void) {
+ buffer *b = buffer_init();
+ size_t space;
+
+ space = buffer_string_space(b);
+ assert(0 == space);
+ buffer_copy_string_len(b, CONST_STR_LEN(""));
+ space = buffer_string_space(b);
+ assert(space > 0);
+ assert(space + buffer_string_length(b) == b->size - 1);
+ buffer_commit(b, b->size - 1);
+ assert(b->used == b->size);
+ space = buffer_string_space(b);
+ assert(0 == space);
+
+ buffer_free(b);
+}
+
+static void test_buffer_append_path_len(void) {
+ buffer *b = buffer_init();
+
+ buffer_append_path_len(b, CONST_STR_LEN("a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("/a")));
+ buffer_clear(b);
+ buffer_append_path_len(b, CONST_STR_LEN("a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("/a")));
+ buffer_clear(b);
+ buffer_append_path_len(b, CONST_STR_LEN("/a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("/a")));
+ buffer_copy_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_path_len(b, CONST_STR_LEN("a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("/a")));
+ buffer_copy_string_len(b, CONST_STR_LEN("/"));
+ buffer_append_path_len(b, CONST_STR_LEN("/a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("/a")));
+ buffer_copy_string_len(b, CONST_STR_LEN("a"));
+ buffer_append_path_len(b, CONST_STR_LEN("a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("a/a")));
+ buffer_copy_string_len(b, CONST_STR_LEN("a/"));
+ buffer_append_path_len(b, CONST_STR_LEN("a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("a/a")));
+ buffer_copy_string_len(b, CONST_STR_LEN("a/"));
+ buffer_append_path_len(b, CONST_STR_LEN("/a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("a/a")));
+ buffer_copy_string_len(b, CONST_STR_LEN("/a/"));
+ buffer_append_path_len(b, CONST_STR_LEN("/a"));
+ assert(buffer_is_equal_string(b, CONST_STR_LEN("/a/a")));
+
+ buffer_free(b);
+}
+
+int main() {
+ test_buffer_path_simplify();
+ test_buffer_to_lower_upper();
+ test_buffer_string_space();
+ test_buffer_append_path_len();
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_burl.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_burl.c
new file mode 100644
index 000000000..7be9be50d
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_burl.c
@@ -0,0 +1,143 @@
+#include "first.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "burl.h"
+
+static void run_burl_normalize (buffer *psrc, buffer *ptmp, int flags, int line, const char *in, size_t in_len, const char *out, size_t out_len) {
+ int qs;
+ buffer_copy_string_len(psrc, in, in_len);
+ qs = burl_normalize(psrc, ptmp, flags);
+ if (out_len == (size_t)-2) {
+ if (-2 == qs) return;
+ fprintf(stderr,
+ "%s.%d: %s('%s') failed: expected error, got '%s'\n",
+ __FILE__, line, __func__+4, in, psrc->ptr);
+ }
+ else {
+ if (buffer_is_equal_string(psrc, out, out_len)) return;
+ fprintf(stderr,
+ "%s.%d: %s('%s') failed: expected '%s', got '%s'\n",
+ __FILE__, line, __func__+4, in, out, psrc->ptr);
+ }
+ fflush(stderr);
+ abort();
+}
+
+static void test_burl_normalize (void) {
+ buffer *psrc = buffer_init();
+ buffer *ptmp = buffer_init();
+ int flags;
+
+ flags = HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("no-slash"), CONST_STR_LEN("no-slash"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/"), CONST_STR_LEN("/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc"), CONST_STR_LEN("/abc"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc/"), CONST_STR_LEN("/abc/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc/def"), CONST_STR_LEN("/abc/def"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?"), CONST_STR_LEN("/abc?"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d"), CONST_STR_LEN("/abc?d"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d="), CONST_STR_LEN("/abc?d="));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e"), CONST_STR_LEN("/abc?d=e"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&"), CONST_STR_LEN("/abc?d=e&"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f"), CONST_STR_LEN("/abc?d=e&f"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f=g"), CONST_STR_LEN("/abc?d=e&f=g"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f=g#"), CONST_STR_LEN("/abc?d=e&f=g"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f=g#any"), CONST_STR_LEN("/abc?d=e&f=g"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2F"), CONST_STR_LEN("/%2F"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2f"), CONST_STR_LEN("/%2F"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%20"), CONST_STR_LEN("/%20"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2b"), CONST_STR_LEN("/%2B"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2B"), CONST_STR_LEN("/%2B"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%3a"), CONST_STR_LEN("/%3A"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%3A"), CONST_STR_LEN("/%3A"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/~test%20รค_"), CONST_STR_LEN("/~test%20%C3%A4_"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\375"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\376"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\377"), "", (size_t)-2);
+
+ flags = HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/"), CONST_STR_LEN("/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc"), CONST_STR_LEN("/abc"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc/"), CONST_STR_LEN("/abc/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc/def"), CONST_STR_LEN("/abc/def"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?"), CONST_STR_LEN("/abc?"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d"), CONST_STR_LEN("/abc?d"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d="), CONST_STR_LEN("/abc?d="));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e"), CONST_STR_LEN("/abc?d=e"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&"), CONST_STR_LEN("/abc?d=e&"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f"), CONST_STR_LEN("/abc?d=e&f"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f=g"), CONST_STR_LEN("/abc?d=e&f=g"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f=g#"), CONST_STR_LEN("/abc?d=e&f=g"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc?d=e&f=g#any"), CONST_STR_LEN("/abc?d=e&f=g"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2F"), CONST_STR_LEN("/%2F"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2f"), CONST_STR_LEN("/%2F"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%20"), CONST_STR_LEN("/%20"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2b"), CONST_STR_LEN("/+"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2B"), CONST_STR_LEN("/+"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%3a"), CONST_STR_LEN("/:"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%3A"), CONST_STR_LEN("/:"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/~test%20รค_"), CONST_STR_LEN("/~test%20%C3%A4_"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\375"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\376"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\377"), "", (size_t)-2);
+
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\a"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\t"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\r"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/\177"), "", (size_t)-2);
+
+ #if defined(__WIN32) || defined(__CYGWIN__)
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a\\b"), CONST_STR_LEN("/a/b"));
+ #endif
+
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=/"), CONST_STR_LEN("/a/b?c=/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=%2f"), CONST_STR_LEN("/a/b?c=/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb"), CONST_STR_LEN("/a/b"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2Fb"), CONST_STR_LEN("/a/b"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb?c=/"), CONST_STR_LEN("/a/b?c=/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb?c=%2f"), CONST_STR_LEN("/a/b?c=/"));
+ flags &= ~HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE;
+
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2Fb"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=%2f"), CONST_STR_LEN("/a/b?c=/"));
+ flags &= ~HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT;
+
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("./a/b"), CONST_STR_LEN("/a/b"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("../a/b"), CONST_STR_LEN("/a/b"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/./b"), CONST_STR_LEN("/a/b"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/../b"), CONST_STR_LEN("/b"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b/."), CONST_STR_LEN("/a/b/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b/.."), CONST_STR_LEN("/a/"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/../b/.."), CONST_STR_LEN("/"));
+ flags &= ~HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE;
+
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("./a/b"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("../a/b"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/./b"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/../b"), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b/."), "", (size_t)-2);
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b/.."), "", (size_t)-2);
+ flags &= ~HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT;
+
+ flags |= HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS;
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=d+e"), CONST_STR_LEN("/a/b?c=d+e"));
+ run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=d%20e"), CONST_STR_LEN("/a/b?c=d+e"));
+ flags &= ~HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS;
+
+ buffer_free(psrc);
+ buffer_free(ptmp);
+}
+
+int main (void) {
+ test_burl_normalize();
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_configfile.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_configfile.c
new file mode 100644
index 000000000..735a79673
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_configfile.c
@@ -0,0 +1,73 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "configfile-glue.c"
+
+const struct {
+ const char *string;
+ const char *rmtstr;
+ int rmtfamily;
+ int expect;
+} rmtmask[] = {
+ { "1.0.0.1/1", "1.0.0.1", AF_INET, 1 }
+ ,{ "254.254.254.254/1", "254.0.0.1", AF_INET, 1 }
+ ,{ "254.254.254.252/31", "254.254.254.253", AF_INET, 1 }
+ ,{ "254.254.254.253/31", "254.254.254.254", AF_INET, 0 }
+ ,{ "254.254.254.253/32", "254.254.254.254", AF_INET, 0 }
+ ,{ "254.254.254.254/32", "254.254.254.254", AF_INET, 1 }
+ #ifdef HAVE_IPV6
+ ,{ "2001::/3", "2001::1", AF_INET6, 1 }
+ ,{ "2f01::/5", "2701::1", AF_INET6, 0 }
+ ,{ "2f01::/32", "2f01::1", AF_INET6, 1 }
+ ,{ "2f01::/32", "2f02::1", AF_INET6, 0 }
+ ,{ "2001::1/127", "2001::1", AF_INET6, 1 }
+ ,{ "2001::1/127", "2001::2", AF_INET6, 0 }
+ ,{ "2001::2/128", "2001::2", AF_INET6, 1 }
+ ,{ "2001::2/128", "2001::3", AF_INET6, 0 }
+ ,{ "1.0.0.1/1", "::ffff:1.0.0.1", AF_INET6, 1 }
+ ,{ "254.254.254.254/1", "::ffff:254.0.0.1", AF_INET6, 1 }
+ ,{ "254.254.254.252/31", "::ffff:254.254.254.253", AF_INET6, 1 }
+ ,{ "254.254.254.253/31", "::ffff:254.254.254.254", AF_INET6, 0 }
+ ,{ "254.254.254.253/32", "::ffff:254.254.254.254", AF_INET6, 0 }
+ ,{ "254.254.254.254/32", "::ffff:254.254.254.254", AF_INET6, 1 }
+ ,{ "::ffff:1.0.0.1/97", "1.0.0.1", AF_INET, 1 }
+ ,{ "::ffff:254.254.254.254/97", "254.0.0.1", AF_INET, 1 }
+ ,{ "::ffff:254.254.254.252/127", "254.254.254.253", AF_INET, 1 }
+ ,{ "::ffff:254.254.254.253/127", "254.254.254.254", AF_INET, 0 }
+ ,{ "::ffff:254.254.254.253/128", "254.254.254.254", AF_INET, 0 }
+ ,{ "::ffff:254.254.254.254/128", "254.254.254.254", AF_INET, 1 }
+ #endif
+};
+
+static void test_configfile_addrbuf_eq_remote_ip_mask (void) {
+ int i, m;
+ buffer * const s = buffer_init();
+ char *slash;
+ sock_addr rmt;
+
+ for (i = 0; i < (int)(sizeof(rmtmask)/sizeof(rmtmask[0])); ++i) {
+ if (1 != sock_addr_inet_pton(&rmt, rmtmask[i].rmtstr, rmtmask[i].rmtfamily, 0)) exit(-1); /*(bad test)*/
+ buffer_copy_string(s, rmtmask[i].string);
+ slash = strchr(s->ptr,'/'); assert(slash);
+ m = config_addrbuf_eq_remote_ip_mask(NULL, s, slash, &rmt);
+ if (m != rmtmask[i].expect) {
+ fprintf(stderr, "failed assertion: %s %s %s\n",
+ rmtmask[i].string,
+ rmtmask[i].expect ? "==" : "!=",
+ rmtmask[i].rmtstr);
+ exit(-1);
+ }
+ }
+
+ buffer_free(s);
+}
+
+int main (void) {
+ test_configfile_addrbuf_eq_remote_ip_mask();
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_keyvalue.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_keyvalue.c
new file mode 100644
index 000000000..83dac9236
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_keyvalue.c
@@ -0,0 +1,124 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> /* STDERR_FILENO */
+
+#include "keyvalue.c"
+
+#ifdef HAVE_PCRE_H
+static pcre_keyvalue_buffer * test_keyvalue_test_kvb_init (void) {
+ pcre_keyvalue_buffer *kvb = pcre_keyvalue_buffer_init();
+ buffer *k = buffer_init();
+ buffer *v = buffer_init();
+ server srv;
+
+ memset(&srv, 0, sizeof(srv));
+ srv.errorlog_fd = STDERR_FILENO;
+ srv.errorlog_mode = ERRORLOG_FD;
+ srv.errorlog_buf = buffer_init();
+
+ buffer_copy_string_len(k, CONST_STR_LEN("^/foo($|\\?.+)"));
+ buffer_copy_string_len(v, CONST_STR_LEN("/foo/$1"));
+ assert(0 == pcre_keyvalue_buffer_append(&srv, kvb, k, v));
+ buffer_copy_string_len(k, CONST_STR_LEN("^/bar(?:$|\\?(.+))"));
+ buffer_copy_string_len(v, CONST_STR_LEN("/?bar&$1"));
+ assert(0 == pcre_keyvalue_buffer_append(&srv, kvb, k, v));
+ buffer_copy_string_len(k, CONST_STR_LEN("^/redirect(?:\\?(.*))?$"));
+ buffer_copy_string_len(v, CONST_STR_LEN("/?seg=%1&$1"));
+ assert(0 == pcre_keyvalue_buffer_append(&srv, kvb, k, v));
+ buffer_copy_string_len(k, CONST_STR_LEN("^(/[^?]*)(?:\\?(.*))?$"));
+ buffer_copy_string_len(v, CONST_STR_LEN("/?file=$1&$2"));
+ assert(0 == pcre_keyvalue_buffer_append(&srv, kvb, k, v));
+
+ buffer_free(k);
+ buffer_free(v);
+ buffer_free(srv.errorlog_buf);
+
+ return kvb;
+}
+
+static void test_keyvalue_pcre_keyvalue_buffer_process (void) {
+ pcre_keyvalue_buffer *kvb = test_keyvalue_test_kvb_init();
+ buffer *url = buffer_init();
+ buffer *result = buffer_init();
+ struct burl_parts_t burl;
+ cond_cache_t cache;
+ pcre_keyvalue_ctx ctx;
+ handler_t rc;
+
+ ctx.burl = &burl;
+ burl.scheme = buffer_init();
+ burl.authority = buffer_init();
+ burl.port = 80;
+ burl.path = buffer_init();
+ burl.query = buffer_init();
+ buffer_copy_string_len(burl.scheme, CONST_STR_LEN("http"));
+ buffer_copy_string_len(burl.authority, CONST_STR_LEN("www.example.com"));
+ /* model outer conditional match of $HTTP["host"] =~ "^(www).example.com$" */
+ ctx.cache = &cache;
+ memset(&cache, 0, sizeof(cache));
+ cache.patterncount = 2;
+ cache.comp_value = burl.authority;
+ cache.matches[0] = 0;
+ cache.matches[1] = 15;
+ cache.matches[2] = 0;
+ cache.matches[3] = 3;
+
+ /* converted from prior sparse tests/mod-redirect.t and tests/mod-rewrite.t
+ * (real-world use should prefer ${url.path} and ${qsa} in substitutions)
+ */
+
+ buffer_copy_string_len(url, CONST_STR_LEN("/foo"));
+ buffer_copy_string_len(burl.path, CONST_STR_LEN("/foo"));
+ buffer_clear(burl.query);
+ rc = pcre_keyvalue_buffer_process(kvb, &ctx, url, result);
+ assert(HANDLER_FINISHED == rc);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/foo/")));
+
+ buffer_copy_string_len(url, CONST_STR_LEN("/foo?a=b"));
+ buffer_copy_string_len(burl.path, CONST_STR_LEN("/foo"));
+ buffer_copy_string_len(burl.query, CONST_STR_LEN("a=b"));
+ rc = pcre_keyvalue_buffer_process(kvb, &ctx, url, result);
+ assert(HANDLER_FINISHED == rc);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/foo/?a=b")));
+
+ buffer_copy_string_len(url, CONST_STR_LEN("/bar?a=b"));
+ buffer_copy_string_len(burl.path, CONST_STR_LEN("/bar"));
+ buffer_copy_string_len(burl.query, CONST_STR_LEN("a=b"));
+ rc = pcre_keyvalue_buffer_process(kvb, &ctx, url, result);
+ assert(HANDLER_FINISHED == rc);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/?bar&a=b")));
+
+ buffer_copy_string_len(url, CONST_STR_LEN("/nofile?a=b"));
+ buffer_copy_string_len(burl.path, CONST_STR_LEN("/nofile"));
+ buffer_copy_string_len(burl.query, CONST_STR_LEN("a=b"));
+ rc = pcre_keyvalue_buffer_process(kvb, &ctx, url, result);
+ assert(HANDLER_FINISHED == rc);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/?file=/nofile&a=b")));
+
+ buffer_copy_string_len(url, CONST_STR_LEN("/redirect?a=b"));
+ buffer_copy_string_len(burl.path, CONST_STR_LEN("/redirect"));
+ buffer_copy_string_len(burl.query, CONST_STR_LEN("a=b"));
+ rc = pcre_keyvalue_buffer_process(kvb, &ctx, url, result);
+ assert(HANDLER_FINISHED == rc);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/?seg=www&a=b")));
+
+ buffer_free(url);
+ buffer_free(result);
+ buffer_free(burl.scheme);
+ buffer_free(burl.authority);
+ buffer_free(burl.path);
+ buffer_free(burl.query);
+ pcre_keyvalue_buffer_free(kvb);
+}
+#endif
+
+int main (void) {
+ #ifdef HAVE_PCRE_H
+ test_keyvalue_pcre_keyvalue_buffer_process();
+ #endif
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_access.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_access.c
new file mode 100644
index 000000000..820cee4c7
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_access.c
@@ -0,0 +1,55 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mod_access.c"
+
+static void test_mod_access_check(void) {
+ array *allow = array_init();
+ array *deny = array_init();
+ buffer *urlpath = buffer_init();
+ int lc = 0;
+
+ /* empty allow and deny lists */
+ buffer_copy_string_len(urlpath, CONST_STR_LEN("/"));
+ assert(1 == mod_access_check(allow, deny, urlpath, lc));
+
+ array_insert_value(deny, CONST_STR_LEN("~"));
+ array_insert_value(deny, CONST_STR_LEN(".inc"));
+
+ /* deny */
+ buffer_copy_string_len(urlpath, CONST_STR_LEN("/index.html~"));
+ assert(0 == mod_access_check(allow, deny, urlpath, lc));
+ lc = 1;
+ buffer_copy_string_len(urlpath, CONST_STR_LEN("/index.INC"));
+ assert(0 == mod_access_check(allow, deny, urlpath, lc));
+ lc = 0;
+
+ array_insert_value(allow, CONST_STR_LEN(".txt"));
+ array_insert_value(deny, CONST_STR_LEN(".txt"));/* allow takes precedence */
+
+ /* explicitly allowed */
+ buffer_copy_string_len(urlpath, CONST_STR_LEN("/ssi-include.txt"));
+ assert(1 == mod_access_check(allow, deny, urlpath, lc));
+ lc = 1;
+ buffer_copy_string_len(urlpath, CONST_STR_LEN("/ssi-include.TXT"));
+ assert(1 == mod_access_check(allow, deny, urlpath, lc));
+ lc = 0;
+
+ /* allow not empty and urlpath not explicitly allowed */
+ buffer_copy_string_len(urlpath, CONST_STR_LEN("/cgi.pl"));
+ assert(0 == mod_access_check(allow, deny, urlpath, lc));
+
+ array_free(allow);
+ array_free(deny);
+ buffer_free(urlpath);
+}
+
+int main (void) {
+ test_mod_access_check();
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_evhost.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_evhost.c
new file mode 100644
index 000000000..0600479e8
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_evhost.c
@@ -0,0 +1,80 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mod_evhost.c"
+
+static plugin_config * test_mod_evhost_plugin_config_init(void) {
+ plugin_config *s = calloc(1, sizeof(plugin_config));
+ s->path_pieces_raw = buffer_init();
+ s->path_pieces = NULL;
+ s->len = 0;
+ return s;
+}
+
+static void test_mod_evhost_plugin_config_free(plugin_config *s) {
+ buffer_free(s->path_pieces_raw);
+ for (size_t i = 0; i < s->len; ++i) buffer_free(s->path_pieces[i]);
+ free(s->path_pieces);
+ free(s);
+}
+
+static void test_mod_evhost_build_doc_root_path(void) {
+ buffer *authority = buffer_init_string("host.example.org");
+ buffer *b = buffer_init();
+ array *a = array_init();
+ struct ttt {
+ const char *pattern;
+ size_t plen;
+ const char *expect;
+ size_t elen;
+ } tt[] = {
+ /* correct pattern not using dot notation */
+ { CONST_STR_LEN("/web/%3/"),
+ CONST_STR_LEN("/web/host/") }
+ /* correct pattern using dot notation */
+ ,{ CONST_STR_LEN("/web/%{3.1}/%{3.2}/%3/"),
+ CONST_STR_LEN("/web/h/o/host/") }
+ /* other pattern 1 */
+ ,{ CONST_STR_LEN("/web/%{3.0}/"),
+ CONST_STR_LEN("/web/host/") }
+ /* other pattern 2 */
+ ,{ CONST_STR_LEN("/web/%3.\1/"),
+ CONST_STR_LEN("/web/host.\1/") }
+ };
+
+ for (size_t i = 0; i < sizeof(tt)/sizeof(tt[0]); ++i) {
+ struct ttt *t = tt+i;
+ plugin_config *s = test_mod_evhost_plugin_config_init();
+ buffer_copy_string_len(s->path_pieces_raw, t->pattern, t->plen);
+ assert(0 == mod_evhost_parse_pattern(s));
+ mod_evhost_build_doc_root_path(b, a, authority, s->path_pieces, s->len);
+ assert(buffer_is_equal_string(b, t->expect, t->elen));
+ test_mod_evhost_plugin_config_free(s);
+ }
+
+ buffer_free(authority);
+ buffer_free(b);
+ array_free(a);
+}
+
+int main (void) {
+ test_mod_evhost_build_doc_root_path();
+
+ return 0;
+}
+
+/*
+ * stub functions
+ */
+
+handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **sce) {
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(name);
+ UNUSED(sce);
+ return HANDLER_GO_ON;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_simple_vhost.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_simple_vhost.c
new file mode 100644
index 000000000..55af4c287
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_mod_simple_vhost.c
@@ -0,0 +1,53 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mod_simple_vhost.c"
+
+static void test_mod_simple_vhost_build_doc_root_path(void) {
+ buffer *sroot = buffer_init();
+ buffer *host = buffer_init();
+ buffer *droot = buffer_init();
+ buffer *result= buffer_init();
+
+ buffer_copy_string_len(sroot, CONST_STR_LEN("/sroot/a/"));
+ buffer_copy_string_len(host, CONST_STR_LEN("www.example.org"));
+ buffer_copy_string_len(droot, CONST_STR_LEN("/droot/b/"));
+ build_doc_root_path(result, sroot, host, droot);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/sroot/a/www.example.org/droot/b/")));
+
+ buffer_copy_string_len(host, CONST_STR_LEN("www.example.org:8080"));
+ build_doc_root_path(result, sroot, host, droot);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/sroot/a/www.example.org/droot/b/")));
+
+ buffer_copy_string_len(droot, CONST_STR_LEN(""));
+ build_doc_root_path(result, sroot, host, droot);
+ assert(buffer_is_equal_string(result, CONST_STR_LEN("/sroot/a/www.example.org/")));
+
+ buffer_free(sroot);
+ buffer_free(host);
+ buffer_free(droot);
+ buffer_free(result);
+}
+
+int main (void) {
+ test_mod_simple_vhost_build_doc_root_path();
+
+ return 0;
+}
+
+/*
+ * stub functions
+ */
+
+handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **sce) {
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(name);
+ UNUSED(sce);
+ return HANDLER_GO_ON;
+}
+
diff --git a/data/lighttpd/lighttpd-1.4.53/src/t/test_request.c b/data/lighttpd/lighttpd-1.4.53/src/t/test_request.c
new file mode 100644
index 000000000..e14647b4d
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/t/test_request.c
@@ -0,0 +1,490 @@
+#include "first.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "request.h"
+#include "base.h"
+#include "burl.h"
+
+static void test_request_connection_reset(connection *con)
+{
+ con->request.http_method = HTTP_METHOD_UNSET;
+ con->request.http_version = HTTP_VERSION_UNSET;
+ con->request.http_host = NULL;
+ con->request.htags = 0;
+ con->request.content_length = 0;
+ con->header_len = 0;
+ con->http_status = 0;
+ buffer_reset(con->proto);
+ buffer_reset(con->parse_request);
+ buffer_reset(con->request.request);
+ buffer_reset(con->request.request_line);
+ buffer_reset(con->request.orig_uri);
+ buffer_reset(con->request.uri);
+ array_reset(con->request.headers);
+}
+
+static void run_http_request_parse(server *srv, connection *con, int line, int status, const char *desc, const char *req, size_t reqlen)
+{
+ test_request_connection_reset(con);
+ buffer_copy_string_len(con->request.request, req, reqlen);
+ http_request_parse(srv, con);
+ if (con->http_status != status) {
+ fprintf(stderr,
+ "%s.%d: %s() failed: expected '%d', got '%d' for test %s\n",
+ __FILE__, line, "http_request_parse", status, con->http_status,
+ desc);
+ fflush(stderr);
+ abort();
+ }
+}
+
+static void test_request_http_request_parse(server *srv, connection *con)
+{
+ data_string *ds;
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "hostname",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: www.example.org\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("www.example.org")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "IPv4 address",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: 127.0.0.1\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("127.0.0.1")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "IPv6 address",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: [::1]\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("[::1]")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "hostname + port",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: www.example.org:80\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("www.example.org")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "IPv4 address + port",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: 127.0.0.1:80\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("127.0.0.1")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "IPv6 address + port",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: [::1]:80\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("[::1]")));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "directory traversal",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: ../123.org\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "leading and trailing dot",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: .jsdh.sfdg.sdfg.\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "trailing dot is ok",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: jsdh.sfdg.sdfg.\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("jsdh.sfdg.sdfg")));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "leading dot",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: .jsdh.sfdg.sdfg\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "two dots",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: jsdh..sfdg.sdfg\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "broken port-number",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: jsdh.sfdg.sdfg:asd\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "negative port-number",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: jsdh.sfdg.sdfg:-1\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "port given but host missing",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: :80\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "port and host are broken",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: .jsdh.sfdg.:sdfg.\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "allowed characters in host-name",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: a.b-c.d123\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("a.b-c.d123")));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "leading dash",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: -a.c\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "dot only",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: .\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "broken IPv4 address - non-digit",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: a192.168.2.10:1234\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "broken IPv4 address - too short",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: 192.168.2:1234\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "IPv6 address + SQL injection",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: [::1]' UNION SELECT '/\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "IPv6 address + path traversal",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: [::1]/../../../\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "negative Content-Length",
+ CONST_STR_LEN("POST /12345.txt HTTP/1.0\r\n"
+ "Content-Length: -2\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 411,
+ "Content-Length is empty",
+ CONST_STR_LEN("POST /12345.txt HTTP/1.0\r\n"
+ "Host: 123.example.org\r\n"
+ "Content-Length:\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "Host missing",
+ CONST_STR_LEN("GET / HTTP/1.1\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "empty request-URI",
+ CONST_STR_LEN("GET HTTP/1.0\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "#1232 - duplicate headers with line-wrapping",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Location: foo\r\n"
+ "Location: foobar\r\n"
+ " baz\r\n"
+ "\r\n"));
+ ds = (data_string *)
+ array_get_element_klen(con->request.headers, CONST_STR_LEN("Location"));
+ assert(ds
+ && buffer_is_equal_string(ds->value,
+ CONST_STR_LEN("foo, foobar baz")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "#1232 - duplicate headers with line-wrapping - test 2",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Location: \r\n"
+ "Location: foobar\r\n"
+ " baz\r\n"
+ "\r\n"));
+ ds = (data_string *)
+ array_get_element_klen(con->request.headers, CONST_STR_LEN("Location"));
+ assert(ds
+ && buffer_is_equal_string(ds->value, CONST_STR_LEN("foobar baz")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "#1232 - duplicate headers with line-wrapping - test 3",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "A: \r\n"
+ "Location: foobar\r\n"
+ " baz\r\n"
+ "\r\n"));
+ ds = (data_string *)
+ array_get_element_klen(con->request.headers, CONST_STR_LEN("Location"));
+ assert(ds
+ && buffer_is_equal_string(ds->value, CONST_STR_LEN("foobar baz")));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "missing protocol",
+ CONST_STR_LEN("GET /\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "zeros in protocol version",
+ CONST_STR_LEN("GET / HTTP/01.01\r\n"
+ "Host: foo\r\n"
+ "\r\n"));
+ assert(con->request.http_version == HTTP_VERSION_1_1);
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "missing major version",
+ CONST_STR_LEN("GET / HTTP/.01\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "missing minor version",
+ CONST_STR_LEN("GET / HTTP/01.\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "strings as version",
+ CONST_STR_LEN("GET / HTTP/a.b\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "missing protocol + unknown method",
+ CONST_STR_LEN("BC /\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "missing protocol + unknown method + missing URI",
+ CONST_STR_LEN("ABC\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 501,
+ "unknown method",
+ CONST_STR_LEN("ABC / HTTP/1.0\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 505,
+ "unknown protocol",
+ CONST_STR_LEN("GET / HTTP/1.3\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "absolute URI",
+ CONST_STR_LEN("GET http://www.example.org/ HTTP/1.0\r\n"
+ "\r\n"));
+ assert(buffer_is_equal_string(con->request.http_host,
+ CONST_STR_LEN("www.example.org")));
+ assert(buffer_is_equal_string(con->request.uri,
+ CONST_STR_LEN("/")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "whitespace after key",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "ABC : foo\r\n"
+ "\r\n"));
+ ds = (data_string *)
+ array_get_element_klen(con->request.headers, CONST_STR_LEN("ABC"));
+ assert(ds && buffer_is_equal_string(ds->value, CONST_STR_LEN("foo")));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "whitespace within key",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "ABC a: foo\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "no whitespace",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "ABC:foo\r\n"
+ "\r\n"));
+ ds = (data_string *)
+ array_get_element_klen(con->request.headers, CONST_STR_LEN("ABC"));
+ assert(ds && buffer_is_equal_string(ds->value, CONST_STR_LEN("foo")));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "line-folding",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "ABC:foo\r\n"
+ " bc\r\n"
+ "\r\n"));
+ ds = (data_string *)
+ array_get_element_klen(con->request.headers, CONST_STR_LEN("ABC"));
+ assert(ds && buffer_is_equal_string(ds->value, CONST_STR_LEN("foo bc")));
+
+ run_http_request_parse(srv, con, __LINE__, 411,
+ "POST request, no Content-Length",
+ CONST_STR_LEN("POST / HTTP/1.0\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "Duplicate Host headers, Bug #25",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: www.example.org\r\n"
+ "Host: 123.example.org\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "Duplicate Content-Length headers",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Content-Length: 5\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "Duplicate Content-Type headers",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Content-Type: 5\r\n"
+ "Content-Type: 4\r\n"
+ "\r\n"));
+
+ /* (not actually testing Range here anymore; parsing deferred until use) */
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers (get appended)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=5-6\r\n"
+ "Range: bytes=5-9\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (a)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=0\r\n"
+ "Range: bytes=5-9\r\n"
+ "\r\n"));
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (b)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=5-9\r\n"
+ "Range: bytes=0\r\n"
+ "\r\n"));
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (c)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: 0\r\n"
+ "Range: bytes=5-9\r\n"
+ "\r\n"));
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (d)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=5-9\r\n"
+ "Range: 0\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate If-None-Match headers",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "If-None-Match: 5\r\n"
+ "If-None-Match: 4\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "Duplicate If-Modified-Since headers",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "If-Modified-Since: 5\r\n"
+ "If-Modified-Since: 4\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "GET with Content-Length",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "1234"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "HEAD with Content-Length",
+ CONST_STR_LEN("HEAD / HTTP/1.0\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "1234"));
+
+ run_http_request_parse(srv, con, __LINE__, 400,
+ "invalid chars in Header values (bug #1286)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "If-Modified-Since: \0\r\n"
+ "\r\n"));
+
+ /* (quick check that none of above tests were left in a state
+ * which resulted in subsequent tests returning 400 for other
+ * reasons) */
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "valid",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Host: www.example.org\r\n"
+ "\r\n"));
+}
+
+int main (void)
+{
+ server srv;
+ connection con;
+
+ memset(&srv, 0, sizeof(server));
+ srv.errorlog_fd = -1; /* use 2 for STDERR_FILENO from unistd.h */
+ srv.errorlog_mode = ERRORLOG_FD;
+ srv.errorlog_buf = buffer_init();
+ srv.split_vals = array_init();
+
+ memset(&con, 0, sizeof(connection));
+ con.proto = buffer_init();
+ con.parse_request = buffer_init();
+ con.request.request = buffer_init();
+ con.request.request_line = buffer_init();
+ con.request.orig_uri = buffer_init();
+ con.request.uri = buffer_init();
+ con.request.headers = array_init();
+ con.conf.allow_http11 = 1;
+ con.conf.http_parseopts = HTTP_PARSEOPT_HEADER_STRICT
+ | HTTP_PARSEOPT_HOST_STRICT
+ | HTTP_PARSEOPT_HOST_NORMALIZE;
+
+ test_request_http_request_parse(&srv, &con);
+
+ buffer_free(con.proto);
+ buffer_free(con.parse_request);
+ buffer_free(con.request.request);
+ buffer_free(con.request.request_line);
+ buffer_free(con.request.orig_uri);
+ buffer_free(con.request.uri);
+ array_free(con.request.headers);
+
+ array_free(srv.split_vals);
+ buffer_free(srv.errorlog_buf);
+
+ return 0;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/vector.c b/data/lighttpd/lighttpd-1.4.53/src/vector.c
new file mode 100644
index 000000000..29b707890
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/vector.c
@@ -0,0 +1,23 @@
+#include "first.h"
+
+#include "vector.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void vector_free(void *data) { free(data); }
+
+void *vector_malloc(size_t sz) { return malloc(sz); }
+
+void *vector_realloc(void *data, size_t elem_size, size_t size, size_t used) {
+ const size_t total_size = elem_size * size;
+ const size_t used_size = elem_size * used;
+ force_assert(size <= SIZE_MAX / elem_size);
+ data = realloc(data, total_size);
+ force_assert(NULL != data);
+
+ /* clear new memory */
+ memset(((char*)data) + used_size, 0, total_size - used_size);
+
+ return data;
+}
diff --git a/data/lighttpd/lighttpd-1.4.53/src/vector.h b/data/lighttpd/lighttpd-1.4.53/src/vector.h
new file mode 100644
index 000000000..d3587936c
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/vector.h
@@ -0,0 +1,68 @@
+#ifndef LI_VECTOR_H
+#define LI_VECTOR_H
+#include "first.h"
+
+#include "buffer.h" /* force_assert() */
+
+static inline size_t vector_align_size(size_t s) {
+ size_t a = (s + 16) & ((size_t)~15);
+ return (a < s) ? s : a;
+}
+
+void vector_free(void *data);
+void *vector_malloc(size_t sz);
+void *vector_realloc(void *data, size_t elem_size, size_t size, size_t used);
+
+#define DEFINE_TYPED_VECTOR(name, entry, release) \
+ typedef struct vector_ ## name { \
+ entry* data; \
+ size_t used; \
+ size_t size; \
+ } vector_ ## name; \
+ static inline void vector_ ## name ## _init(vector_ ## name *v) { \
+ v->data = NULL; \
+ v->used = v->size = 0; \
+ } \
+ static inline vector_ ## name *vector_ ## name ## _alloc() { \
+ vector_ ## name *v = vector_malloc(sizeof(*v)); \
+ force_assert(NULL != v); \
+ vector_ ## name ## _init(v); \
+ return v; \
+ } \
+ static inline void vector_ ## name ## _clear(vector_ ## name *v) { \
+ size_t ndx; \
+ vector_ ## name vcopy = *v; \
+ vector_ ## name ## _init(v); \
+ if (release) for (ndx = 0; ndx < vcopy.used; ++ndx) release(vcopy.data[ndx]); \
+ vector_free(vcopy.data); \
+ } \
+ static inline void vector_ ## name ## _free(vector_ ## name *v) { \
+ if (NULL != v) { \
+ vector_ ## name ## _clear(v); \
+ vector_free(v); \
+ } \
+ } \
+ static inline void vector_ ## name ## _reserve(vector_ ## name *v, size_t p) { \
+ force_assert(v->used < SIZE_MAX - p); \
+ if (v->size < v->used + p) { \
+ v->size = vector_align_size(v->used + p); \
+ v->data = vector_realloc(v->data, sizeof(entry), v->size, v->used); \
+ } \
+ } \
+ static inline void vector_ ## name ## _push(vector_ ## name *v, entry e) { \
+ vector_ ## name ## _reserve(v, 1); \
+ v->data[v->used++] = e; \
+ } \
+ static inline entry vector_ ## name ## _pop(vector_ ## name *v) { \
+ force_assert(v->used > 0); \
+ return v->data[--v->used]; \
+ } \
+ struct vector_ ## name /* expect trailing semicolon */ \
+ /* end of DEFINE_TYPED_VECTOR */
+
+#define DEFINE_TYPED_VECTOR_NO_RELEASE(name, entry) \
+ DEFINE_TYPED_VECTOR(name, entry, ((void(*)(entry)) NULL)) \
+ /* end of DEFINE_TYPED_VECTOR_NO_RELEASE */
+
+
+#endif