summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.cvsignore17
-rw-r--r--src/CMakeLists.txt678
-rw-r--r--src/Makefile.am365
-rw-r--r--src/XGetopt.h23
-rw-r--r--src/ajp13.h136
-rw-r--r--src/array-static.h38
-rw-r--r--src/array.c398
-rw-r--r--src/array.h160
-rw-r--r--src/base.h731
-rw-r--r--src/bitset.c69
-rw-r--r--src/bitset.h21
-rw-r--r--src/buffer.c1169
-rw-r--r--src/buffer.h166
-rw-r--r--src/chunk.c718
-rw-r--r--src/chunk.h94
-rw-r--r--src/config.h.cmake153
-rw-r--r--src/configfile-glue.c675
-rw-r--r--src/configfile.c1376
-rw-r--r--src/configfile.h30
-rw-r--r--src/configparser.y571
-rw-r--r--src/connections-glue.c51
-rw-r--r--src/connections.c1599
-rw-r--r--src/connections.h20
-rw-r--r--src/crc32.c82
-rw-r--r--src/crc32.h25
-rw-r--r--src/data_array.c65
-rw-r--r--src/data_config.c136
-rw-r--r--src/data_count.c68
-rw-r--r--src/data_integer.c65
-rw-r--r--src/data_string.c121
-rw-r--r--src/etag.c53
-rw-r--r--src/etag.h16
-rw-r--r--src/fastcgi.h136
-rw-r--r--src/fcgi-stat-accel.c118
-rw-r--r--src/fdevent.c390
-rw-r--r--src/fdevent.h280
-rw-r--r--src/fdevent_freebsd_kqueue.c221
-rw-r--r--src/fdevent_linux_rtsig.c235
-rw-r--r--src/fdevent_linux_sysepoll.c147
-rw-r--r--src/fdevent_poll.c153
-rw-r--r--src/fdevent_select.c166
-rw-r--r--src/fdevent_solaris_devpoll.c181
-rw-r--r--src/filter.c182
-rw-r--r--src/filter.h42
-rw-r--r--src/http-header-glue.c384
-rw-r--r--src/http_auth.c1252
-rw-r--r--src/http_auth.h81
-rw-r--r--src/http_auth_digest.c25
-rw-r--r--src/http_auth_digest.h24
-rw-r--r--src/http_parser.h11
-rw-r--r--src/http_req.c323
-rw-r--r--src/http_req.h37
-rw-r--r--src/http_req_parser.y160
-rw-r--r--src/http_req_range.c188
-rw-r--r--src/http_req_range.h37
-rw-r--r--src/http_req_range_parser.y76
-rw-r--r--src/http_req_range_test.c72
-rw-r--r--src/http_req_test.c141
-rw-r--r--src/http_resp.c303
-rw-r--r--src/http_resp.h40
-rw-r--r--src/http_resp_parser.y143
-rw-r--r--src/http_resp_test.c141
-rw-r--r--src/inet_ntop_cache.c53
-rw-r--r--src/inet_ntop_cache.h7
-rw-r--r--src/iosocket.c44
-rw-r--r--src/iosocket.h50
-rw-r--r--src/joblist.c77
-rw-r--r--src/joblist.h19
-rw-r--r--src/keyvalue.c390
-rw-r--r--src/keyvalue.h112
-rw-r--r--src/lemon.c4400
-rw-r--r--src/lempar.c693
-rw-r--r--src/log.c457
-rw-r--r--src/log.h43
-rw-r--r--src/md5.c355
-rw-r--r--src/md5.h57
-rw-r--r--src/mod_access.c230
-rw-r--r--src/mod_accesslog.c911
-rw-r--r--src/mod_alias.c204
-rw-r--r--src/mod_auth.c672
-rw-r--r--src/mod_auth.h0
-rw-r--r--src/mod_cgi.c1312
-rw-r--r--src/mod_chunked.c381
-rw-r--r--src/mod_compress.c848
-rw-r--r--src/mod_deflate.c1408
-rw-r--r--src/mod_dirlisting.c957
-rw-r--r--src/mod_evasive.c200
-rw-r--r--src/mod_evhost.c347
-rw-r--r--src/mod_expire.c375
-rw-r--r--src/mod_flv_streaming.c322
-rw-r--r--src/mod_indexfile.c254
-rw-r--r--src/mod_magnet.c984
-rw-r--r--src/mod_magnet_cache.c137
-rw-r--r--src/mod_magnet_cache.h33
-rw-r--r--src/mod_mysql_vhost.c309
-rw-r--r--src/mod_postgresql_vhost.c371
-rw-r--r--src/mod_proxy_backend_ajp13.c836
-rw-r--r--src/mod_proxy_backend_fastcgi.c819
-rw-r--r--src/mod_proxy_backend_http.c423
-rw-r--r--src/mod_proxy_backend_scgi.c475
-rw-r--r--src/mod_proxy_core.c2624
-rw-r--r--src/mod_proxy_core.h122
-rw-r--r--src/mod_proxy_core_address.c210
-rw-r--r--src/mod_proxy_core_address.h36
-rw-r--r--src/mod_proxy_core_backend.c50
-rw-r--r--src/mod_proxy_core_backend.h74
-rw-r--r--src/mod_proxy_core_backlog.c109
-rw-r--r--src/mod_proxy_core_backlog.h61
-rw-r--r--src/mod_proxy_core_pool.c141
-rw-r--r--src/mod_proxy_core_pool.h68
-rw-r--r--src/mod_proxy_core_protocol.c66
-rw-r--r--src/mod_proxy_core_protocol.h40
-rw-r--r--src/mod_proxy_core_rewrites.c127
-rw-r--r--src/mod_proxy_core_rewrites.h40
-rw-r--r--src/mod_redirect.c229
-rw-r--r--src/mod_rewrite.c337
-rw-r--r--src/mod_rrdtool.c501
-rw-r--r--src/mod_secure_download.c351
-rw-r--r--src/mod_setenv.c254
-rw-r--r--src/mod_simple_vhost.c282
-rw-r--r--src/mod_skeleton.c207
-rw-r--r--src/mod_sql_vhost_core.c384
-rw-r--r--src/mod_sql_vhost_core.h60
-rw-r--r--src/mod_ssi.c1095
-rw-r--r--src/mod_ssi.h44
-rw-r--r--src/mod_ssi_expr.c325
-rw-r--r--src/mod_ssi_expr.h31
-rw-r--r--src/mod_ssi_exprparser.y122
-rw-r--r--src/mod_staticfile.c552
-rw-r--r--src/mod_status.c893
-rw-r--r--src/mod_trigger_b4_dl.c589
-rw-r--r--src/mod_uploadprogress.c638
-rw-r--r--src/mod_userdir.c325
-rw-r--r--src/mod_usertrack.c277
-rw-r--r--src/mod_webdav.c2688
-rw-r--r--src/network.c891
-rw-r--r--src/network.h16
-rw-r--r--src/network_backends.h59
-rw-r--r--src/network_freebsd_sendfile.c157
-rw-r--r--src/network_gthread_aio.c481
-rw-r--r--src/network_gthread_freebsd_sendfile.c265
-rw-r--r--src/network_gthread_sendfile.c272
-rw-r--r--src/network_linux_aio.c382
-rw-r--r--src/network_linux_sendfile.c192
-rw-r--r--src/network_openssl.c402
-rw-r--r--src/network_posix_aio.c467
-rw-r--r--src/network_solaris_sendfilev.c149
-rw-r--r--src/network_win32_send.c265
-rw-r--r--src/network_write.c227
-rw-r--r--src/network_writev.c356
-rw-r--r--src/plugin.c592
-rw-r--r--src/plugin.h114
-rw-r--r--src/proc_open.c395
-rw-r--r--src/proc_open.h25
-rw-r--r--src/request.c599
-rw-r--r--src/request.h9
-rw-r--r--src/response.c794
-rw-r--r--src/response.h22
-rw-r--r--src/server.c1792
-rw-r--r--src/server.h20
-rw-r--r--src/settings.h183
-rw-r--r--src/splaytree.c210
-rw-r--r--src/splaytree.h24
-rw-r--r--src/stat_cache.c563
-rw-r--r--src/stat_cache.h14
-rw-r--r--src/status_counter.c75
-rw-r--r--src/status_counter.h20
-rw-r--r--src/stream.c107
-rw-r--r--src/stream.h14
-rw-r--r--src/sys-files.c66
-rw-r--r--src/sys-files.h87
-rw-r--r--src/sys-mmap.h26
-rw-r--r--src/sys-process.h17
-rw-r--r--src/sys-socket.c76
-rw-r--r--src/sys-socket.h73
-rw-r--r--src/sys-strings.h46
-rw-r--r--src/timing.c11
-rw-r--r--src/timing.h12
-rw-r--r--src/valgrind/Makefile.am1
-rw-r--r--src/valgrind/valgrind.h469
-rw-r--r--src/xgetopt.c222
181 files changed, 0 insertions, 60354 deletions
diff --git a/src/.cvsignore b/src/.cvsignore
deleted file mode 100644
index 55061b0a..00000000
--- a/src/.cvsignore
+++ /dev/null
@@ -1,17 +0,0 @@
-Makefile.in
-Makefile
-spawn-fcgi
-chunk
-lemon
-lighttpd
-*.loT
-*.exe
-.deps
-.libs
-array
-proc_open
-regex
-mod_ssi_exprparser.c
-mod_ssi_exprparser.h
-configparser.c
-configparser.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index 1323272d..00000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,678 +0,0 @@
-INCLUDE(CheckCSourceCompiles)
-INCLUDE(CheckIncludeFiles)
-INCLUDE(CheckFunctionExists)
-INCLUDE(CheckVariableExists)
-INCLUDE(CheckTypeSize)
-INCLUDE(CheckLibraryExists)
-INCLUDE(CMakeDetermineCCompiler)
-INCLUDE(FindThreads)
-INCLUDE(CPack)
-INCLUDE(UsePkgConfig)
-
-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 the mod_sql_vhost [default: off]")
-OPTION(WITH_POSTGRESQL "with postgress-support for the mod_sql_vhost [default: off]")
-OPTION(WITH_OPENSSL "with openssl-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_BZIP "with bzip2-support for mod_compress [default: off]")
-OPTION(WITH_ZLIB "with deflate-support for mod_compress [default: on]" ON)
-OPTION(WITH_LDAP "with LDAP-support for the mod_auth [default: off]")
-OPTION(WITH_LIBAIO "with libaio for the linux [default: off]")
-OPTION(WITH_LIBFCGI "with libfcgi for fcgi-stat-accel [default: off]")
-OPTION(WITH_LUA "with lua 5.1 for mod_magnet [default: off]")
-OPTION(WITH_GLIB "with glib support for internal caches [default: on]" ON)
-
-IF(CMAKE_COMPILER_IS_GNUCC)
- OPTION(BUILD_EXTRA_WARNINGS "extra warnings")
-
- IF(BUILD_EXTRA_WARNINGS)
- SET(WARN_FLAGS "-g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wformat-security")
- # -Wl,--as-needed
- # -Werror -Wbad-function-cast -Wmissing-prototypes
- ELSE(BUILD_EXTRA_WARNINGS)
- SET(WARN_FLAGS "")
- ENDIF(BUILD_EXTRA_WARNINGS)
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
-
-OPTION(BUILD_STATIC "build a static lighttpd with all modules added")
-IF(BUILD_STATIC)
- SET(LIGHTTPD_STATIC 1)
-ELSE(BUILD_STATIC)
- SET(CMAKE_SHARED_LIBRARY_PREFIX "")
-ENDIF(BUILD_STATIC)
-
-IF(WITH_WEBDAV_PROPS)
- SET(WITH_XML 1)
- SET(WITH_SQLITE3 1)
- SET(WITH_UUID 1)
-ENDIF(WITH_WEBDAV_PROPS)
-
-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/syslimits.h HAVE_SYS_SYSLIMITS_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(time.h HAVE_TIME_H)
-CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H)
-CHECK_INCLUDE_FILES(pthread.h HAVE_PTHREAD_H)
-
-
-## 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(${_package}CONFIG_EXECUTABLE)
- MESSAGE(STATUS "found ${_package}: no")
- ENDIF(${_package}CONFIG_EXECUTABLE)
-ENDMACRO(XCONFIG _package _include_DIR _link_DIR _link_FLAGS _cflags)
-
-##INCLUDE_DIRECTORIES(${GTHREAD_INCDIR})
-ADD_DEFINITIONS(${GTHREAD_CFLAGS})
-
-IF(WITH_XATTR)
- CHECK_INCLUDE_FILES(attr/attributes.h HAVE_ATTR_ATTRIBUTES_H)
-ENDIF(WITH_XATTR)
-
-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_LIBMYSQL)
- ENDIF(HAVE_MYSQL_H)
-ENDIF(WITH_MYSQL)
-
-IF(WITH_POSTGRESQL)
- SET(CMAKE_REQUIRED_INCLUDES /usr/include/pgsql)
- CHECK_INCLUDE_FILES(libpq-fe.h HAVE_LIBPQ_FE_H)
- SET(CMAKE_REQUIRED_INCLUDES)
- IF(HAVE_LIBPG_FE_H)
- CHECK_LIBRARY_EXISTS(pq PQconnectdb "" HAVE_LIBPQ)
- ENDIF(HAVE_LIBPG_FE_H)
-ENDIF(WITH_POSTGRESQL)
-
-IF(WITH_OPENSSL)
- CHECK_INCLUDE_FILES(openssl/ssl.h HAVE_OPENSSL_SSL_H)
- IF(HAVE_OPENSSL_SSL_H)
- CHECK_LIBRARY_EXISTS(crypto BIO_f_base64 "" HAVE_LIBCRYPTO)
- IF(HAVE_LIBCRYPTO)
- SET(OPENSSL_NO_KRB5 1)
- CHECK_LIBRARY_EXISTS(ssl SSL_new "" HAVE_LIBSSL)
- ENDIF(HAVE_LIBCRYPTO)
- ENDIF(HAVE_OPENSSL_SSL_H)
-ENDIF(WITH_OPENSSL)
-
-CHECK_INCLUDE_FILES(aio.h HAVE_AIO_H)
-IF(WITH_BZIP)
- CHECK_INCLUDE_FILES(bzlib.h HAVE_BZLIB_H)
- CHECK_LIBRARY_EXISTS(bz2 BZ2_bzCompressInit "" HAVE_LIBBZ2)
-ENDIF(WITH_BZIP)
-
-CHECK_INCLUDE_FILES(getopt.h HAVE_GETOPT_H)
-CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H)
-IF(WITH_LDAP)
- CHECK_INCLUDE_FILES(ldap.h HAVE_LDAP_H)
- CHECK_LIBRARY_EXISTS(ldap ldap_open "" HAVE_LIBLDAP)
-ENDIF(WITH_LDAP)
-
-IF(WITH_LIBAIO)
- CHECK_INCLUDE_FILES(libaio.h HAVE_LIBAIO_H)
- CHECK_LIBRARY_EXISTS(aio io_getevents "" HAVE_LIBAIO)
-ENDIF(WITH_LIBAIO)
-
-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(XML2_LDFLAGS OR XML2_CFLAGS)
- CHECK_INCLUDE_FILES(libxml.h HAVE_LIBXML_H)
- CHECK_LIBRARY_EXISTS(xml2 xmlParseChunk "" HAVE_LIBXML)
- ENDIF(XML2_LDFLAGS OR XML2_CFLAGS)
-
- IF(NOT HAVE_LIBXML_H)
- MESSAGE(FATAL_ERROR "libxml/tree.h couldn't be found")
- ENDIF(NOT HAVE_LIBXML_H)
- IF(NOT HAVE_LIBXML)
- MESSAGE(FATAL_ERROR "libxml2 couldn't be found")
- ENDIF(NOT HAVE_LIBXML)
-
-ENDIF(WITH_XML)
-
-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(NOT PCRE_CFLAGS STREQUAL "\n")
-
- CHECK_INCLUDE_FILES(pcre.h HAVE_PCRE_H)
-
- SET(CMAKE_REQUIRED_FLAGS ${PCRE_LDFLAGS})
- CHECK_LIBRARY_EXISTS(pcre pcre_exec "" HAVE_LIBPCRE)
- SET(CMAKE_REQUIRED_FLAGS)
-
- ELSE(PCRE_LDFLAGS OR PCRE_CFLAGS)
- IF(NOT WIN32)
- CHECK_INCLUDE_FILES(pcre.h HAVE_PCRE_H)
- CHECK_LIBRARY_EXISTS(pcre pcre_exec "" HAVE_LIBPCRE)
- SET(PCRE_LIBRARY pcre)
- ELSE(NOT WIN32)
- 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(PCRE_INCLUDE_DIR AND PCRE_LIBRARY)
- ENDIF(NOT WIN32)
- ENDIF(PCRE_LDFLAGS OR PCRE_CFLAGS)
-
- IF(NOT HAVE_PCRE_H)
- MESSAGE(FATAL_ERROR "pcre.h couldn't be found")
- ENDIF(NOT HAVE_PCRE_H)
- IF(NOT HAVE_LIBPCRE)
- MESSAGE(FATAL_ERROR "libpcre couldn't be found")
- ENDIF(NOT HAVE_LIBPCRE)
-
-ENDIF(WITH_PCRE)
-
-CHECK_INCLUDE_FILES(poll.h HAVE_POLL_H)
-CHECK_INCLUDE_FILES(pwd.h HAVE_PWD_H)
-
-OPTION(WITH_SQLITE3 "with property-support [sqlite3] for mod_webdav [default: off]")
-IF(WITH_SQLITE3)
- CHECK_INCLUDE_FILES(sqlite3.h HAVE_SQLITE3_H)
- CHECK_LIBRARY_EXISTS(sqlite3 sqlite3_reset "" HAVE_SQLITE3)
-ENDIF(WITH_SQLITE3)
-
-IF(WITH_GLIB)
- PKGCONFIG(gthread-2.0 GTHREAD_INCDIR GTHREAD_LIBDIR GTHREAD_LDFLAGS GTHREAD_CFLAGS)
- MESSAGE(STATUS "found gthread-2.0 at: INCDIR: ${GTHREAD_INCDIR} LIBDIR: ${GTHREAD_LIBDIR} LDFLAGS: ${GTHREAD_LDFLAGS} CFLAGS: ${GTHREAD_CFLAGS}")
-
- SET(GLIB_INC_DIRS ${GTHREAD_INCDIR}/glib-2.0/ ${GTHREAD_LIBDIR}/glib-2.0/include/)
- INCLUDE_DIRECTORIES(${GLIB_INC_DIRS})
-
- SET(CMAKE_REQUIRED_INCLUDES ${GLIB_INC_DIRS})
- CHECK_INCLUDE_FILES(glib.h HAVE_GLIB_H)
- SET(CMAKE_REQUIRED_INCLUDES)
-ENDIF(WITH_GLIB)
-
-IF(WITH_LIBFCGI)
- CHECK_INCLUDE_FILES(fastcgi.h HAVE_FASTCGI_H)
- CHECK_INCLUDE_FILES(fastcgi/fastcgi.h HAVE_FASTCGI_FASTCGI_H)
- IF(HAVE_FASTCGI_H OR HAVE_FASTCGI_FASTCGI_H)
- CHECK_LIBRARY_EXISTS(fcgi FCGI_Accept "" HAVE_LIBFCGI)
- ENDIF(HAVE_FASTCGI_H OR HAVE_FASTCGI_FASTCGI_H)
-ENDIF(WITH_LIBFCGI)
-
-CHECK_INCLUDE_FILES(stddef.h HAVE_STDDEF_H)
-CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H)
-CHECK_INCLUDE_FILES(syslog.h HAVE_SYSLOG_H)
-IF(WITH_UUID)
- CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H)
- CHECK_LIBRARY_EXISTS(uuid uuid_generate "" NEED_LIBUUID)
- IF(NOT NEED_LIBUUID)
- CHECK_FUNCTION_EXISTS(uuid_generate HAVE_LIBUUID)
- ELSE(NOT NEED_LIBUUID)
- SET(HAVE_LIBUUID 1)
- ENDIF(NOT NEED_LIBUUID)
-ENDIF(WITH_UUID)
-
-CHECK_INCLUDE_FILES(sys/inotify.h HAVE_SYS_INOTIFY_H)
-IF(HAVE_SYS_INOTIFY_H)
- CHECK_FUNCTION_EXISTS(inotify_init HAVE_INOTIFY_INIT)
-ENDIF(HAVE_SYS_INOTIFY_H)
-
-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(NOT WIN32)
- 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(ZLIB_INCLUDE_DIR AND ZLIB_LIBRARY)
- ENDIF(NOT WIN32)
-ENDIF(WITH_ZLIB)
-
-IF(WITH_LUA)
- PKGCONFIG(lua LUA_INCDIR LUA_LIBDIR LUA_LDFLAGS LUA_CFLAGS)
- IF(NOT LUA_LDFLAGS)
- PKGCONFIG(lua5.1 LUA_INCDIR LUA_LIBDIR LUA_LDFLAGS LUA_CFLAGS)
- ENDIF(NOT LUA_LDFLAGS)
- IF(NOT LUA_LDFLAGS)
- PKGCONFIG(lua-5.1 LUA_INCDIR LUA_LIBDIR LUA_LDFLAGS LUA_CFLAGS)
- ENDIF(NOT LUA_LDFLAGS)
- MESSAGE(STATUS "found lua at: INCDIR: ${LUA_INCDIR} LIBDIR: ${LUA_LIBDIR} LDFLAGS: ${LUA_LDFLAGS} CFLAGS: ${LUA_CFLAGS}")
- IF(LUA_LDFLAGS)
- SET(HAVE_LIBLUA 1 "Have liblua")
- INCLUDE_DIRECTORIES(${LUA_INCDIR})
-
- SET(CMAKE_REQUIRED_INCLUDES ${LUA_INCDIR})
- SET(CMAKE_REQUIRED_FLAGS ${LUA_CFLAGS})
- CHECK_INCLUDE_FILES(lua.h HAVE_LUA_H)
- SET(CMAKE_REQUIRED_INCLUDES)
- SET(CMAKE_REQUIRED_FLAGS)
- ELSE(LUA_LDFLAGS)
- SET(HAVE_LIBLUA "" "Have liblua")
- SET(HAVE_LUA_H "" "Have liblua header")
- ENDIF(LUA_LDFLAGS)
-ENDIF(WITH_LUA)
-
-CHECK_INCLUDE_FILES(crypt.h HAVE_CRYPT_H)
-IF(NOT BUILD_STATIC)
- CHECK_INCLUDE_FILES(dlfcn.h HAVE_DLFCN_H)
-ENDIF(NOT BUILD_STATIC)
-
-SET(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
-CHECK_TYPE_SIZE(socklen_t HAVE_SOCKLEN_T)
-SET(CMAKE_EXTRA_INCLUDE_FILES)
-
-CHECK_TYPE_SIZE(long SIZEOF_LONG)
-CHECK_TYPE_SIZE(off_t SIZEOF_OFF_T)
-
-CHECK_FUNCTION_EXISTS(chroot HAVE_CHROOT)
-CHECK_FUNCTION_EXISTS(crypt HAVE_CRYPT)
-CHECK_FUNCTION_EXISTS(epoll_ctl HAVE_EPOLL_CTL)
-CHECK_FUNCTION_EXISTS(fork HAVE_FORK)
-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(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(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(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(strptime HAVE_STRPTIME)
-CHECK_FUNCTION_EXISTS(strtoll HAVE_STRTOLL)
-CHECK_FUNCTION_EXISTS(syslog HAVE_SYSLOG)
-CHECK_FUNCTION_EXISTS(writev HAVE_WRITEV)
-CHECK_FUNCTION_EXISTS(inet_aton HAVE_INET_ATON)
-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_FUNCTION_EXISTS(issetugid HAVE_ISSETUGID)
-
-IF(NOT HAVE_CRYPT)
- ## check if we need libcrypt for crypt()
- CHECK_LIBRARY_EXISTS(crypt crypt "" HAVE_LIBCRYPT)
-ENDIF(NOT HAVE_CRYPT)
-
-IF(HAVE_DLFCN_H)
- CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL)
-ENDIF(HAVE_DLFCN_H)
-
-ADD_DEFINITIONS(
- -DLIGHTTPD_VERSION_ID=10500
- -DPACKAGE_NAME="\\"${CMAKE_PROJECT_NAME}\\""
- -DPACKAGE_VERSION="\\"${CPACK_PACKAGE_VERSION}\\""
- )
-
-IF(NOT SBINDIR)
- SET(SBINDIR "sbin")
-ENDIF(NOT SBINDIR)
-
-SET(LIGHTTPD_MODULES_DIR "lib${LIB_SUFFIX}/lighttpd")
-IF(NOT WIN32)
-ADD_DEFINITIONS(
- -DLIBRARY_DIR="\\"${CMAKE_INSTALL_PREFIX}/${LIGHTTPD_MODULES_DIR}\\""
-)
-ELSE(NOT WIN32)
-## We use relative path in windows
-ADD_DEFINITIONS(
- -DLIBRARY_DIR="\\"lib\\""
-)
-ENDIF(NOT WIN32)
-
-## 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
- buffer.c log.c
- keyvalue.c chunk.c
- stream.c fdevent.c
- stat_cache.c plugin.c joblist.c etag.c array.c
- data_string.c data_count.c data_array.c
- data_integer.c md5.c
- fdevent_select.c fdevent_linux_rtsig.c
- fdevent_poll.c fdevent_linux_sysepoll.c
- fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c
- data_config.c bitset.c
- inet_ntop_cache.c crc32.c
- connections-glue.c iosocket.c
- configfile-glue.c
- http-header-glue.c status_counter.c
- network_writev.c
- network_write.c
- network_linux_sendfile.c
- network_freebsd_sendfile.c
- network_win32_send.c
- network_solaris_sendfilev.c
- network_openssl.c
- network_linux_aio.c
- network_posix_aio.c
- network_gthread_aio.c
- network_gthread_sendfile.c
- network_gthread_freebsd_sendfile.c
- http_resp.c
- http_resp_parser.c
- http_req.c
- http_req_parser.c
- http_req_range.c
- http_req_range_parser.c
- sys-files.c
- sys-socket.c
- filter.c
- timing.c
-)
-
-IF(WIN32)
- MESSAGE(STATUS "Adding local getopt implementation.")
- SET(COMMON_SRC ${COMMON_SRC} xgetopt.c)
-ENDIF(WIN32)
-
-ADD_EXECUTABLE(lemon lemon.c)
-
-## Build parsers by using lemon...
-LEMON_PARSER(configparser.y)
-LEMON_PARSER(http_req_parser.y)
-LEMON_PARSER(http_req_range_parser.y)
-LEMON_PARSER(http_resp_parser.y)
-LEMON_PARSER(mod_ssi_exprparser.y)
-
-SET(L_INSTALL_TARGETS)
-
-IF(HAVE_LIBFCGI)
- ADD_EXECUTABLE(fcgi-stat-accel fcgi-stat-accel.c)
- TARGET_LINK_LIBRARIES(fcgi-stat-accel fcgi)
- SET_TARGET_PROPERTIES(fcgi-stat-accel PROPERTIES LINK_FLAGS "-pthread")
- SET(L_INSTALL_TARGETS ${L_INSTALL_TARGETS} fcgi-stat-accel)
-ENDIF(HAVE_LIBFCGI)
-
-ADD_EXECUTABLE(lighttpd
- server.c
- network.c
- configfile.c
- configparser.c
- connections.c
- proc_open.c
- request.c
- response.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_alias mod_alias.c)
-ADD_AND_INSTALL_LIBRARY(mod_dirlisting mod_dirlisting.c)
-ADD_AND_INSTALL_LIBRARY(mod_staticfile mod_staticfile.c)
-
-ADD_AND_INSTALL_LIBRARY(mod_indexfile mod_indexfile.c)
-ADD_AND_INSTALL_LIBRARY(mod_setenv mod_setenv.c)
-ADD_AND_INSTALL_LIBRARY(mod_rrdtool mod_rrdtool.c)
-ADD_AND_INSTALL_LIBRARY(mod_usertrack mod_usertrack.c)
-ADD_AND_INSTALL_LIBRARY(mod_proxy_core "mod_proxy_core.c;mod_proxy_core_pool.c;mod_proxy_core_backend.c;mod_proxy_core_address.c;mod_proxy_core_backlog.c;mod_proxy_core_protocol.c;mod_proxy_core_rewrites.c")
-ADD_AND_INSTALL_LIBRARY(mod_proxy_backend_http mod_proxy_backend_http.c)
-ADD_AND_INSTALL_LIBRARY(mod_proxy_backend_fastcgi mod_proxy_backend_fastcgi.c)
-ADD_AND_INSTALL_LIBRARY(mod_proxy_backend_scgi mod_proxy_backend_scgi.c)
-ADD_AND_INSTALL_LIBRARY(mod_proxy_backend_ajp13 mod_proxy_backend_ajp13.c)
-ADD_AND_INSTALL_LIBRARY(mod_userdir mod_userdir.c)
-ADD_AND_INSTALL_LIBRARY(mod_secdownload mod_secure_download.c)
-ADD_AND_INSTALL_LIBRARY(mod_accesslog mod_accesslog.c)
-ADD_AND_INSTALL_LIBRARY(mod_simple_vhost mod_simple_vhost.c)
-ADD_AND_INSTALL_LIBRARY(mod_evhost mod_evhost.c)
-ADD_AND_INSTALL_LIBRARY(mod_expire mod_expire.c)
-ADD_AND_INSTALL_LIBRARY(mod_status mod_status.c)
-ADD_AND_INSTALL_LIBRARY(mod_compress mod_compress.c)
-ADD_AND_INSTALL_LIBRARY(mod_redirect mod_redirect.c)
-ADD_AND_INSTALL_LIBRARY(mod_rewrite mod_rewrite.c)
-ADD_AND_INSTALL_LIBRARY(mod_auth "mod_auth.c;http_auth_digest.c;http_auth.c")
-ADD_AND_INSTALL_LIBRARY(mod_sql_vhost_core mod_sql_vhost_core.c)
-ADD_AND_INSTALL_LIBRARY(mod_mysql_vhost mod_mysql_vhost.c)
-ADD_AND_INSTALL_LIBRARY(mod_postgresql_vhost mod_postgresql_vhost.c)
-ADD_AND_INSTALL_LIBRARY(mod_trigger_b4_dl mod_trigger_b4_dl.c)
-ADD_AND_INSTALL_LIBRARY(mod_uploadprogress mod_uploadprogress.c)
-ADD_AND_INSTALL_LIBRARY(mod_evasive mod_evasive.c)
-ADD_AND_INSTALL_LIBRARY(mod_ssi "mod_ssi_exprparser.c;mod_ssi_expr.c;mod_ssi.c")
-ADD_AND_INSTALL_LIBRARY(mod_flv_streaming mod_flv_streaming.c)
-ADD_AND_INSTALL_LIBRARY(mod_chunked mod_chunked.c)
-ADD_AND_INSTALL_LIBRARY(mod_magnet "mod_magnet.c;mod_magnet_cache.c")
-ADD_AND_INSTALL_LIBRARY(mod_deflate mod_deflate.c)
-ADD_AND_INSTALL_LIBRARY(mod_webdav mod_webdav.c)
-
-IF(NOT WIN32)
-ADD_AND_INSTALL_LIBRARY(mod_cgi mod_cgi.c)
-ENDIF(NOT WIN32)
-
-IF(HAVE_PCRE_H)
- TARGET_LINK_LIBRARIES(lighttpd ${PCRE_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_rewrite ${PCRE_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_dirlisting ${PCRE_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_redirect ${PCRE_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_ssi ${PCRE_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_trigger_b4_dl ${PCRE_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_proxy_core ${PCRE_LIBRARY})
-ENDIF(HAVE_PCRE_H)
-
-ADD_TARGET_PROPERTIES(mod_magnet LINK_FLAGS "${LUA_LDFLAGS}")
-ADD_TARGET_PROPERTIES(mod_magnet COMPILE_FLAGS "${LUA_CFLAGS}")
-
-IF(HAVE_MYSQL_H AND HAVE_LIBMYSQL)
- TARGET_LINK_LIBRARIES(mod_mysql_vhost mysqlclient)
- INCLUDE_DIRECTORIES(/usr/include/mysql)
-ENDIF(HAVE_MYSQL_H AND HAVE_LIBMYSQL)
-
-IF(HAVE_LIBPQ_FE_H AND HAVE_LIBPQ)
- TARGET_LINK_LIBRARIES(mod_postgresql_vhost pq)
- INCLUDE_DIRECTORIES(/usr/include/pgsql)
-ENDIF(HAVE_LIBPQ_FE_H AND HAVE_LIBPQ)
-
-SET(L_MOD_WEBDAV)
-IF(HAVE_SQLITE3_H)
- SET(L_MOD_WEBDAV ${L_MOD_WEBDAV} sqlite3)
-ENDIF(HAVE_SQLITE3_H)
-IF(HAVE_LIBXML_H)
- SET_TARGET_PROPERTIES(mod_webdav PROPERTIES LINK_FLAGS ${XML2_LDFLAGS})
-ENDIF(HAVE_LIBXML_H)
-IF(HAVE_UUID_H)
- IF(NEED_LIBUUID)
- SET(L_MOD_WEBDAV ${L_MOD_WEBDAV} uuid)
- ENDIF(NEED_LIBUUID)
-ENDIF(HAVE_UUID_H)
-
-TARGET_LINK_LIBRARIES(mod_webdav ${L_MOD_WEBDAV})
-
-SET(L_MOD_AUTH)
-IF(HAVE_LIBCRYPT)
- SET(L_MOD_AUTH ${L_MOD_AUTH} crypt)
-ENDIF(HAVE_LIBCRYPT)
-
-IF(HAVE_LDAP_H)
- SET(L_MOD_AUTH ${L_MOD_AUTH} ldap lber)
-ENDIF(HAVE_LDAP_H)
-TARGET_LINK_LIBRARIES(mod_auth ${L_MOD_AUTH})
-
-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(HAVE_BZLIB_H)
- TARGET_LINK_LIBRARIES(mod_compress ${ZLIB_LIBRARY})
- TARGET_LINK_LIBRARIES(mod_deflate ${ZLIB_LIBRARY})
- ENDIF(HAVE_BZLIB_H)
-ENDIF(HAVE_ZLIB_H)
-
-IF(CMAKE_COMPILER_IS_GNUCC)
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -g -Wshadow -W -pedantic ${WARN_FLAGS}")
- 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")
- ADD_DEFINITIONS(-D_GNU_SOURCE)
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
-
-ADD_TARGET_PROPERTIES(lighttpd LINK_FLAGS "-export-dynamic ${GTHREAD_LDFLAGS} ${XML2_LDFLAGS}")
-IF(CMAKE_SYSTEM MATCHES "Linux")
- ## on linux we need pthread and librt for posix-aio
- ADD_TARGET_PROPERTIES(lighttpd LINK_FLAGS "-lrt")
-ENDIF(CMAKE_SYSTEM MATCHES "Linux")
-
-ADD_TARGET_PROPERTIES(lighttpd COMPILE_FLAGS "${GTHREAD_CFLAGS}")
-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_core ws2_32)
- TARGET_LINK_LIBRARIES(mod_proxy_backend_ajp13 ws2_32)
- TARGET_LINK_LIBRARIES(mod_proxy_backend_fastcgi ws2_32)
- TARGET_LINK_LIBRARIES(mod_proxy_backend_scgi ws2_32)
- TARGET_LINK_LIBRARIES(mod_ssi ws2_32)
- # required for mingw gcc/ld
- IF(WITH_GLIB)
- TARGET_LINK_LIBRARIES(lighttpd glib-2.0 gthread-2.0)
- ENDIF(WITH_GLIB)
-
- IF(MINGW)
- TARGET_LINK_LIBRARIES(lighttpd msvcr70)
- ADD_TARGET_PROPERTIES(lighttpd LINK_FLAGS "-Wl,-subsystem,console")
- ENDIF(MINGW)
-ENDIF(WIN32)
-
-IF(NOT BUILD_STATIC)
- IF(HAVE_LIBDL)
- TARGET_LINK_LIBRARIES(lighttpd dl)
- ENDIF(HAVE_LIBDL)
-ENDIF(NOT BUILD_STATIC)
-
-IF(HAVE_LIBAIO_H)
- TARGET_LINK_LIBRARIES(lighttpd aio)
-ENDIF(HAVE_LIBAIO_H)
-
-IF(HAVE_LIBSSL AND HAVE_LIBCRYPTO)
- TARGET_LINK_LIBRARIES(lighttpd ssl)
- TARGET_LINK_LIBRARIES(lighttpd crypto)
-ENDIF(HAVE_LIBSSL AND HAVE_LIBCRYPTO)
-
-IF(NOT WIN32)
-INSTALL(TARGETS ${L_INSTALL_TARGETS}
- RUNTIME DESTINATION ${SBINDIR}
- LIBRARY DESTINATION ${LIGHTTPD_MODULES_DIR}
- ARCHIVE DESTINATION ${LIGHTTPD_MODULES_DIR}/static)
-ELSE(NOT WIN32)
-## 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(NOT WIN32)
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index eb50e379..00000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,365 +0,0 @@
-AM_CFLAGS = $(GTHREAD_CFLAGS)
-
-noinst_PROGRAMS=proc_open lemon # simple-fcgi
-if CHECK_WITH_FASTCGI
-sbin_PROGRAMS=lighttpd fcgi-stat-accel
-else
-sbin_PROGRAMS=lighttpd
-endif
-LEMON=$(top_builddir)/src/lemon
-
-lemon_SOURCES=lemon.c
-
-#simple_fcgi_SOURCES=simple-fcgi.c
-#simple_fcgi_LDADD=-lfcgi
-
-if CROSS_COMPILING
-configparser.c configparser.h:
-mod_ssi_exprparser.c mod_ssi_exprparser.h:
-http_req_parser.c http_req_parser.h:
-http_req_range_parser.c http_req_range_parser.h:
-mod_ssi_exprparser.c mod_ssi_exprparser.h:
-else
-configparser.c configparser.h: $(srcdir)/configparser.y $(srcdir)/lempar.c | $(LEMON)
- rm -f configparser.h
- $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
-
-http_resp_parser.c http_resp_parser.h: $(srcdir)/http_resp_parser.y $(srcdir)/lempar.c | $(LEMON)
- rm -f http_resp_parser.h
- $(LEMON) -q $(srcdir)/http_resp_parser.y $(srcdir)/lempar.c
-
-http_req_parser.c http_req_parser.h: $(srcdir)/http_req_parser.y $(srcdir)/lempar.c | $(LEMON)
- rm -f http_req_parser.h
- $(LEMON) -q $(srcdir)/http_req_parser.y $(srcdir)/lempar.c
-
-http_req_range_parser.c http_req_range_parser.h: $(srcdir)/http_req_range_parser.y $(srcdir)/lempar.c | $(LEMON)
- rm -f http_req_range_parser.h
- $(LEMON) -q $(srcdir)/http_req_range_parser.y $(srcdir)/lempar.c
-
-mod_ssi_exprparser.c mod_ssi_exprparser.h: $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c | $(LEMON)
- rm -f mod_ssi_exprparser.h
- $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
-endif
-
-BUILT_SOURCES = configparser.c configparser.h \
- http_resp_parser.c http_resp_parser.h \
- http_req_parser.c http_req_parser.h \
- http_req_range_parser.c http_req_range_parser.h \
- mod_ssi_exprparser.c mod_ssi_exprparser.h
-
-common_src=buffer.c log.c \
- keyvalue.c chunk.c filter.c \
- stream.c fdevent.c \
- stat_cache.c plugin.c joblist.c etag.c array.c \
- data_string.c data_count.c data_array.c \
- data_integer.c md5.c \
- fdevent_select.c fdevent_linux_rtsig.c \
- fdevent_poll.c fdevent_linux_sysepoll.c \
- fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
- data_config.c bitset.c \
- inet_ntop_cache.c crc32.c \
- connections-glue.c iosocket.c \
- configfile-glue.c status_counter.c \
- http-header-glue.c \
- network_write.c network_linux_sendfile.c \
- network_freebsd_sendfile.c network_writev.c \
- network_solaris_sendfilev.c network_openssl.c \
- network_linux_aio.c \
- network_posix_aio.c \
- network_gthread_aio.c network_gthread_sendfile.c \
- network_gthread_freebsd_sendfile.c \
- http_resp.c http_resp_parser.c \
- http_req.c http_req_parser.c \
- http_req_range.c http_req_range_parser.c timing.c
-
-src = server.c response.c connections.c network.c \
- configfile.c configparser.c request.c proc_open.c
-
-if CHECK_WITH_FASTCGI
-fcgi_stat_accel_SOURCES=fcgi-stat-accel.c
-fcgi_stat_accel_LDADD = -lfcgi
-endif
-
-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
-lib_LTLIBRARIES += liblightcomp.la
-liblightcomp_la_SOURCES=$(common_src)
-liblightcomp_la_CFLAGS=$(AM_CFLAGS)
-liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
-liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(GTHREAD_LIBS)
-common_libadd = liblightcomp.la
-else
-src += $(common_src)
-common_libadd =
-endif
-
-lib_LTLIBRARIES += mod_flv_streaming.la
-mod_flv_streaming_la_SOURCES = mod_flv_streaming.c
-mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_flv_streaming_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_uploadprogress.la
-mod_uploadprogress_la_SOURCES = mod_uploadprogress.c
-mod_uploadprogress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_uploadprogress_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_evasive.la
-mod_evasive_la_SOURCES = mod_evasive.c
-mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_evasive_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_webdav.la
-mod_webdav_la_SOURCES = mod_webdav.c
-mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
-mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
-
-lib_LTLIBRARIES += mod_magnet.la
-mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c
-mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
-mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_magnet_la_LIBADD = $(MEMCACHE_LIB) $(common_libadd) $(LUA_LIBS) -lm
-
-lib_LTLIBRARIES += mod_trigger_b4_dl.la
-mod_trigger_b4_dl_la_SOURCES = mod_trigger_b4_dl.c
-mod_trigger_b4_dl_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_trigger_b4_dl_la_LIBADD = $(GDBM_LIB) $(MEMCACHE_LIB) $(PCRE_LIB) $(common_libadd)
-
-lib_LTLIBRARIES += mod_mysql_vhost.la
-mod_mysql_vhost_la_SOURCES = mod_mysql_vhost.c
-mod_mysql_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
-mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
-
-lib_LTLIBRARIES += mod_postgresql_vhost.la
-mod_postgresql_vhost_la_SOURCES = mod_postgresql_vhost.c
-mod_postgresql_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_postgresql_vhost_la_LIBADD = $(POSTGRESQL_LIBS) $(common_libadd)
-mod_postgresql_vhost_la_CPPFLAGS = $(POSTGRESQL_INCLUDE)
-
-
-lib_LTLIBRARIES += mod_sql_vhost_core.la
-mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
-mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_sql_vhost_core_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_cgi.la
-mod_cgi_la_SOURCES = mod_cgi.c
-mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_cgi_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_staticfile.la
-mod_staticfile_la_SOURCES = mod_staticfile.c
-mod_staticfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_staticfile_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_deflate.la
-mod_deflate_la_SOURCES = mod_deflate.c
-mod_deflate_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_deflate_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
-
-lib_LTLIBRARIES += mod_chunked.la
-mod_chunked_la_SOURCES = mod_chunked.c
-mod_chunked_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_chunked_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_dirlisting.la
-mod_dirlisting_la_SOURCES = mod_dirlisting.c
-mod_dirlisting_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-lib_LTLIBRARIES += mod_indexfile.la
-mod_indexfile_la_SOURCES = mod_indexfile.c
-mod_indexfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_indexfile_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_setenv.la
-mod_setenv_la_SOURCES = mod_setenv.c
-mod_setenv_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_setenv_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_alias.la
-mod_alias_la_SOURCES = mod_alias.c
-mod_alias_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_alias_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_userdir.la
-mod_userdir_la_SOURCES = mod_userdir.c
-mod_userdir_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_userdir_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_rrdtool.la
-mod_rrdtool_la_SOURCES = mod_rrdtool.c
-mod_rrdtool_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_rrdtool_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_usertrack.la
-mod_usertrack_la_SOURCES = mod_usertrack.c
-mod_usertrack_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_usertrack_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_proxy_core.la
-mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
- mod_proxy_core_backend.c mod_proxy_core_address.c \
- mod_proxy_core_backlog.c mod_proxy_core_rewrites.c \
- mod_proxy_core_protocol.c
-mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-lib_LTLIBRARIES += mod_proxy_backend_http.la
-mod_proxy_backend_http_la_SOURCES = mod_proxy_backend_http.c
-mod_proxy_backend_http_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_proxy_backend_http_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-lib_LTLIBRARIES += mod_proxy_backend_fastcgi.la
-mod_proxy_backend_fastcgi_la_SOURCES = mod_proxy_backend_fastcgi.c
-mod_proxy_backend_fastcgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_proxy_backend_fastcgi_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-lib_LTLIBRARIES += mod_proxy_backend_scgi.la
-mod_proxy_backend_scgi_la_SOURCES = mod_proxy_backend_scgi.c
-mod_proxy_backend_scgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_proxy_backend_scgi_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-lib_LTLIBRARIES += mod_proxy_backend_ajp13.la
-mod_proxy_backend_ajp13_la_SOURCES = mod_proxy_backend_ajp13.c
-mod_proxy_backend_ajp13_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_proxy_backend_ajp13_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-
-lib_LTLIBRARIES += mod_ssi.la
-mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
-mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_ssi_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-
-lib_LTLIBRARIES += mod_secdownload.la
-mod_secdownload_la_SOURCES = mod_secure_download.c
-mod_secdownload_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_secdownload_la_LIBADD = $(common_libadd)
-
-#lib_LTLIBRARIES += mod_httptls.la
-#mod_httptls_la_SOURCES = mod_httptls.c
-#mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-#mod_httptls_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_expire.la
-mod_expire_la_SOURCES = mod_expire.c
-mod_expire_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_expire_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_evhost.la
-mod_evhost_la_SOURCES = mod_evhost.c
-mod_evhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-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 = -module -export-dynamic -avoid-version -no-undefined
-mod_simple_vhost_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_access.la
-mod_access_la_SOURCES = mod_access.c
-mod_access_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_access_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_compress.la
-mod_compress_la_SOURCES = mod_compress.c
-mod_compress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
-
-lib_LTLIBRARIES += mod_auth.la
-mod_auth_la_SOURCES = mod_auth.c http_auth_digest.c http_auth.c
-mod_auth_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_auth_la_LIBADD = $(CRYPT_LIB) $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
-
-lib_LTLIBRARIES += mod_rewrite.la
-mod_rewrite_la_SOURCES = mod_rewrite.c
-mod_rewrite_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_rewrite_la_LIBADD = $(PCRE_LIB) $(common_libadd)
-
-lib_LTLIBRARIES += mod_redirect.la
-mod_redirect_la_SOURCES = mod_redirect.c
-mod_redirect_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_redirect_la_LIBADD = $(PCRE_LIB) $(common_libadd)
-
-lib_LTLIBRARIES += mod_status.la
-mod_status_la_SOURCES = mod_status.c
-mod_status_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_status_la_LIBADD = $(common_libadd)
-
-lib_LTLIBRARIES += mod_accesslog.la
-mod_accesslog_la_SOURCES = mod_accesslog.c
-mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_accesslog_la_LIBADD = $(common_libadd)
-
-
-hdr = server.h buffer.h network.h log.h keyvalue.h \
- response.h request.h fastcgi.h chunk.h filter.h \
- settings.h http_auth_digest.h \
- md5.h http_auth.h stream.h \
- fdevent.h connections.h base.h stat_cache.h \
- plugin.h mod_auth.h \
- etag.h joblist.h array.h crc32.h \
- network_backends.h configfile.h bitset.h \
- mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
- configparser.h mod_ssi_exprparser.h \
- sys-mmap.h sys-socket.h \
- proc_open.h mod_sql_vhost_core.h \
- sys-files.h sys-process.h sys-strings.h \
- iosocket.h array-static.h \
- mod_proxy_core_address.h \
- mod_proxy_core_backend.h \
- mod_proxy_core_backlog.h \
- mod_proxy_core.h \
- mod_proxy_core_pool.h \
- mod_proxy_core_rewrites.h \
- status_counter.h \
- http_req.h \
- http_req_parser.h \
- http_req_range.h \
- http_req_range_parser.h \
- http_resp.h \
- http_resp_parser.h \
- http_parser.h \
- ajp13.h \
- mod_proxy_core_protocol.h \
- mod_magnet_cache.h \
- timing.h
-
-DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
-
-lighttpd_SOURCES = $(src)
-lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(AIO_LIB) $(POSIX_AIO_LIB) $(GTHREAD_LIBS)
-lighttpd_LDFLAGS = -export-dynamic
-
-proc_open_SOURCES = proc_open.c buffer.c
-proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN
-
-#gen_license_SOURCES = license.c md5.c buffer.c gen_license.c
-
-#ssl_SOURCES = ssl.c
-
-
-#adserver_SOURCES = buffer.c iframe.c
-#adserver_LDADD = -lfcgi -lmysqlclient
-
-#error_test_SOURCES = error_test.c
-
-#evalo_SOURCES = buffer.c eval.c
-#bench_SOURCES = buffer.c bench.c
-#ajp_SOURCES = ajp.c
-
-noinst_HEADERS = $(hdr)
-EXTRA_DIST = mod_skeleton.c \
- configparser.y \
- mod_ssi_exprparser.y \
- lempar.c \
- http_resp_parser.y \
- http_req_parser.y \
- http_req_range_parser.y
-
-SUBDIRS=valgrind
diff --git a/src/XGetopt.h b/src/XGetopt.h
deleted file mode 100644
index 7e75f26e..00000000
--- a/src/XGetopt.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// XGetopt.h Version 1.2
-//
-// Author: Hans Dietrich
-// hdietrich2@hotmail.com
-//
-// This software is released into the public domain.
-// You are free to use it in any way you like.
-//
-// This software is provided "as is" with no expressed
-// or implied warranty. I accept no liability for any
-// damage or loss of business that this software may cause.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef XGETOPT_H
-#define XGETOPT_H
-
-extern int optind, opterr;
-extern TCHAR *optarg;
-
-int getopt(int argc, TCHAR *argv[], TCHAR *optstring);
-
-#endif //XGETOPT_H
diff --git a/src/ajp13.h b/src/ajp13.h
deleted file mode 100644
index 8ad6a577..00000000
--- a/src/ajp13.h
+++ /dev/null
@@ -1,136 +0,0 @@
-
-#ifndef _AJP13_H
-#define _AJP13_H
-/**
- * AJP13 protocol definitions.
- */
-#define AJP13_MAX_PACKET_SIZE (8 * 1024)
-#define AJP13_MAX_BODY_PACKET_SIZE (AJP13_MAX_PACKET_SIZE - AJP13_HEADER_LEN - 2)
-
-/**
- * two byte maigc codes
- */
-#define AJP13_SERVER_MAGIC 0x1234
-#define AJP13_CONTAINER_MAGIC 0x4142
-
-/**
- * packet types.
- */
-typedef enum {
- AJP13_TYPE_DATA = 0, /* 0 */
- AJP13_TYPE_UNKNOWN, /* 1 */
- AJP13_TYPE_FORWARD_REQUEST, /* 2 */
- AJP13_TYPE_SEND_BODY_CHUNK, /* 3 */
- AJP13_TYPE_SEND_HEADERS, /* 4 */
- AJP13_TYPE_END_RESPONSE, /* 5 */
- AJP13_TYPE_GET_BODY_CHUNK, /* 6 */
- AJP13_TYPE_SHUTDOWN, /* 7 */
- AJP13_TYPE_PING_REQUEST, /* 8 */
- AJP13_TYPE_CPONG_REPLY, /* 9 */
- AJP13_TYPE_CPING_REQUEST, /* 10 */
-} ajp13_type_t;
-
-/*
- * http method codes
- */
-typedef enum {
- AJP13_METHOD_UNKNOWN = 0, /* 0 */
- AJP13_METHOD_OPTIONS, /* 1 */
- AJP13_METHOD_GET, /* 2 */
- AJP13_METHOD_HEAD, /* 3 */
- AJP13_METHOD_POST, /* 4 */
- AJP13_METHOD_PUT, /* 5 */
- AJP13_METHOD_DELETE, /* 6 */
- AJP13_METHOD_TRACE, /* 7 */
- AJP13_METHOD_PROPFIND, /* 8 */
- AJP13_METHOD_PROPPATCH, /* 9 */
- AJP13_METHOD_MKCOL, /* 10 */
- AJP13_METHOD_COPY, /* 11 */
- AJP13_METHOD_MOVE, /* 12 */
- AJP13_METHOD_LOCK, /* 13 */
- AJP13_METHOD_UNLOCK, /* 14 */
- AJP13_METHOD_ACL, /* 15 */
- AJP13_METHOD_REPORT, /* 16 */
- AJP13_METHOD_VERSION_CONTROL, /* 17 */
- AJP13_METHOD_CHECKIN, /* 18 */
- AJP13_METHOD_CHECKOUT, /* 19 */
- AJP13_METHOD_UNCHECKOUT, /* 20 */
- AJP13_METHOD_SEARCH, /* 21 */
- AJP13_METHOD_MKWORKSPACE, /* 22 */
- AJP13_METHOD_UPDATE, /* 23 */
- AJP13_METHOD_LABEL, /* 24 */
- AJP13_METHOD_MERGE, /* 25 */
- AJP13_METHOD_BASELINE_CONTROL,/* 26 */
- AJP13_METHOD_MKACTIVITY /* 27 */
-} ajp13_method_t;
-
-/*
- * request headers
- */
-typedef enum {
- AJP13_REQ_ACCEPT = 0x01, /* 0x01 */
- AJP13_REQ_ACCEPT_CHARSET, /* 0x02 */
- AJP13_REQ_ACCEPT_ENCODING, /* 0x03 */
- AJP13_REQ_ACCEPT_LANGUAGE, /* 0x04 */
- AJP13_REQ_AUTHORIZATION, /* 0x05 */
- AJP13_REQ_CONNECTION, /* 0x06 */
- AJP13_REQ_CONTENT_TYPE, /* 0x07 */
- AJP13_REQ_CONTENT_LENGTH, /* 0x08 */
- AJP13_REQ_COOKIE, /* 0x09 */
- AJP13_REQ_COOKIE2, /* 0x0A */
- AJP13_REQ_HOST, /* 0x0B */
- AJP13_REQ_PRAGMA, /* 0x0C */
- AJP13_REQ_REFERER, /* 0x0D */
- AJP13_REQ_USER_AGENT /* 0x0E */
-} ajp13_request_header_t;
-
-/*
- * request attributes
- */
-typedef enum {
- AJP13_ATTRIBUTE_CONTEXT = 1, /* 1 */
- AJP13_ATTRIBUTE_SERVLET_PATH, /* 2 */
- AJP13_ATTRIBUTE_REMOTE_USER, /* 3 */
- AJP13_ATTRIBUTE_AUTH_TYPE, /* 4 */
- AJP13_ATTRIBUTE_QUERY_STRING, /* 5 */
- AJP13_ATTRIBUTE_JVM_ROUTE, /* 6 */
- AJP13_ATTRIBUTE_SSL_CERT, /* 7 */
- AJP13_ATTRIBUTE_SSL_CIPHER, /* 8 */
- AJP13_ATTRIBUTE_SSL_SESSION, /* 9 */
- AJP13_ATTRIBUTE_REQ_ATTRIBUTE, /* 10 */
- AJP13_ATTRIBUTE_SSL_KEY_SIZE, /* 11 */
- AJP13_ATTRIBUTE_SECRET, /* 12 */
- AJP13_ATTRIBUTE_STORED_METHOD, /* 13 */
- AJP13_ATTRIBUTE_ARE_DONE = 0xFF, /* 0xFF */
-} ajp13_attributes_t;
-
-/*
- * response headers
- */
-typedef enum {
- AJP13_RESP_CONTENT_TYPE = 0x01, /* 0x01 */
- AJP13_RESP_CONTENT_LANGUAGE, /* 0x02 */
- AJP13_RESP_CONTENT_LENGTH, /* 0x03 */
- AJP13_RESP_DATE, /* 0x04 */
- AJP13_RESP_LAST_MODIFIED, /* 0x05 */
- AJP13_RESP_LOCATION, /* 0x06 */
- AJP13_RESP_SET_COOKIE, /* 0x07 */
- AJP13_RESP_SET_COOKIE2, /* 0x08 */
- AJP13_RESP_SERVLET_ENGINE, /* 0x09 */
- AJP13_RESP_STATUS, /* 0x0A */
- AJP13_RESP_WWW_AUTHENTICATE, /* 0x0B */
-} ajp13_response_header_t;
-
-/*
- *
- */
-#define AJP13_COMMON_HEADER_CODE 0xA000
-
-/*
- * fixed header lengths.
- */
-#define AJP13_HEADER_LEN 4
-#define AJP13_FULL_HEADER_LEN 5
-
-#endif /* _AJP13_H */
-
diff --git a/src/array-static.h b/src/array-static.h
deleted file mode 100644
index fdeebf63..00000000
--- a/src/array-static.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _ARRAY_STATIC_H_
-#define _ARRAY_STATIC_H_
-
-/* define a generic array of <type>
- * */
-
-#define ARRAY_STATIC_DEF(name, type, extra) \
-typedef struct { \
- type **ptr; \
- size_t used; \
- size_t size; \
- extra\
-} name
-
-/* all append operations need a 'resize' for the +1 */
-
-#define ARRAY_STATIC_PREPARE_APPEND(a) \
- if (a->size == 0) { \
- a->size = 16; \
- a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
- } else if (a->size == a->used) { \
- a->size += 16; \
- a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
- }
-
-#define FOREACH(array, type, element, func) \
-do { size_t _i; for (_i = 0; _i < array->used; _i++) { type *element = array->ptr[_i]; func; } } while(0);
-
-#define STRUCT_INIT(type, var) \
- type *var;\
- var = calloc(1, sizeof(*var))
-
-#define ARRAY_STATIC_FREE(array, type, element, func) \
- FOREACH(array, type, element, func); \
- if(array->ptr) free(array->ptr); \
- array->ptr = NULL;
-
-#endif
diff --git a/src/array.c b/src/array.c
deleted file mode 100644
index 6d740f1a..00000000
--- a/src/array.c
+++ /dev/null
@@ -1,398 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include <errno.h>
-#include <assert.h>
-
-#include "array.h"
-#include "buffer.h"
-
-array *array_init(void) {
- array *a;
-
- a = calloc(1, sizeof(*a));
- assert(a);
-
- a->next_power_of_2 = 1;
-
- return a;
-}
-
-array *array_init_array(array *src) {
- size_t i;
- array *a = array_init();
-
- a->used = src->used;
- a->size = src->size;
- a->next_power_of_2 = src->next_power_of_2;
- a->unique_ndx = src->unique_ndx;
-
- a->data = malloc(sizeof(*src->data) * src->size);
- for (i = 0; i < src->size; i++) {
- if (src->data[i]) a->data[i] = src->data[i]->copy(src->data[i]);
- else a->data[i] = NULL;
- }
-
- a->sorted = malloc(sizeof(*src->sorted) * src->size);
- memcpy(a->sorted, src->sorted, sizeof(*src->sorted) * src->size);
- return a;
-}
-
-void array_free(array *a) {
- size_t i;
- if (!a) return;
-
- if (!a->is_weakref) {
- for (i = 0; i < a->size; i++) {
- if (a->data[i]) a->data[i]->free(a->data[i]);
- }
- }
-
- if (a->data) free(a->data);
- if (a->sorted) free(a->sorted);
-
- free(a);
-}
-
-void array_reset(array *a) {
- size_t i;
- if (!a) return;
-
- if (!a->is_weakref) {
- for (i = 0; i < a->used; i++) {
- a->data[i]->reset(a->data[i]);
- }
- }
-
- a->used = 0;
-}
-
-data_unset *array_pop(array *a) {
- data_unset *du;
-
- assert(a->used != 0);
-
- a->used --;
- du = a->data[a->used];
- a->data[a->used] = NULL;
-
- return du;
-}
-
-static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
- int ndx = -1;
- int i, pos = 0;
-
- if (key == NULL) return -1;
-
- /* try to find the string */
- for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
- int cmp;
-
- if (pos < 0) {
- pos += i;
- } else if (pos >= (int)a->used) {
- pos -= i;
- } else {
- cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
-
- if (cmp == 0) {
- /* found */
- ndx = a->sorted[pos];
- break;
- } else if (cmp < 0) {
- pos -= i;
- } else {
- pos += i;
- }
- }
- if (i == 0) break;
- }
-
- if (rndx) *rndx = pos;
-
- return ndx;
-}
-
-data_unset *array_get_element(array *a, const char *key, size_t keylen) {
- int ndx;
-
- if (-1 != (ndx = array_get_index(a, key, keylen + 1, NULL))) {
- /* found, leave here */
-
- return a->data[ndx];
- }
-
- return NULL;
-}
-
-data_unset *array_get_unused_element(array *a, data_type_t t) {
- data_unset *ds = NULL;
-
- UNUSED(t);
-
- if (a->size == 0) return NULL;
-
- if (a->used == a->size) return NULL;
-
- if (a->data[a->used]) {
- ds = a->data[a->used];
-
- a->data[a->used] = NULL;
- }
-
- return ds;
-}
-
-void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
- data_string *ds_dst;
-
- if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key, key_len))) {
- buffer_copy_string_len(ds_dst->value, value, val_len);
- return;
- }
-
- if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
- ds_dst = data_string_init();
- }
-
- buffer_copy_string_len(ds_dst->key, key, key_len);
- buffer_copy_string_len(ds_dst->value, value, val_len);
- array_insert_unique(hdrs, (data_unset *)ds_dst);
-}
-
-void array_append_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
- data_string *ds_dst;
-
- if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
- ds_dst = data_string_init();
- }
-
- buffer_copy_string_len(ds_dst->key, key, key_len);
- buffer_copy_string_len(ds_dst->value, value, val_len);
- array_insert_unique(hdrs, (data_unset *)ds_dst);
-}
-
-/* replace or insert data, return the old one with the same key */
-data_unset *array_replace(array *a, data_unset *du) {
- int ndx;
-
- if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
- array_insert_unique(a, du);
- return NULL;
- } else {
- data_unset *old = a->data[ndx];
- a->data[ndx] = du;
- return old;
- }
-}
-
-int array_insert_unique(array *a, data_unset *str) {
- int ndx = -1;
- int pos = 0;
- size_t j;
-
- /* generate unique index if necessary */
- if (str->key->used == 0 || str->is_index_key) {
- buffer_copy_long(str->key, a->unique_ndx++);
- str->is_index_key = 1;
- }
-
- /* try to find the string */
- if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
- /* found, leave here */
- if (a->data[ndx]->type == str->type) {
- str->insert_dup(a->data[ndx], str);
- } else {
- fprintf(stderr, "a\n");
- }
- return 0;
- }
-
- /* insert */
-
- if (a->used+1 > INT_MAX) {
- /* we can't handle more then INT_MAX entries: see array_get_index() */
- return -1;
- }
-
- if (a->size == 0) {
- a->size = 16;
- a->data = malloc(sizeof(*a->data) * a->size);
- a->sorted = malloc(sizeof(*a->sorted) * a->size);
- assert(a->data);
- 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);
- assert(a->data);
- assert(a->sorted);
- for (j = a->used; j < a->size; j++) a->data[j] = NULL;
- }
-
- ndx = (int) a->used;
-
- a->data[a->used++] = str;
-
- if (pos != ndx &&
- ((pos < 0) ||
- buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
- pos++;
- }
-
- /* move everything 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;
-
- if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
-
- return 0;
-}
-
-void array_print_indent(int depth) {
- int i;
- for (i = 0; i < depth; i ++) {
- fprintf(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 = strlen(du->key->ptr);
-
- 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:
- case TYPE_COUNT:
- 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->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, "# %zd\n", i);
- array_print_indent(depth + 1);
- }
- fprintf(stdout, "\"%s\"", du->key->ptr);
- for (j = maxlen - strlen(du->key->ptr); j > 0; j --) {
- fprintf(stdout, " ");
- }
- fprintf(stdout, " => ");
- }
- du->print(du, depth + 1);
- fprintf(stdout, ",\n");
- }
- if (!(i && (i - 1 % 5) == 0)) {
- array_print_indent(depth + 1);
- fprintf(stdout, "# %zd\n", i);
- }
- array_print_indent(depth);
- fprintf(stdout, ")");
-
- return 0;
-}
-
-#ifdef DEBUG_ARRAY
-int main (int argc, char **argv) {
- array *a;
- data_string *ds;
- data_count *dc;
-
- UNUSED(argc);
- UNUSED(argv);
-
- a = array_init();
-
- ds = data_string_init();
- buffer_copy_string_len(ds->key, CONST_STR_LEN("abc"));
- buffer_copy_string_len(ds->value, CONST_STR_LEN("alfrag"));
-
- array_insert_unique(a, (data_unset *)ds);
-
- ds = data_string_init();
- buffer_copy_string_len(ds->key, CONST_STR_LEN("abc"));
- buffer_copy_string_len(ds->value, CONST_STR_LEN("hameplman"));
-
- array_insert_unique(a, (data_unset *)ds);
-
- ds = data_string_init();
- buffer_copy_string_len(ds->key, CONST_STR_LEN("123"));
- buffer_copy_string_len(ds->value, CONST_STR_LEN("alfrag"));
-
- array_insert_unique(a, (data_unset *)ds);
-
- dc = data_count_init();
- buffer_copy_string_len(dc->key, CONST_STR_LEN("def"));
-
- array_insert_unique(a, (data_unset *)dc);
-
- dc = data_count_init();
- buffer_copy_string_len(dc->key, CONST_STR_LEN("def"));
-
- array_insert_unique(a, (data_unset *)dc);
-
- array_print(a, 0);
-
- array_free(a);
-
- fprintf(stderr, "%d\n",
- buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
-
- return 0;
-}
-#endif
diff --git a/src/array.h b/src/array.h
deleted file mode 100644
index 0fa73e87..00000000
--- a/src/array.h
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef ARRAY_H
-#define ARRAY_H
-
-#include "settings.h"
-
-#include <stdlib.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#ifdef HAVE_PCRE_H
-# include <pcre.h>
-#endif
-#include "buffer.h"
-
-#define DATA_IS_STRING(x) (x->type == TYPE_STRING)
-
-typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_COUNT, TYPE_ARRAY, TYPE_INTEGER, TYPE_FASTCGI, TYPE_CONFIG } data_type_t;
-#define DATA_UNSET \
- data_type_t type; \
- buffer *key; \
- int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
- struct data_unset *(*copy)(const struct data_unset *src); \
- void (* free)(struct data_unset *p); \
- void (* reset)(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 struct data_unset {
- DATA_UNSET;
-} data_unset;
-
-typedef struct {
- data_unset **data;
-
- size_t *sorted;
-
- size_t used;
- size_t size;
-
- size_t unique_ndx;
-
- size_t next_power_of_2;
- int is_weakref; /* data is weakref, don't bother the data */
-} array;
-
-typedef struct {
- DATA_UNSET;
-
- int count;
-} data_count;
-
-LI_API data_count* data_count_init(void);
-
-typedef struct {
- DATA_UNSET;
-
- buffer *value;
-} data_string;
-
-LI_API data_string* data_string_init(void);
-LI_API data_string* data_response_init(void);
-
-typedef struct {
- DATA_UNSET;
-
- array *value;
-} data_array;
-
-LI_API data_array* data_array_init(void);
-
-/**
- * possible compare ops in the configfile parser
- */
-typedef enum {
- CONFIG_COND_UNSET,
- CONFIG_COND_EQ, /** == */
- CONFIG_COND_MATCH, /** =~ */
- CONFIG_COND_NE, /** != */
- CONFIG_COND_NOMATCH /** !~ */
-} config_cond_t;
-
-/**
- * possible fields to match against
- */
-typedef enum {
- COMP_UNSET,
- COMP_SERVER_SOCKET,
- COMP_HTTP_URL,
- COMP_HTTP_HOST,
- COMP_HTTP_REFERER,
- COMP_HTTP_USER_AGENT,
- COMP_HTTP_COOKIE,
- COMP_HTTP_SCHEME,
- COMP_HTTP_REMOTE_IP,
- COMP_HTTP_QUERY_STRING,
- COMP_HTTP_REQUEST_METHOD,
- COMP_PHYSICAL_PATH,
- COMP_PHYSICAL_PATH_EXISTS,
-
- COMP_LAST_ELEMENT
-} comp_key_t;
-
-/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
- * for print: comp_key op string
- * for compare: comp cond string/regex
- */
-
-typedef struct _data_config data_config;
-struct _data_config {
- DATA_UNSET;
-
- array *value;
-
- buffer *comp_key;
- comp_key_t comp;
-
- config_cond_t cond;
- buffer *op;
-
- int context_ndx; /* more or less like an id */
- array *childs;
- /* nested */
- data_config *parent;
- /* for chaining only */
- data_config *prev;
- data_config *next;
-
- buffer *string;
-#ifdef HAVE_PCRE_H
- pcre *regex;
- pcre_extra *regex_study;
-#endif
-};
-
-LI_API data_config* data_config_init(void);
-
-typedef struct {
- DATA_UNSET;
-
- int value;
-} data_integer;
-
-LI_API data_integer* data_integer_init(void);
-LI_API array* array_init(void);
-LI_API array* array_init_array(array *a);
-LI_API void array_free(array *a);
-LI_API void array_reset(array *a);
-LI_API int array_insert_unique(array *a, data_unset *str);
-LI_API data_unset* array_pop(array *a);
-LI_API int array_print(array *a, int depth);
-LI_API data_unset* array_get_unused_element(array *a, data_type_t t);
-LI_API data_unset* array_get_element(array *a, const char *key, size_t key_len);
-LI_API void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
-LI_API void array_append_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
-LI_API data_unset* array_replace(array *a, data_unset *du);
-LI_API int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len);
-LI_API void array_print_indent(int depth);
-LI_API size_t array_get_max_key_length(array *a);
-
-#endif
diff --git a/src/base.h b/src/base.h
deleted file mode 100644
index a61a755a..00000000
--- a/src/base.h
+++ /dev/null
@@ -1,731 +0,0 @@
-#ifndef _BASE_H_
-#define _BASE_H_
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <limits.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-
-#include "settings.h"
-
-#ifdef HAVE_GLIB_H
-/* include glib.h before our buffer.h and array.h to make sure their parameter-names
- * don't clash with our type-names */
-#include <glib.h>
-#endif
-
-#include "buffer.h"
-#include "array.h"
-#include "chunk.h"
-#include "filter.h"
-#include "keyvalue.h"
-#include "settings.h"
-#include "fdevent.h"
-#include "sys-socket.h"
-#include "http_req.h"
-#include "etag.h"
-
-#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
-# define USE_OPENSSL
-# include <openssl/ssl.h>
-# if ! defined OPENSSL_NO_TLSEXT && ! defined SSL_CTRL_SET_TLSEXT_HOSTNAME
-# define OPENSSL_NO_TLSEXT
-# endif
-#endif
-
-#ifdef HAVE_SYS_INOTIFY_H
-# include <sys/inotify.h>
-#endif
-
-#ifdef USE_LINUX_AIO_SENDFILE
-# include <libaio.h>
-#endif
-
-#ifdef USE_POSIX_AIO
-# include <aio.h>
-#endif
-
-/** some compat */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-#ifndef SIZE_MAX
-# ifdef SIZE_T_MAX
-# define SIZE_MAX SIZE_T_MAX
-# else
-# define SIZE_MAX ((size_t)~0)
-# endif
-#endif
-
-#ifndef SSIZE_MAX
-# define SSIZE_MAX ((size_t)~0 >> 1)
-#endif
-
-#ifdef __APPLE__
-#include <crt_externs.h>
-#define environ (* _NSGetEnviron())
-#elif !defined(_WIN32)
-extern char **environ;
-#endif
-
-/* for solaris 2.5 and NetBSD 1.3.x */
-#ifndef HAVE_SOCKLEN_T
-typedef int socklen_t;
-#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 */
-typedef unsigned __int32 uint32_t;
-#endif
-
-
-#ifndef SHUT_WR
-# define SHUT_WR 1
-#endif
-
-#include "settings.h"
-
-typedef enum {
- TIME_CONNECTION_ACCEPT,
- TIME_REQUEST_START,
- TIME_BACKEND_CONNECT,
-
- TIME_BACKEND_SEND_HEADER_START,
- TIME_BACKEND_SEND_HEADER_END,
- TIME_BACKEND_SEND_CONTENT_START,
- TIME_BACKEND_SEND_CONTENT_END,
-
- TIME_BACKEND_RECV_HEADER_START,
- TIME_BACKEND_RECV_HEADER_END,
- TIME_BACKEND_RECV_CONTENT_START,
- TIME_BACKEND_RECV_CONTENT_END,
-
- TIME_BACKEND_DISCONNECT,
-
- TIME_SEND_HEADER_START,
- TIME_SEND_HEADER_END,
-
- TIME_SEND_CONTENT_START,
-
- TIME_SEND_ASYNC_READ_QUEUED, /* for async-io read */
- TIME_SEND_ASYNC_READ_START, /* for async-io read */
- TIME_SEND_ASYNC_READ_END, /* for async-io read */
- TIME_SEND_ASYNC_READ_END_QUEUED, /* for async-io read */
-
- TIME_SEND_WRITE_START,
- TIME_SEND_WRITE_END,
-
- TIME_SEND_CONTENT_END,
-
- TIME_REQUEST_END,
- TIME_CONNECTION_CLOSE,
-
- TIME_LAST_ELEMENT
-} connection_time_field_t;
-
-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;
-
-typedef enum { DIRECT, EXTERNAL } connection_type;
-
-typedef struct {
- char *key;
- connection_type type;
- char *value;
-} request_handler;
-
-typedef struct {
- char *key;
- char *host;
- unsigned short port;
- int used;
- short factor;
-} fcgi_connections;
-
-typedef struct {
- /** HEADER */
- /* the request-line */
- buffer *request;
- buffer *uri;
-
- buffer *orig_uri;
-
- http_method_t http_method;
- http_version_t http_version;
-
- buffer *http_host;
-
- array *headers;
-
- /* CONTENT */
- off_t content_length; /* returned by strtoul() */
-
- /* internal representation */
- int accept_encoding;
-
- /* internal */
- buffer *pathinfo;
-} request;
-
-typedef struct {
- off_t content_length;
- int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
-
- array *headers;
-
- enum {
- HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
- } transfer_encoding;
-} 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 {
- buffer *name;
- buffer *etag;
-
- struct stat st;
-
- time_t stat_ts;
-
- enum {
- STAT_CACHE_ENTRY_UNSET,
- STAT_CACHE_ENTRY_ASYNC_STAT,
- STAT_CACHE_ENTRY_STAT_FINISHED
- } state;
-
-#ifdef HAVE_LSTAT
- char is_symlink;
-#endif
-
-#if defined(HAVE_SYS_INOTIFY_H)
- int dir_version; /* when this entry was created the dir had this version */
- int dir_ndx;
-#endif
-
- buffer *content_type;
-} stat_cache_entry;
-
-typedef struct {
-#ifdef HAVE_GLIB_H
- GHashTable *files; /* a HashTable of stat_cache_entries for the files */
- GHashTable *dirs; /* a HashTable of stat_cache_entries for the dirs */
-#endif
-
- buffer *dir_name; /* for building the dirname from the filename */
- buffer *hash_key; /* tmp-buf for building the hash-key */
-
-#if defined(HAVE_SYS_INOTIFY_H)
- iosocket *sock; /* socket to the inotify fd (this should be in a backend struct */
-#endif
-} stat_cache;
-
-typedef struct {
- array *mimetypes;
-
- /* virtual-servers */
- buffer *document_root;
- buffer *server_name;
- buffer *error_handler;
- buffer *server_tag;
- buffer *dirlist_encoding;
- buffer *errorfile_prefix;
-
- unsigned short max_keep_alive_requests;
- unsigned short max_keep_alive_idle;
- unsigned short max_read_idle;
- unsigned short max_write_idle;
- unsigned short max_connection_idle;
- unsigned short use_xattr;
- unsigned short follow_symlink;
- unsigned short range_requests;
-
- /* debug */
-
- unsigned short log_file_not_found;
- unsigned short log_request_header;
- unsigned short log_request_handling;
- unsigned short log_response_header;
- unsigned short log_condition_handling;
- unsigned short log_condition_cache_handling;
- unsigned short log_ssl_noise;
- unsigned short log_timeouts;
-
-
- /* server wide */
- buffer *ssl_pemfile;
- buffer *ssl_ca_file;
- buffer *ssl_cipher_list;
- unsigned short ssl_use_sslv2;
- unsigned short ssl_verifyclient;
- unsigned short ssl_verifyclient_enforce;
- unsigned short ssl_verifyclient_depth;
- buffer *ssl_verifyclient_username;
- unsigned short ssl_verifyclient_export_cert;
-
- unsigned short use_ipv6;
- unsigned short is_ssl;
- unsigned short allow_http11;
- unsigned short etag_use_inode;
- unsigned short etag_use_mtime;
- unsigned short etag_use_size;
- unsigned short force_lowercase_filenames; /* if the FS is case-insensitive, force all files to lower-case */
- unsigned int max_request_size;
-
- unsigned short kbytes_per_second; /* connection kb/s limit */
-
- /* configside */
- unsigned short global_kbytes_per_second; /* */
-
- off_t global_bytes_per_second_cnt;
- /* server-wide traffic-shaper
- *
- * each context has the counter which is inited once
- * per 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 lose our "we are writable" signal
- * on the way.
- *
- */
- off_t *global_bytes_per_second_cnt_ptr; /* */
-
-#ifdef USE_OPENSSL
- SSL_CTX *ssl_ctx;
-#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, /** we are wait for a connect */
- CON_STATE_REQUEST_START, /** after the connect, the request is initialized, keep-alive starts here again */
- CON_STATE_READ_REQUEST_HEADER, /** loop in the read-request-header until the full header is received */
- CON_STATE_VALIDATE_REQUEST_HEADER, /** validate the request-header */
- CON_STATE_HANDLE_REQUEST_HEADER, /** find a handler for the request */
- CON_STATE_READ_REQUEST_CONTENT, /** forward the request content to the handler */
- CON_STATE_HANDLE_RESPONSE_HEADER, /** the backend bounces the response back to the client */
- CON_STATE_WRITE_RESPONSE_HEADER,
- CON_STATE_WRITE_RESPONSE_CONTENT,
- CON_STATE_RESPONSE_END,
- CON_STATE_ERROR,
- CON_STATE_CLOSE
-} connection_state_t;
-
-typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
-typedef struct {
- cond_result_t result;
- int patterncount;
- int matches[3 * 10];
- buffer *comp_value; /* just a pointer */
-
- comp_key_t comp_type;
-} cond_cache_t;
-
-typedef struct {
- connection_state_t state;
-
- /* timestamps */
- time_t read_idle_ts;
- time_t close_timeout_ts;
- time_t write_request_ts;
-
- time_t connection_start;
- time_t request_start;
-
- struct timeval start_tv;
-
- size_t request_count; /* number of requests handled in this connection */
- size_t loops_per_request; /* to catch endless loops in a single request
- *
- * used by mod_rewrite, mod_fastcgi, ... and others
- * this is self-protection
- */
-
- iosocket *sock;
- 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 others just disable */
- int keep_alive_idle; /* remember max_keep_alive_idle from config */
-
- int file_started;
-
- chunkqueue *send; /* the response-content before filters are applied */
- chunkqueue *recv; /* the request-content, without encoding */
-
- filter_chain *send_filters; /* the chain of filters to apply to response-content. */
- chunkqueue *send_raw; /* the full response (HTTP-Header + compression + chunking ) */
- chunkqueue *recv_raw; /* the full request (HTTP-Header + chunking ) */
-
- 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;
-
- http_req *http_req;
- request request;
- request_uri uri;
- physical physical;
- response response;
-
- size_t header_len;
-
- buffer *authed_user;
- array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
-
- /* response */
- int got_response;
-
- int in_joblist;
-
- connection_type mode;
-
- void **plugin_ctx; /* plugin connection specific config */
-
- specific_config conf; /* global connection specific config */
- cond_cache_t *cond_cache;
-
- buffer *server_name;
-
- /* error-handler */
- buffer *error_handler;
- int error_handler_saved_status;
- int in_error_handler;
-
- void *srv_socket; /* reference to the server-socket (typecast to server_socket) */
-
- /* etag handling */
- etag_flags_t etag_flags;
-
-
-#ifdef HAVE_GLIB_H
- GTimeVal timestamps[TIME_LAST_ELEMENT]; /**< used by timing.h */
-#endif
-
- int conditional_is_valid[COMP_LAST_ELEMENT];
-} connection;
-
-typedef struct {
- connection **ptr;
- size_t size;
- size_t used;
-} connections;
-
-
-#ifdef HAVE_IPV6
-typedef struct {
- int family;
- union {
- struct in6_addr ipv6;
- struct in_addr ipv4;
- } addr;
- char b2[INET6_ADDRSTRLEN + 1];
- time_t ts;
-} inet_ntop_cache_type;
-#endif
-
-
-typedef struct {
- buffer *uri;
- time_t mtime;
- int http_status;
-} realpath_cache_type;
-
-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 enum {
- NETWORK_STATUS_UNSET,
- NETWORK_STATUS_SUCCESS,
- NETWORK_STATUS_FATAL_ERROR,
- NETWORK_STATUS_CONNECTION_CLOSE,
- NETWORK_STATUS_WAIT_FOR_EVENT,
- NETWORK_STATUS_WAIT_FOR_AIO_EVENT,
- NETWORK_STATUS_WAIT_FOR_FD,
- NETWORK_STATUS_INTERRUPTED
-} network_status_t;
-
-typedef struct {
- unsigned short port;
- buffer *bindhost;
-
- unsigned short dont_daemonize;
- unsigned short daemonize_on_shutdown;
- buffer *changeroot;
- buffer *username;
- buffer *groupname;
-
- buffer *pid_file;
-
- buffer *event_handler;
-
- buffer *modules_dir;
- buffer *network_backend;
- array *modules;
- array *upload_tempdirs;
-
- unsigned short use_noatime;
-
- unsigned short max_worker;
- unsigned short max_fds;
- unsigned short max_conns;
- unsigned int max_request_size;
-
- unsigned short log_request_header_on_error;
- unsigned short log_state_handling;
- unsigned short log_timing;
-
- enum { STAT_CACHE_ENGINE_UNSET,
- STAT_CACHE_ENGINE_NONE,
- STAT_CACHE_ENGINE_SIMPLE,
- STAT_CACHE_ENGINE_FAM,
- STAT_CACHE_ENGINE_INOTIFY
- } stat_cache_engine;
- unsigned short enable_cores;
-
- buffer *errorlog_file;
- unsigned short errorlog_use_syslog;
- buffer *breakagelog_file;
-
- unsigned short max_stat_threads;
- unsigned short max_read_threads;
-} server_config;
-
-typedef enum {
- NETWORK_BACKEND_UNSET,
-
- NETWORK_BACKEND_WRITE,
- NETWORK_BACKEND_WRITEV,
-
- NETWORK_BACKEND_LINUX_SENDFILE,
- NETWORK_BACKEND_LINUX_AIO_SENDFILE,
- NETWORK_BACKEND_POSIX_AIO,
- NETWORK_BACKEND_GTHREAD_AIO,
- NETWORK_BACKEND_GTHREAD_SENDFILE,
- NETWORK_BACKEND_GTHREAD_FREEBSD_SENDFILE,
-
- NETWORK_BACKEND_FREEBSD_SENDFILE,
- NETWORK_BACKEND_SOLARIS_SENDFILEV,
-
- NETWORK_BACKEND_WIN32_SEND,
- NETWORK_BACKEND_WIN32_TRANSMITFILE,
-
-} network_backend_t;
-
-
-typedef struct {
- sock_addr addr;
- iosocket *sock;
-
- buffer *ssl_pemfile;
- buffer *ssl_ca_file;
- buffer *ssl_cipher_list;
- unsigned short ssl_use_sslv2;
- unsigned short use_ipv6;
- unsigned short is_ssl;
-
- buffer *srv_token;
-
-#ifdef USE_OPENSSL
- SSL_CTX *ssl_ctx;
-#endif
-} server_socket;
-
-typedef struct {
- server_socket **ptr;
-
- size_t size;
- size_t used;
-} server_socket_array;
-
-typedef struct server {
- server_socket_array srv_sockets;
-
- fdevents *ev, *ev_ins;
-
- buffer_plugin plugins;
- void *plugin_slots;
-
- /* counters */
- int con_opened;
- int con_read;
- int con_written;
- int con_closed;
-
- int ssl_is_init;
-
- int max_fds; /* max possible fds */
- int 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 */
-#ifdef HAVE_IPV6
- inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
-#endif
- mtime_cache_type mtime_cache[FILE_CACHE_MAX];
-
- array *split_vals;
-
- /* Timestamps */
- time_t cur_ts;
- time_t last_generated_date_ts;
- time_t last_generated_debug_ts;
- time_t startup_ts;
-
- char entropy[8]; /* from /dev/[u]random if possible, otherwise rand() */
- char is_real_entropy; /* whether entropy is from /dev/[u]random */
-
- buffer *ts_debug_str;
- buffer *ts_date_str;
-
- /* config-file */
- array *config;
- array *config_touched;
-
- array *config_context;
- specific_config **config_storage;
-
- server_config srvconf;
-
- short unsigned config_deprecated;
- short unsigned config_unsupported;
-
- connections *conns;
- connections *joblist;
- connections *joblist_prev;
- connections *fdwaitqueue;
-
- stat_cache *stat_cache;
-
- fdevent_handler_t event_handler;
-
- network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
- network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
-#ifdef USE_OPENSSL
- network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
- network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
-#endif
-
-#ifdef HAVE_PWD_H
- uid_t uid;
- gid_t gid;
-#endif
-#ifdef USE_GTHREAD
-#ifdef USE_LINUX_AIO_SENDFILE
- io_context_t linux_io_ctx;
-
- struct iocb *linux_io_iocbs;
-
-#endif
-#ifdef USE_POSIX_AIO
- struct aiocb *posix_aio_iocbs;
-#endif
-
- GAsyncQueue *stat_queue; /* send a stat_job into this queue and joblist_queue will get a wakeup when the stat is finished */
- GAsyncQueue *joblist_queue;
- GAsyncQueue *aio_write_queue;
-
- int did_wakeup;
- int wakeup_pipe[2];
- iosocket *wakeup_iosocket;
-#endif
- network_backend_t network_backend;
- int is_shutdown;
-} server;
-
-int server_out_of_fds(server *srv, connection *con);
-
-LI_EXPORT unsigned short sock_addr_get_port(sock_addr *addr); /* configfile-glue.c */
-
-#endif
diff --git a/src/bitset.c b/src/bitset.c
deleted file mode 100644
index 9e7e38b2..00000000
--- a/src/bitset.c
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "bitset.h"
-#include "buffer.h"
-#include "log.h"
-
-#define BITSET_BITS \
- ( CHAR_BIT * sizeof(size_t) )
-
-#define BITSET_MASK(pos) \
- ( ((size_t)1) << ((pos) % BITSET_BITS) )
-
-#define BITSET_WORD(set, pos) \
- ( (set)->bits[(pos) / BITSET_BITS] )
-
-#define BITSET_USED(nbits) \
- ( ((nbits) + (BITSET_BITS - 1)) / BITSET_BITS )
-
-bitset *bitset_init(size_t nbits) {
- bitset *set;
-
- set = malloc(sizeof(*set));
- assert(set);
-
- set->bits = calloc(BITSET_USED(nbits), sizeof(*set->bits));
- set->nbits = nbits;
-
- assert(set->bits);
-
- return set;
-}
-
-void bitset_reset(bitset *set) {
- memset(set->bits, 0, BITSET_USED(set->nbits) * sizeof(*set->bits));
-}
-
-void bitset_free(bitset *set) {
- free(set->bits);
- free(set);
-}
-
-void bitset_clear_bit(bitset *set, size_t pos) {
- if (pos >= set->nbits) {
- SEGFAULT("pos >= set->nbits: %zd >= %zd", pos, set->nbits);
- }
-
- BITSET_WORD(set, pos) &= ~BITSET_MASK(pos);
-}
-
-void bitset_set_bit(bitset *set, size_t pos) {
- if (pos >= set->nbits) {
- SEGFAULT("pos >= set->nbits: %zd >= %zd", pos, set->nbits);
- }
-
- BITSET_WORD(set, pos) |= BITSET_MASK(pos);
-}
-
-int bitset_test_bit(bitset *set, size_t pos) {
- if (pos >= set->nbits) {
- SEGFAULT("pos >= set->nbits: %zd >= %zd", pos, set->nbits);
- }
-
- return (BITSET_WORD(set, pos) & BITSET_MASK(pos)) != 0;
-}
-
diff --git a/src/bitset.h b/src/bitset.h
deleted file mode 100644
index 45f9a9d5..00000000
--- a/src/bitset.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _BITSET_H_
-#define _BITSET_H_
-
-#include <stddef.h>
-
-#include "settings.h"
-
-typedef struct {
- size_t *bits;
- size_t nbits;
-} bitset;
-
-LI_API bitset* bitset_init(size_t nbits);
-LI_API void bitset_reset(bitset *set);
-LI_API void bitset_free(bitset *set);
-
-LI_API void bitset_clear_bit(bitset *set, size_t pos);
-LI_API void bitset_set_bit(bitset *set, size_t pos);
-LI_API int bitset_test_bit(bitset *set, size_t pos);
-
-#endif
diff --git a/src/buffer.c b/src/buffer.c
deleted file mode 100644
index 7354bda5..00000000
--- a/src/buffer.c
+++ /dev/null
@@ -1,1169 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-
-#include <stdio.h>
-#include <assert.h>
-#include <ctype.h>
-
-#include "buffer.h"
-
-
-static const char hex_chars[] = "0123456789abcdef";
-
-
-/**
- * init the buffer
- *
- */
-
-buffer* buffer_init(void) {
- buffer *b;
-
- b = malloc(sizeof(*b));
- assert(b);
-
- b->ptr = NULL;
- b->size = 0;
- b->used = 0;
-
- return b;
-}
-
-buffer *buffer_init_buffer(buffer *src) {
- buffer *b = buffer_init();
- buffer_copy_string_buffer(b, src);
- return b;
-}
-
-/**
- * free the buffer
- *
- */
-
-void buffer_free(buffer *b) {
- if (!b) return;
-
- free(b->ptr);
- free(b);
-}
-
-void buffer_reset(buffer *b) {
- if (!b) return;
-
- /* limit don't reuse buffer larger than ... bytes */
- if (b->size > BUFFER_MAX_REUSE_SIZE) {
- free(b->ptr);
- b->ptr = NULL;
- b->size = 0;
- } else if (b->size) {
- b->ptr[0] = '\0';
- }
-
- b->used = 0;
-}
-
-
-/**
- *
- * allocate (if necessary) enough space for 'size' (+1, if 'size' > 0) bytes and
- * set the 'used' counter to 0
- *
- */
-
-#define BUFFER_PIECE_SIZE 64
-
-int buffer_prepare_copy(buffer *b, size_t size) {
- if (!b) return -1;
-
- if ((0 == b->size) ||
- (size >= b->size)) {
- if (b->size) free(b->ptr);
-
- b->size = size;
-
- /* always allocate a multiple of BUFFER_PIECE_SIZE */
- /* adds a least 1 byte */
- b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
-
- b->ptr = malloc(b->size);
- assert(b->ptr);
- }
- b->used = 0;
- return 0;
-}
-
-/**
- *
- * increase the internal buffer (if necessary) to append another 'size' byte
- * ->used isn't changed
- *
- */
-
-int buffer_prepare_append(buffer *b, size_t size) {
- if (!b) return -1;
-
- if (0 == b->size) {
- b->size = size;
-
- /* always allocate a multiple of BUFFER_PIECE_SIZE */
- b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
-
- b->ptr = malloc(b->size);
- b->used = 0;
- assert(b->ptr);
- } else if (b->used + size >= b->size) {
- b->size += size;
-
- /* always allocate a multiple of BUFFER_PIECE_SIZE */
- b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
-
- b->ptr = realloc(b->ptr, b->size);
- assert(b->ptr);
- }
- return 0;
-}
-
-int buffer_copy_string(buffer *b, const char *s) {
- size_t s_len;
-
- if (!s || !b) return -1;
-
- s_len = strlen(s) + 1;
- buffer_prepare_copy(b, s_len);
-
- memcpy(b->ptr, s, s_len);
- b->used = s_len;
-
- return 0;
-}
-
-int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
- if (!s || !b) return -1;
-#if 0
- /* removed optimization as we have to keep the empty string
- * in some cases for the config handling
- *
- * url.access-deny = ( "" )
- */
- if (s_len == 0) return 0;
-#endif
- buffer_prepare_copy(b, s_len + 1);
-
- memcpy(b->ptr, s, s_len);
- b->ptr[s_len] = '\0';
- b->used = s_len + 1;
-
- return 0;
-}
-
-int buffer_copy_string_buffer(buffer *b, const buffer *src) {
- if (!src) return -1;
-
- if (src->used == 0) {
- buffer_reset(b);
- return 0;
- }
- return buffer_copy_string_len(b, src->ptr, src->used - 1);
-}
-
-int buffer_append_string(buffer *b, const char *s) {
- size_t s_len;
-
- if (!s || !b) return -1;
-
- s_len = strlen(s);
- buffer_prepare_append(b, s_len + 1);
- if (b->used == 0)
- b->used++;
-
- memcpy(b->ptr + b->used - 1, s, s_len + 1);
- b->used += s_len;
-
- return 0;
-}
-
-int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
- size_t s_len;
-
- if (!s || !b) return -1;
-
- s_len = strlen(s);
- if (s_len > maxlen) s_len = maxlen;
- buffer_prepare_append(b, maxlen + 1);
- if (b->used == 0)
- b->used++;
-
- memcpy(b->ptr + b->used - 1, s, s_len);
- if (maxlen > s_len) {
- memset(b->ptr + b->used - 1 + s_len, ' ', maxlen - s_len);
- }
-
- b->used += maxlen;
- b->ptr[b->used - 1] = '\0';
- return 0;
-}
-
-/**
- * append a string to the end of the buffer
- *
- * the resulting buffer is terminated with a '\0'
- * s is treated as an un-terminated string (a \0 is handled as a normal character)
- *
- * @param b a buffer
- * @param s the string
- * @param s_len size of the string (without the terminating \0)
- */
-
-int buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
- if (!s || !b) return -1;
- if (s_len == 0) return 0;
-
- buffer_prepare_append(b, s_len + 1);
- if (b->used == 0)
- b->used++;
-
- memcpy(b->ptr + b->used - 1, s, s_len);
- b->used += s_len;
- b->ptr[b->used - 1] = '\0';
-
- return 0;
-}
-
-int buffer_append_string_buffer(buffer *b, const buffer *src) {
- if (!src) return -1;
- if (src->used == 0) return 0;
-
- return buffer_append_string_len(b, src->ptr, src->used - 1);
-}
-
-int buffer_append_memory(buffer *b, const char *s, size_t s_len) {
- if (!s || !b) return -1;
- if (s_len == 0) return 0;
-
- buffer_prepare_append(b, s_len);
- memcpy(b->ptr + b->used, s, s_len);
- b->used += s_len;
-
- return 0;
-}
-
-int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
- if (!s || !b) return -1;
-
- b->used = 0;
-
- return buffer_append_memory(b, s, s_len);
-}
-
-int buffer_append_long_hex(buffer *b, unsigned long value) {
- char *buf;
- int shift = 0;
- unsigned long copy = value;
-
- while (copy) {
- copy >>= 4;
- shift++;
- }
- if (shift == 0)
- shift++;
- if (shift & 0x01)
- shift++;
-
- buffer_prepare_append(b, shift + 1);
- if (b->used == 0)
- b->used++;
- buf = b->ptr + (b->used - 1);
- b->used += shift;
-
- shift <<= 2;
- while (shift > 0) {
- shift -= 4;
- *(buf++) = hex_chars[(value >> shift) & 0x0F];
- }
- *buf = '\0';
-
- return 0;
-}
-
-int LI_ltostr(char *buf, long val) {
- char swap;
- char *end;
- int len = 1;
-
- if (val < 0) {
- len++;
- *(buf++) = '-';
- val = -val;
- }
-
- end = buf;
- while (val > 9) {
- *(end++) = '0' + (val % 10);
- val = val / 10;
- }
- *(end) = '0' + val;
- *(end + 1) = '\0';
- len += end - buf;
-
- while (buf < end) {
- swap = *end;
- *end = *buf;
- *buf = swap;
-
- buf++;
- end--;
- }
-
- return len;
-}
-
-int buffer_append_long(buffer *b, long val) {
- if (!b) return -1;
-
- buffer_prepare_append(b, 32);
- if (b->used == 0)
- b->used++;
-
- b->used += LI_ltostr(b->ptr + (b->used - 1), val);
- return 0;
-}
-
-int buffer_copy_long(buffer *b, long val) {
- if (!b) return -1;
-
- b->used = 0;
- return buffer_append_long(b, val);
-}
-
-#if !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T)
-int buffer_append_off_t(buffer *b, off_t val) {
- char swap;
- char *end;
- char *start;
- int len = 1;
-
- if (!b) return -1;
-
- buffer_prepare_append(b, 32);
- if (b->used == 0)
- b->used++;
-
- start = b->ptr + (b->used - 1);
- if (val < 0) {
- len++;
- *(start++) = '-';
- val = -val;
- }
-
- end = start;
- while (val > 9) {
- *(end++) = '0' + (val % 10);
- val = val / 10;
- }
- *(end) = '0' + val;
- *(end + 1) = '\0';
- len += end - start;
-
- while (start < end) {
- swap = *end;
- *end = *start;
- *start = swap;
-
- start++;
- end--;
- }
-
- b->used += len;
- return 0;
-}
-
-int buffer_copy_off_t(buffer *b, off_t val) {
- if (!b) return -1;
-
- b->used = 0;
- return buffer_append_off_t(b, val);
-}
-#endif /* !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T) */
-
-char int2hex(char c) {
- return hex_chars[(c & 0x0F)];
-}
-
-/* converts hex char (0-9, A-Z, a-z) to decimal.
- * returns 0xFF on invalid input.
- */
-char hex2int(unsigned char hex) {
- hex = hex - '0';
- if (hex > 9) {
- hex = (hex + '0' - 1) | 0x20;
- hex = hex - 'a' + 11;
- }
- if (hex > 15)
- hex = 0xFF;
-
- return hex;
-}
-
-
-/**
- * init the ptr buffer
- *
- */
-buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
-{
- buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
- l->free = freer;
-
- return l;
-}
-
-/**
- * free the buffer_array
- *
- */
-void buffer_ptr_free(buffer_ptr *l)
-{
- if (NULL != l) {
- buffer_ptr_clear(l);
- free(l);
- }
-}
-
-void buffer_ptr_clear(buffer_ptr *l)
-{
- assert(NULL != l);
-
- if (l->free && l->used) {
- size_t i;
- for (i = 0; i < l->used; i ++) {
- l->free(l->ptr[i]);
- }
- }
-
- if (l->ptr) {
- free(l->ptr);
- l->ptr = NULL;
- }
- l->used = 0;
- l->size = 0;
-}
-
-void buffer_ptr_append(buffer_ptr* l, void *item)
-{
- assert(NULL != l);
- if (l->ptr == NULL) {
- l->size = 16;
- l->ptr = (void **)malloc(sizeof(void *) * l->size);
- }
- else if (l->used == l->size) {
- l->size += 16;
- l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
- }
- l->ptr[l->used++] = item;
-}
-
-void *buffer_ptr_pop(buffer_ptr* l)
-{
- assert(NULL != l && l->used > 0);
- return l->ptr[--l->used];
-}
-
-void *buffer_ptr_top(buffer_ptr* l)
-{
- assert(NULL != l && l->used > 0);
- return l->ptr[l->used-1];
-}
-
-/**
- * init the buffer
- *
- */
-
-buffer_array* buffer_array_init(void) {
- buffer_array *b;
-
- b = malloc(sizeof(*b));
-
- assert(b);
- b->ptr = NULL;
- b->size = 0;
- b->used = 0;
-
- return b;
-}
-
-void buffer_array_reset(buffer_array *b) {
- size_t i;
-
- if (!b) return;
-
- /* if they are too large, reduce them */
- for (i = 0; i < b->used; i++) {
- buffer_reset(b->ptr[i]);
- }
-
- b->used = 0;
-}
-
-
-/**
- * free the buffer_array
- *
- */
-
-void buffer_array_free(buffer_array *b) {
- size_t i;
- if (!b) return;
-
- for (i = 0; i < b->size; i++) {
- if (b->ptr[i]) buffer_free(b->ptr[i]);
- }
- free(b->ptr);
- free(b);
-}
-
-buffer *buffer_array_append_get_buffer(buffer_array *b) {
- size_t i;
-
- if (b->size == 0) {
- b->size = 16;
- b->ptr = malloc(sizeof(*b->ptr) * b->size);
- assert(b->ptr);
- for (i = 0; i < b->size; i++) {
- b->ptr[i] = NULL;
- }
- } else if (b->size == b->used) {
- b->size += 16;
- b->ptr = realloc(b->ptr, sizeof(*b->ptr) * b->size);
- assert(b->ptr);
- for (i = b->used; i < b->size; i++) {
- b->ptr[i] = NULL;
- }
- }
-
- if (b->ptr[b->used] == NULL) {
- b->ptr[b->used] = buffer_init();
- }
-
- b->ptr[b->used]->used = 0;
-
- return b->ptr[b->used++];
-}
-
-
-char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
- size_t i;
- if (len == 0) return NULL;
- if (needle == NULL) return NULL;
-
- if (b->used < len) return NULL;
-
- for(i = 0; i < b->used - len; i++) {
- if (0 == memcmp(b->ptr + i, needle, len)) {
- return b->ptr + i;
- }
- }
-
- return NULL;
-}
-
-buffer *buffer_init_string(const char *str) {
- buffer *b = buffer_init();
-
- buffer_copy_string(b, str);
-
- return b;
-}
-
-int buffer_is_empty(buffer *b) {
- if (!b) return 1;
-
- return (b->used == 0);
-}
-
-/**
- * check if two buffers contain the same data
- *
- * HISTORY: this function was pretty much optimized, but didn't handled
- * alignment properly.
- */
-
-int buffer_is_equal(buffer *a, buffer *b) {
- if (a->used != b->used) return 0;
- if (a->used == 0) return 1;
-
- return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
-}
-
-int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
- buffer b;
-
- b.ptr = (char *)s;
- b.used = b_len + 1;
-
- return buffer_is_equal(a, &b);
-}
-
-/* simple-assumption:
- *
- * most parts are equal and doing a case conversion takes time
- *
- */
-int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
- size_t ndx = 0, max_ndx;
- size_t *al, *bl;
- size_t mask = sizeof(*al) - 1;
-
- al = (size_t *)a;
- bl = (size_t *)b;
-
- /* is the alignment correct? */
- if ( ((size_t)al & mask) == 0 &&
- ((size_t)bl & mask) == 0 ) {
-
- max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
-
- for (; ndx < max_ndx; ndx += sizeof(*al)) {
- if (*al != *bl) break;
- al++; bl++;
-
- }
-
- }
-
- a = (char *)al;
- b = (char *)bl;
-
- max_ndx = ((a_len < b_len) ? a_len : b_len);
-
- for (; ndx < max_ndx; ndx++) {
- int a1 = *a++, b1 = *b++;
-
- if (a1 != b1) {
- /* always lowercase for transitive results */
- if (a1 >= 'A' && a1 <= 'Z') a1 |= 32;
- if (b1 >= 'A' && b1 <= 'Z') b1 |= 32;
-
- if ((a1 - b1) != 0) return (a1 - b1);
- }
- }
-
- /* all chars are the same, and the length match too
- *
- * they are the same */
- if (a_len == b_len) return 0;
-
- /* if a is shorter then b, then b is larger */
- return (a_len - b_len);
-}
-
-
-/**
- * check if the rightmost bytes of the string are equal.
- *
- *
- */
-
-int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
- /* no, len -> equal */
- if (len == 0) return 1;
-
- /* len > 0, but empty buffers -> not equal */
- if (b1->used == 0 || b2->used == 0) return 0;
-
- /* buffers too small -> not equal */
- if (b1->used - 1 < len || b2->used - 1 < len) return 0;
-
- if (0 == strncmp(b1->ptr + b1->used - 1 - len,
- b2->ptr + b2->used - 1 - len, len)) {
- return 1;
- }
-
- return 0;
-}
-
-int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
- size_t i;
-
- /* BO protection */
- if (in_len * 2 < in_len) return -1;
-
- buffer_prepare_copy(b, in_len * 2 + 1);
-
- for (i = 0; i < in_len; i++) {
- b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
- b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
- }
- b->ptr[b->used++] = '\0';
-
- return 0;
-}
-
-/* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
-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, 1, 1, /* 70 - 7F { | } ~ DEL */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
- 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 */
-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, 1, 1, /* 70 - 7F { | } ~ DEL */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
- 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 */
-};
-
-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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 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 */
-};
-
-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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 */
-};
-
-const char encoded_chars_hex[] = {
- /*
- 0 1 2 3 4 5 6 7 8 9 A B C D E F
- */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
- 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 */
-};
-
-
-int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
- unsigned char *ds, *d;
- size_t d_len, ndx;
- const char *map = NULL;
-
- if (!s || !b) return -1;
- if (b->used == 0) return -1;
-
- if (b->ptr[b->used - 1] != '\0') return -1;
-
- if (s_len == 0) return 0;
-
- 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;
- case ENCODING_HEX:
- map = encoded_chars_hex;
- break;
- case ENCODING_UNSET:
- return buffer_append_string_len(b, s, s_len);
- }
-
- assert(map != NULL);
-
- /* count to-be-encoded characters */
- for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
- if (map[*ds]) {
- 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;
- case ENCODING_HEX:
- d_len += 2;
- break;
- case ENCODING_UNSET:
- break;
- }
- } else {
- d_len ++;
- }
- }
-
- buffer_prepare_append(b, d_len);
-
- for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
- if (map[*ds]) {
- switch(encoding) {
- case ENCODING_REL_URI:
- case ENCODING_REL_URI_PART:
- d[d_len++] = '%';
- d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
- d[d_len++] = hex_chars[(*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[((*ds) >> 4) & 0x0F];
- d[d_len++] = hex_chars[(*ds) & 0x0F];
- d[d_len++] = ';';
- break;
- case ENCODING_HEX:
- d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
- d[d_len++] = hex_chars[(*ds) & 0x0F];
- break;
- case ENCODING_UNSET:
- break;
- }
- } else {
- d[d_len++] = *ds;
- }
- }
-
- /* terminate buffer and calculate new length */
- b->ptr[b->used + d_len - 1] = '\0';
-
- b->used += d_len;
-
- return 0;
-}
-
-
-/* decodes url-special chars in-place.
- * replaces non-printable characters with '_'
- */
-
-static int buffer_urldecode_internal(buffer *url, int is_query) {
- unsigned char high, low;
- const char *src;
- char *dst;
-
- if (!url || !url->ptr) return -1;
-
- src = (const char*) url->ptr;
- dst = (char*) url->ptr;
-
- while ((*src) != '\0') {
- if (is_query && *src == '+') {
- *dst = ' ';
- } else if (*src == '%') {
- *dst = '%';
-
- high = hex2int(*(src + 1));
- if (high != 0xFF) {
- low = hex2int(*(src + 2));
- if (low != 0xFF) {
- high = (high << 4) | low;
-
- /* map out control characters */
- if (high < 32 || high == 127) high = '_';
-
- *dst = high;
- src += 2;
- }
- }
- } else {
- *dst = *src;
- }
-
- dst++;
- src++;
- }
-
- *dst = '\0';
- url->used = (dst - url->ptr) + 1;
-
- return 0;
-}
-
-int buffer_urldecode_path(buffer *url) {
- return buffer_urldecode_internal(url, 0);
-}
-
-int buffer_urldecode_query(buffer *url) {
- return buffer_urldecode_internal(url, 1);
-}
-
-/* Remove "/../", "//", "/./" parts from path.
- *
- * /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.
- */
-
-int buffer_path_simplify(buffer *dest, buffer *src)
-{
- int toklen;
- char c, pre1;
- char *start, *slash, *walk, *out;
- unsigned short pre;
-
- if (src == NULL || src->ptr == NULL || dest == NULL)
- return -1;
-
- if (src == dest)
- buffer_prepare_append(dest, 1);
- else
- buffer_prepare_copy(dest, src->used + 1);
-
- walk = src->ptr;
- start = dest->ptr;
- out = dest->ptr;
- slash = dest->ptr;
- while (*walk == ' ') {
- walk++;
- }
-
- pre1 = *(walk++);
- c = *(walk++);
- pre = pre1;
- if (pre1 != '/') {
- pre = ('/' << 8) | pre1;
- *(out++) = '/';
- }
- *(out++) = pre1;
-
- if (pre1 == '\0') {
- dest->used = (out - start) + 1;
- return 0;
- }
-
- while (1) {
- if (c == '/' || c == '\0') {
- toklen = out - slash;
- if (toklen == 3 && pre == (('.' << 8) | '.')) {
- out = slash;
- if (out > start) {
- out--;
- while (out > start && *out != '/') {
- out--;
- }
- }
-
- if (c == '\0')
- out++;
- } else if (toklen == 1 || pre == (('/' << 8) | '.')) {
- out = slash;
- if (c == '\0')
- out++;
- }
-
- slash = out;
- }
-
- if (c == '\0')
- break;
-
- pre1 = c;
- pre = (pre << 8) | pre1;
- c = *walk;
- *out = pre1;
-
- out++;
- walk++;
- }
-
- *out = '\0';
- dest->used = (out - start) + 1;
-
- return 0;
-}
-
-int light_isdigit(int c) {
- return (c >= '0' && c <= '9');
-}
-
-int light_isxdigit(int c) {
- if (light_isdigit(c)) return 1;
-
- c |= 32;
- return (c >= 'a' && c <= 'f');
-}
-
-int light_isalpha(int c) {
- c |= 32;
- return (c >= 'a' && c <= 'z');
-}
-
-int light_isalnum(int c) {
- return light_isdigit(c) || light_isalpha(c);
-}
-
-#undef BUFFER_CTYPE_FUNC
-#define BUFFER_CTYPE_FUNC(type) \
- int buffer_is##type(buffer *b) { \
- size_t i, len; \
- if (b->used < 2) return 0; \
- /* strlen */ \
- len = b->used - 1; \
- /* c-string only */ \
- if (b->ptr[len] != '\0') { \
- return 0; \
- } \
- /* check on the whole string */ \
- for (i = 0; i < len; i ++) { \
- if (!light_is##type(b->ptr[i])) { \
- return 0; \
- } \
- } \
- return 1; \
- }
-
-BUFFER_CTYPE_FUNC(digit)
-BUFFER_CTYPE_FUNC(xdigit)
-BUFFER_CTYPE_FUNC(alpha)
-BUFFER_CTYPE_FUNC(alnum)
-
-int buffer_to_lower(buffer *b) {
- char *c;
-
- if (b->used == 0) return 0;
-
- for (c = b->ptr; *c; c++) {
- if (*c >= 'A' && *c <= 'Z') {
- *c |= 32;
- }
- }
-
- return 0;
-}
-
-
-int buffer_to_upper(buffer *b) {
- char *c;
-
- if (b->used == 0) return 0;
-
- for (c = b->ptr; *c; c++) {
- if (*c >= 'a' && *c <= 'z') {
- *c &= ~32;
- }
- }
-
- return 0;
-}
-
-buffer_pool *buffer_pool_init() {
- buffer_pool *bp;
-
- bp = calloc(1, sizeof(*bp));
-
- return bp;
-}
-
-void buffer_pool_free(buffer_pool *bp) {
- if (!bp) return;
-
- ARRAY_STATIC_FREE(bp, buffer, b, buffer_free(b));
-
- free(bp);
-
- return;
-}
-
-buffer *buffer_pool_get(buffer_pool *bp) {
- buffer *b;
-
- if (bp->used == 0) {
- return buffer_init();
- }
-
- b = bp->ptr[--bp->used];
-
- buffer_reset(b);
-
- return b;
-}
-
-void buffer_pool_append(buffer_pool *bp, buffer *b) {
- ARRAY_STATIC_PREPARE_APPEND(bp);
-
- bp->ptr[bp->used++] = b;
-}
-
-
diff --git a/src/buffer.h b/src/buffer.h
deleted file mode 100644
index 16d05601..00000000
--- a/src/buffer.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef _BUFFER_H_
-#define _BUFFER_H_
-
-#include "settings.h"
-
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include "array-static.h"
-
-typedef struct {
- char *ptr;
-
- size_t used;
- size_t size;
-} buffer;
-
-typedef void (*buffer_ptr_free_t)(void *p);
-
-typedef struct {
- void **ptr;
- size_t size;
- size_t used;
- buffer_ptr_free_t free;
-} buffer_ptr;
-
-typedef struct {
- buffer **ptr;
-
- size_t used;
- size_t size;
-} buffer_array;
-
-typedef struct {
- char *ptr;
-
- size_t offset; /* input pointer */
-
- size_t used; /* output pointer */
- size_t size;
-} read_buffer;
-
-LI_API buffer_ptr* buffer_ptr_init(buffer_ptr_free_t freer);
-LI_API void buffer_ptr_free(buffer_ptr *b);
-LI_API void buffer_ptr_clear(buffer_ptr *b);
-LI_API void buffer_ptr_append(buffer_ptr *b, void *item);
-LI_API void* buffer_ptr_pop(buffer_ptr *b);
-LI_API void* buffer_ptr_top(buffer_ptr *b);
-
-LI_API buffer_array* buffer_array_init(void);
-LI_API void buffer_array_free(buffer_array *b);
-LI_API void buffer_array_reset(buffer_array *b);
-LI_API buffer* buffer_array_append_get_buffer(buffer_array *b);
-
-LI_API buffer* buffer_init(void);
-LI_API buffer* buffer_init_buffer(buffer *b);
-LI_API buffer* buffer_init_string(const char *str);
-LI_API void buffer_free(buffer *b);
-LI_API void buffer_reset(buffer *b);
-
-LI_API int buffer_prepare_copy(buffer *b, size_t size);
-LI_API int buffer_prepare_append(buffer *b, size_t size);
-
-LI_API int buffer_copy_string(buffer *b, const char *s);
-LI_API int buffer_copy_string_len(buffer *b, const char *s, size_t s_len);
-LI_API int buffer_copy_string_buffer(buffer *b, const buffer *src);
-LI_API int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len);
-
-LI_API int buffer_copy_long(buffer *b, long val);
-
-LI_API int buffer_copy_memory(buffer *b, const char *s, size_t s_len);
-
-LI_API int buffer_append_string(buffer *b, const char *s);
-LI_API int buffer_append_string_len(buffer *b, const char *s, size_t s_len);
-LI_API int buffer_append_string_buffer(buffer *b, const buffer *src);
-LI_API int buffer_append_string_lfill(buffer *b, const char *s, size_t maxlen);
-LI_API int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen);
-
-LI_API int buffer_append_long_hex(buffer *b, unsigned long len);
-LI_API int buffer_append_long(buffer *b, long val);
-
-#if defined(SIZEOF_LONG) && (SIZEOF_LONG == SIZEOF_OFF_T)
-#define buffer_copy_off_t(x, y) buffer_copy_long(x, y)
-#define buffer_append_off_t(x, y) buffer_append_long(x, y)
-#else
-LI_API int buffer_copy_off_t(buffer *b, off_t val);
-LI_API int buffer_append_off_t(buffer *b, off_t val);
-#endif
-
-LI_API int buffer_append_memory(buffer *b, const char *s, size_t s_len);
-
-LI_API char* buffer_search_string_len(buffer *b, const char *needle, size_t len);
-
-LI_API int buffer_is_empty(buffer *b);
-LI_API int buffer_is_equal(buffer *a, buffer *b);
-LI_API int buffer_is_equal_right_len(buffer *a, buffer *b, size_t len);
-LI_API int buffer_is_equal_string(buffer *a, const char *s, size_t b_len);
-LI_API int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len);
-
-typedef enum {
- ENCODING_UNSET,
- ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
- ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
- ENCODING_HTML, /* "&" becomes "&amp;" and so on */
- ENCODING_MINIMAL_XML, /* minimal encoding for xml */
- ENCODING_HEX /* encode string as hex */
-} buffer_encoding_t;
-
-LI_API int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
-
-LI_API int buffer_urldecode_path(buffer *url);
-LI_API int buffer_urldecode_query(buffer *url);
-LI_API int buffer_path_simplify(buffer *dest, buffer *src);
-
-LI_API int buffer_to_lower(buffer *b);
-LI_API int buffer_to_upper(buffer *b);
-
-/** deprecated */
-LI_API int LI_ltostr(char *buf, long val);
-LI_API char hex2int(unsigned char c);
-LI_API char int2hex(char i);
-
-LI_API int light_isdigit(int c);
-LI_API int light_isxdigit(int c);
-LI_API int light_isalpha(int c);
-LI_API int light_isalnum(int c);
-
-#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
-BUFFER_CTYPE_FUNC(digit)
-BUFFER_CTYPE_FUNC(xdigit)
-BUFFER_CTYPE_FUNC(alpha)
-BUFFER_CTYPE_FUNC(alnum)
-
-#define BUF_STR(x) x->ptr
-#define BUF_STR_LEN(x) (x->used ? x->used - 1 : 0)
-
-/* used on solaris as their vprintf() hates NULL for %s */
-#define SAFE_BUF_STR(x) x && x->ptr ? x->ptr : "(null)"
-
-#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) BUF_STR(x), x->used ? x->used - 1 : 0
-
-
-#define UNUSED(x) ( (void)(x) )
-
-/**
- * a pool of unused buffer *
- */
-
-ARRAY_STATIC_DEF(buffer_pool, buffer, );
-
-buffer_pool* buffer_pool_init();
-void buffer_pool_free(buffer_pool* );
-
-buffer *buffer_pool_get(buffer_pool *bp);
-void buffer_pool_append(buffer_pool *bp, buffer *);
-
-#endif
-
-
diff --git a/src/chunk.c b/src/chunk.c
deleted file mode 100644
index a5742e51..00000000
--- a/src/chunk.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/**
- * the network chunk-API
- *
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <fcntl.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-
-#include "chunk.h"
-
-#include "sys-mmap.h"
-#include "sys-files.h"
-
-#include "log.h"
-
-/**
- * create a global pool for unused chunks
- *
- * the chunk is moved from queue to queue (by stealing)
- * and moved back into the unused pool.
- *
- * Instead of having a local pool of unused chunks per queue
- * we use a global pool
- *
- */
-
-static chunk *chunkpool = NULL;
-static size_t chunkpool_chunks = 0;
-
-chunkqueue *chunkqueue_init(void) {
- chunkqueue *cq;
-
- cq = calloc(1, sizeof(*cq));
-
- cq->first = NULL;
- cq->last = NULL;
-
- return cq;
-}
-
-static chunk *chunk_init(void) {
- chunk *c;
-
- c = calloc(1, sizeof(*c));
-
- c->mem = buffer_init();
- c->file.name = buffer_init();
- c->file.fd = -1;
- c->file.copy.fd = -1;
- c->file.mmap.start = MAP_FAILED;
- c->next = NULL;
-
- c->async.written = -1;
-
- return c;
-}
-
-static void chunk_reset(chunk *c) {
- if (!c) return;
-
- buffer_reset(c->mem);
-
- if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
- unlink(c->file.name->ptr);
- }
- c->file.is_temp = 0;
-
- buffer_reset(c->file.name);
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
-
- if (c->file.copy.fd != -1) {
- close(c->file.copy.fd);
- c->file.copy.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.length = 0;
- c->file.start = 0;
-
- c->file.mmap.length = 0;
- c->file.mmap.offset = 0;
-
- c->file.copy.length = 0;
- c->file.copy.offset = 0;
-
- c->async.written = -1;
- c->async.ret_val = 0;
-
- c->offset = 0;
- c->next = NULL;
-}
-
-static void chunk_free(chunk *c) {
- if (!c) return;
-
- /* make sure fd's are closed and tempfile's are deleted. */
- chunk_reset(c);
-
- buffer_free(c->mem);
- buffer_free(c->file.name);
-
- free(c);
-}
-
-/**
- * mark the chunk as done
- *
- * @param c chunk to set done
- * @return 1 if done, 0 if not
- */
-void chunk_set_done(chunk *c) {
- switch (c->type) {
- case MEM_CHUNK:
- c->offset = c->mem->used - 1;
-
- break;
- case FILE_CHUNK:
- c->offset = c->file.length;
-
- break;
- default:
- break;
- }
-}
-
-/**
- * check if chunk is finished
- *
- * @param c chunk to set done
- * @return 1 if done, 0 if not
- */
-int chunk_is_done(chunk *c) {
- switch (c->type) {
- case MEM_CHUNK:
- return ((c->mem->used == 0) || (c->offset == (off_t)c->mem->used - 1));
- case FILE_CHUNK:
- return ((c->file.length == 0) || (c->offset == c->file.length));
- case UNUSED_CHUNK:
- default:
- return 1;
- }
-}
-
-off_t chunk_length(chunk *c) {
- switch (c->type) {
- case MEM_CHUNK:
- if (c->mem->used == 0) return 0;
- return (off_t)c->mem->used - 1 - c->offset;
- case FILE_CHUNK:
- return c->file.length - c->offset;
- case UNUSED_CHUNK:
- break;
- }
- return 0;
-}
-
-void chunkpool_free(void) {
- if (!chunkpool) return;
-
- /* free the pool */
- while(chunkpool) {
- chunk *c = chunkpool->next;
- chunk_free(chunkpool);
- chunkpool = c;
- }
- chunkpool_chunks = 0;
-}
-
-static chunk *chunkpool_get_unused_chunk(void) {
- chunk *c;
-
- /* check if we have an unused chunk */
- if (!chunkpool) {
- c = chunk_init();
- } else {
- /* take the first element from the list (a stack) */
- c = chunkpool;
- chunkpool = c->next;
- c->next = NULL;
-
- chunkpool_chunks--;
- }
-
- return c;
-}
-
-/**
- * keep unused chunks alive and store them in the chunkpool
- *
- * we only want to keep a small set of chunks alive to balance between
- * memory-usage and mallocs
- *
- * each filter will ask for a chunk
- */
-static void chunkpool_add_unused_chunk(chunk *c) {
- if (chunkpool_chunks > 128) {
- chunk_free(c);
- } else {
- chunk_reset(c);
-
- /* prepend the chunk to the chunkpool */
- c->next = chunkpool;
- chunkpool = c;
- chunkpool_chunks++;
- }
-}
-
-
-void chunkqueue_free(chunkqueue *cq) {
- chunk *c, *pc;
-
- if (!cq) return;
-
- for (c = cq->first; c; ) {
- pc = c;
- c = c->next;
- chunk_free(pc);
- }
-
- free(cq);
-}
-
-static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
- c->next = cq->first;
- cq->first = c;
-
- if (cq->last == NULL) {
- cq->last = c;
- }
-
- return 0;
-}
-
-static int chunkqueue_append_chunk(chunkqueue *cq, chunk *c) {
- if (cq->last) {
- cq->last->next = c;
- }
- cq->last = c;
-
- if (cq->first == NULL) {
- cq->first = c;
- }
-
- return 0;
-}
-
-/**
- * reset all chunks of the queue
- */
-void chunkqueue_reset(chunkqueue *cq) {
- chunk *c;
-
- /* mark all read done */
- for (c = cq->first; c; c = c->next) {
- chunk_set_done(c);
- }
-
- chunkqueue_remove_finished_chunks(cq);
-
- cq->bytes_in = 0;
- cq->bytes_out = 0;
- cq->is_closed = 0;
-}
-
-int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
- chunk *c;
-
- if (len == 0) return 0;
-
- c = chunkpool_get_unused_chunk();
-
- c->type = FILE_CHUNK;
-
- buffer_copy_string_buffer(c->file.name, fn);
- c->file.start = offset;
- c->file.length = len;
- c->offset = 0;
-
- chunkqueue_append_chunk(cq, c);
-
- return 0;
-}
-
-int chunkqueue_steal_tempfile(chunkqueue *cq, chunk *in) {
- chunk *c;
-
- assert(in->type == FILE_CHUNK);
- assert(in->file.is_temp == 1);
-
- c = chunkpool_get_unused_chunk();
-
- c->type = FILE_CHUNK;
- buffer_copy_string_buffer(c->file.name, in->file.name);
- c->file.start = in->file.start + in->offset;
- c->file.length = in->file.length - in->offset;
- c->offset = 0;
- c->file.is_temp = 1;
- in->file.is_temp = 0;
-
- chunkqueue_append_chunk(cq, c);
-
- return 0;
-}
-
-/**
- * move the content of chunk to another chunkqueue. return total bytes copied/stolen.
- */
-off_t chunkqueue_steal_chunk(chunkqueue *cq, chunk *c) {
- /* we are copying the whole buffer, just steal it */
- off_t total = 0;
- buffer *b, btmp;
-
- if (!cq) return 0;
- if (chunk_is_done(c)) return 0;
-
- switch (c->type) {
- case MEM_CHUNK:
- total = c->mem->used - c->offset - 1;
- if (c->offset == 0) {
- b = chunkqueue_get_append_buffer(cq);
- btmp = *b; *b = *(c->mem); *(c->mem) = btmp;
- } else {
- chunkqueue_append_mem(cq, c->mem->ptr + c->offset, total);
- chunk_set_done(c);
- }
- break;
- case FILE_CHUNK:
- total = c->file.length - c->offset;
-
- if (c->file.is_temp) {
- chunkqueue_steal_tempfile(cq, c);
- } else {
- chunkqueue_append_file(cq, c->file.name, c->file.start + c->offset, c->file.length - c->offset);
- chunk_set_done(c);
- }
-
- break;
- case UNUSED_CHUNK:
- return 0;
- }
-
- return total;
-}
-
-/*
- * copy/steal all chunks from in chunkqueue. return total bytes copied/stolen.
- *
- */
-off_t chunkqueue_steal_all_chunks(chunkqueue *cq, chunkqueue *in) {
- off_t total = 0;
- chunk *c;
-
- if (!cq || !in) return 0;
-
- for (c = in->first; c; c = c->next) {
- total += chunkqueue_steal_chunk(cq, c);
- }
-
- return total;
-}
-
-/*
- * copy/steal max_len bytes from chunk chain. return total bytes copied/stolen.
- *
- */
-off_t chunkqueue_steal_chunks_len(chunkqueue *out, chunk *c, off_t max_len) {
- off_t total = 0;
- off_t we_have = 0, we_want = 0;
- buffer *b;
-
- if (!out || !c) return 0;
-
- /* copy/steal chunks */
- for (; c && max_len > 0; c = c->next) {
- switch (c->type) {
- case FILE_CHUNK:
- we_have = c->file.length - c->offset;
-
- if (we_have == 0) break;
-
- if (we_have > max_len) we_have = max_len;
-
- chunkqueue_append_file(out, c->file.name, c->offset, we_have);
-
- c->offset += we_have;
- max_len -= we_have;
- total += we_have;
-
- /* steal the tempfile
- *
- * This is tricky:
- * - we reference the tempfile from the in-queue several times
- * if the chunk is larger than max_len
- * - we can't simply cleanup the in-queue as soon as possible
- * as it would remove the tempfiles
- * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
- * referencing chunk of the fastcgi-write-queue
- *
- */
-
- if (c->offset == c->file.length) {
- chunk *out_c;
-
- out_c = out->last;
-
- /* the last of the out-queue should be a FILE_CHUNK (we just created it)
- * and the incoming side should have given use a temp-file-chunk */
- assert(out_c->type == FILE_CHUNK);
- assert(c->file.is_temp == 1);
-
- out_c->file.is_temp = 1;
- c->file.is_temp = 0;
- }
-
- break;
- case MEM_CHUNK:
- /* skip empty chunks */
- if (c->mem->used == 0) break;
-
- we_have = c->mem->used - c->offset - 1;
- if (we_have == 0) break;
-
- we_want = we_have < max_len ? we_have : max_len;
-
- if (we_have == we_want) {
- /* steal whole chunk */
- chunkqueue_steal_chunk(out, c);
- } else {
- /* copy unused data from chunk */
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
- c->offset += we_want;
- }
- total += we_want;
- max_len -= we_want;
-
- break;
- default:
- break;
- }
- }
- return total;
-}
-
-/**
- * skip bytes in the chunkqueue
- *
- * @param cq chunkqueue
- * @param skip bytes to skip
- * @return bytes skipped
- */
-off_t chunkqueue_skip(chunkqueue *cq, off_t skip) {
- off_t total = 0;
- off_t we_have = 0, we_want = 0;
- chunk *c;
-
- if (!cq) return 0;
-
- /* consume chunks */
- for (c = cq->first; c && skip > 0; c = c->next) {
- we_have = chunk_length(c);
-
- /* skip empty chunks */
- if (!we_have) continue;
-
- we_want = we_have < skip ? we_have : skip;
-
- c->offset += we_want;
- total += we_want;
- skip -= we_want;
- }
-
- return total;
-}
-
-int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
- chunk *c;
-
- if (mem->used == 0) return 0;
-
- c = chunkpool_get_unused_chunk();
- c->type = MEM_CHUNK;
- c->offset = 0;
- buffer_copy_string_buffer(c->mem, mem);
-
- chunkqueue_append_chunk(cq, c);
-
- return 0;
-}
-
-int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
- chunk *c;
-
- if (mem->used == 0) return 0;
-
- c = chunkpool_get_unused_chunk();
- c->type = MEM_CHUNK;
- c->offset = 0;
- buffer_copy_string_buffer(c->mem, mem);
-
- chunkqueue_prepend_chunk(cq, c);
-
- return 0;
-}
-
-int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
- chunk *c;
-
- if (len == 0) return 0;
-
- c = chunkpool_get_unused_chunk();
- c->type = MEM_CHUNK;
- c->offset = 0;
- buffer_copy_string_len(c->mem, mem, len);
-
- chunkqueue_append_chunk(cq, c);
-
- return 0;
-}
-
-buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
- chunk *c;
-
- c = chunkpool_get_unused_chunk();
-
- c->type = MEM_CHUNK;
- c->offset = 0;
- buffer_reset(c->mem);
-
- chunkqueue_prepend_chunk(cq, c);
-
- return c->mem;
-}
-
-buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
- chunk *c;
-
- c = chunkpool_get_unused_chunk();
-
- c->type = MEM_CHUNK;
- c->offset = 0;
- buffer_reset(c->mem);
-
- chunkqueue_append_chunk(cq, c);
-
- return c->mem;
-}
-
-int chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
- if (!cq) return -1;
-
- cq->tempdirs = tempdirs;
-
- return 0;
-}
-
-chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
- chunk *c;
- buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
-
- c = chunkpool_get_unused_chunk();
-
- c->type = FILE_CHUNK;
- c->offset = 0;
-
- if (cq->tempdirs && cq->tempdirs->used) {
- size_t i;
-
- /* we have several tempdirs, only if all of them fail we jump out */
-
- for (i = 0; i < cq->tempdirs->used; i++) {
- data_string *ds = (data_string *)cq->tempdirs->data[i];
-
- buffer_copy_string_buffer(template, ds->value);
- PATHNAME_APPEND_SLASH(template);
- buffer_append_string_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX"));
-
- if (-1 != (c->file.fd = mkstemp(template->ptr))) {
- /* only trigger the unlink if we created the temp-file successfully */
- c->file.is_temp = 1;
- break;
- }
- }
- } else {
- if (-1 != (c->file.fd = mkstemp(template->ptr))) {
- /* only trigger the unlink if we created the temp-file successfully */
- c->file.is_temp = 1;
- }
- }
-
- buffer_copy_string_buffer(c->file.name, template);
- c->file.length = 0;
-
- chunkqueue_append_chunk(cq, c);
-
- buffer_free(template);
-
- return c;
-}
-
-
-off_t chunkqueue_length(chunkqueue *cq) {
- off_t len = 0;
- chunk *c;
-
- for (c = cq->first; c; c = c->next) {
- switch (c->type) {
- case MEM_CHUNK:
- len += c->mem->used ? c->mem->used - 1 : 0;
- break;
- case FILE_CHUNK:
- len += c->file.length;
- break;
- default:
- break;
- }
- }
-
- return len;
-}
-
-off_t chunkqueue_written(chunkqueue *cq) {
- off_t len = 0;
- chunk *c;
-
- for (c = cq->first; c; c = c->next) {
- switch (c->type) {
- case MEM_CHUNK:
- case FILE_CHUNK:
- len += c->offset;
- break;
- default:
- break;
- }
- }
-
- return len;
-}
-
-int chunkqueue_is_empty(chunkqueue *cq) {
- return cq->first ? 0 : 1;
-}
-
-int chunkqueue_remove_finished_chunks(chunkqueue *cq) {
- chunk *c;
-
- for (c = cq->first; c; c = cq->first) {
- if (!chunk_is_done(c)) break;
-
- /* the chunk is finished, remove it from the queue */
- cq->first = c->next;
- if (c == cq->last) cq->last = NULL;
-
- chunkpool_add_unused_chunk(c);
-
- }
-
- return 0;
-}
-
-void chunkqueue_print(chunkqueue *cq) {
- chunk *c;
-
- for (c = cq->first; c; c = c->next) {
- fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
- }
- fprintf(stderr, "\r\n");
-}
-
-
-/**
- * remove the last chunk if it is empty
- */
-
-void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
- chunk *c;
- if (!cq->last) return;
- if (!cq->first) return;
-
- if (cq->last->type != MEM_CHUNK || cq->last->mem->used != 0) return;
-
- if (cq->first == cq->last) {
- c = cq->first;
-
- chunk_free(c);
- cq->first = cq->last = NULL;
- } else {
- for (c = cq->first; c->next; c = c->next) {
- if (c->next == cq->last) {
- cq->last = c;
-
- chunk_free(c->next);
- c->next = NULL;
-
- return;
- }
- }
- }
-}
-
-
diff --git a/src/chunk.h b/src/chunk.h
deleted file mode 100644
index 63793b2f..00000000
--- a/src/chunk.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef _CHUNK_H_
-#define _CHUNK_H_
-
-#include "buffer.h"
-#include "array.h"
-#include "sys-mmap.h"
-
-typedef struct chunk {
- enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
-
- buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
-
- struct {
- /* filechunk */
- buffer *name; /* name of the file */
- off_t start; /* starting offset in the file */
- off_t length; /* octets to send from the starting offset */
-
- int fd;
- 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> octets away from the start of the file */
- } mmap;
-
- int is_temp; /* file is temporary and will be deleted on cleanup */
-
- struct {
- int fd;
- off_t length;
- off_t offset;
- } copy;
- } file;
-
- off_t offset; /* octets sent from this chunk
- the size of the chunk is either
- - mem-chunk: mem->used - 1
- - file-chunk: file.length
- */
-
- struct {
- off_t written;
- int ret_val;
- } async;
-
- struct chunk *next;
-} chunk;
-
-typedef struct {
- chunk *first;
- chunk *last;
-
- array *tempdirs;
-
- int is_closed; /* the input to this CQ is closed */
-
- off_t bytes_in, bytes_out;
-} chunkqueue;
-
-LI_API void chunkpool_free(void);
-
-LI_API chunkqueue* chunkqueue_init(void);
-LI_API int chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs);
-LI_API int chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len);
-LI_API int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len);
-LI_API int chunkqueue_append_buffer(chunkqueue *c, buffer *mem);
-LI_API int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem);
-
-LI_API buffer * chunkqueue_get_append_buffer(chunkqueue *c);
-LI_API buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
-LI_API chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
-LI_API int chunkqueue_steal_tempfile(chunkqueue *cq, chunk *in);
-LI_API off_t chunkqueue_steal_chunk(chunkqueue *cq, chunk *c);
-LI_API off_t chunkqueue_steal_chunks_len(chunkqueue *cq, chunk *c, off_t max_len);
-LI_API off_t chunkqueue_steal_all_chunks(chunkqueue *cq, chunkqueue *in);
-LI_API off_t chunkqueue_skip(chunkqueue *cq, off_t skip);
-LI_API void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
-
-LI_API int chunkqueue_remove_finished_chunks(chunkqueue *cq);
-
-LI_API off_t chunkqueue_length(chunkqueue *c);
-LI_API off_t chunkqueue_written(chunkqueue *c);
-LI_API void chunkqueue_free(chunkqueue *c);
-LI_API void chunkqueue_reset(chunkqueue *c);
-
-LI_API int chunkqueue_is_empty(chunkqueue *c);
-
-LI_API void chunkqueue_print(chunkqueue *cq);
-
-LI_API int chunk_is_done(chunk *c);
-LI_API void chunk_set_done(chunk *c);
-LI_API off_t chunk_length(chunk *c);
-
-#endif
diff --git a/src/config.h.cmake b/src/config.h.cmake
deleted file mode 100644
index 0aaeaa4f..00000000
--- a/src/config.h.cmake
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- CMake autogenerated config.h file. Do not edit!
-*/
-
-/* 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_SYSLIMITS_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_TIME_H
-#cmakedefine HAVE_UNISTD_H
-#cmakedefine HAVE_PTHREAD_H
-#cmakedefine HAVE_INET_ATON
-#cmakedefine HAVE_IPV6
-#cmakedefine HAVE_ISSETUGID
-
-/* XATTR */
-#cmakedefine HAVE_ATTR_ATTRIBUTES_H
-
-/* mySQL */
-#cmakedefine HAVE_MYSQL_H
-#cmakedefine HAVE_LIBMYSQL
-
-/* postgresql */
-#cmakedefine HAVE_LIBPQ_FE_H
-#cmakedefine HAVE_LIBPQ
-
-/* OpenSSL */
-#cmakedefine HAVE_OPENSSL_SSL_H
-#cmakedefine HAVE_LIBCRYPTO
-#cmakedefine OPENSSL_NO_KRB5
-#cmakedefine HAVE_LIBSSL
-
-#cmakedefine HAVE_AIO_H
-
-/* BZip */
-#cmakedefine HAVE_BZLIB_H
-#cmakedefine HAVE_LIBBZ2
-
-/* FAM */
-#cmakedefine HAVE_FAM_H
-
-/* getopt */
-#cmakedefine HAVE_GETOPT_H
-
-#cmakedefine HAVE_INTTYPES_H
-
-/* LDAP */
-#cmakedefine HAVE_LDAP_H
-#cmakedefine HAVE_LIBLDAP
-
-/* libaio */
-#cmakedefine HAVE_LIBAIO_H
-#cmakedefine HAVE_LIBAIO
-
-/* 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_H
-#cmakedefine HAVE_LIBUUID
-
-/* ZLIB */
-#cmakedefine HAVE_ZLIB_H
-#cmakedefine HAVE_LIBZ
-
-/* GLIB */
-#cmakedefine HAVE_GLIB_H
-#cmakedefine HAVE_GLIB
-
-/* lua */
-#cmakedefine HAVE_LUA_H
-#cmakedefine HAVE_LIBLUA
-
-/* 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_CRYPT
-#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_SENDFILE64
-#cmakedefine HAVE_SENDFILEV
-#cmakedefine HAVE_SIGACTION
-#cmakedefine HAVE_SIGNAL
-#cmakedefine HAVE_SIGTIMEDWAIT
-#cmakedefine HAVE_STRPTIME
-#cmakedefine HAVE_STRTOLL
-#cmakedefine HAVE_SYSLOG
-#cmakedefine HAVE_WRITEV
-
-/* libcrypt */
-#cmakedefine HAVE_LIBCRYPT
-
-/* fastcgi */
-#cmakedefine HAVE_FASTCGI_H
-#cmakedefine HAVE_FASTCGI_FASTCGI_H
-
-#cmakedefine LIGHTTPD_STATIC
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
deleted file mode 100644
index 8a31e333..00000000
--- a/src/configfile-glue.c
+++ /dev/null
@@ -1,675 +0,0 @@
-#include <string.h>
-#include <ctype.h>
-
-#include "base.h"
-#include "buffer.h"
-#include "array.h"
-#include "log.h"
-#include "plugin.h"
-#include "configfile.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[]) {
- size_t i;
- data_unset *du;
-
- for (i = 0; cv[i].key; i++) {
-
- if (NULL == (du = array_get_element(ca, cv[i].key, strlen(cv[i].key)))) {
- /* no found */
-
- continue;
- }
-
- switch (cv[i].type) {
- case T_CONFIG_ARRAY:
- if (du->type == TYPE_ARRAY) {
- size_t j;
- data_array *da = (data_array *)du;
-
- for (j = 0; j < da->value->used; j++) {
- if (da->value->data[j]->type == TYPE_STRING) {
- data_string *ds;
-
- if (NULL == (ds = (data_string *)array_get_unused_element(cv[i].destination, TYPE_STRING))) {
- ds = data_string_init();
- }
-
- buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
- if (!da->is_index_key) {
- /* the id's were generated automaticly, as we copy now we might have to renumber them
- * this is used to prepend server.modules by mod_indexfile as it has to be loaded
- * before mod_fastcgi and friends */
- buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
- }
-
- array_insert_unique(cv[i].destination, (data_unset *)ds);
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sssd",
- "the key of an array can only be a string or a integer, variable:",
- cv[i].key, "type:", da->value->data[j]->type);
-
- return -1;
- }
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
-
- return -1;
- }
- break;
- case T_CONFIG_STRING:
- if (du->type == TYPE_STRING) {
- data_string *ds = (data_string *)du;
-
- buffer_copy_string_buffer(cv[i].destination, ds->value);
- } else if (du->type == TYPE_INTEGER) {
- data_integer *di = (data_integer *)du;
-
- buffer_copy_long(cv[i].destination, di->value);
- } else {
- log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
-
- 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 (buffer_isdigit(ds->value)) {
- *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
- 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 (buffer_isdigit(ds->value)) {
- *((unsigned int *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
- break;
- }
-
- log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a 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 a 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:
- ERROR("found unsupported key in '%s' = '%s'", cv[i].key, (char *)(cv[i].destination));
-
- srv->config_unsupported = 1;
-
- break;
- case T_CONFIG_DEPRECATED:
- ERROR("found deprecated key in '%s' = '%s'", cv[i].key, (char *)(cv[i].destination));
-
- srv->config_deprecated = 1;
-
- break;
- }
- }
- return 0;
-}
-
-int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
- size_t i;
- data_unset *du;
-
- for (i = 0; cv[i].key; i++) {
- data_string *touched;
-
- if (NULL == (du = array_get_element(ca, cv[i].key, strlen(cv[i].key)))) {
- /* no found */
-
- continue;
- }
-
- /* touched */
- touched = data_string_init();
-
- buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
- buffer_copy_string_buffer(touched->key, du->key);
-
- array_insert_unique(srv->config_touched, (data_unset *)touched);
- }
-
- return config_insert_values_internal(srv, ca, cv);
-}
-
-unsigned short sock_addr_get_port(sock_addr *addr) {
- switch (addr->plain.sa_family) {
- case AF_INET:
- return ntohs(addr->ipv4.sin_port);
-#ifdef HAVE_IPV6
- case AF_INET6:
- return ntohs(addr->ipv6.sin6_port);
-#endif
- default:
- return 0;
- }
-}
-
-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;
- /* check parent first */
- if (dc->parent && dc->parent->context_ndx) {
- if (con->conf.log_condition_handling) {
- TRACE("checking if the parent (%s) evaluates to 'true'", SAFE_BUF_STR(dc->parent->key));
- }
-
- switch (config_check_cond_cached(srv, con, dc->parent)) {
- case COND_RESULT_FALSE:
- return COND_RESULT_FALSE;
- case COND_RESULT_UNSET:
- return COND_RESULT_UNSET;
- default:
- break;
- }
- }
-
- if (dc->prev) {
- if (con->conf.log_condition_handling) {
- TRACE("triggering eval of successors of (%s) [in else]", SAFE_BUF_STR(dc->key));
- }
-
- /* make sure prev is checked first */
- config_check_cond_cached(srv, con, dc->prev);
-
- if (con->conf.log_condition_handling) {
- TRACE("(%s) [in else] -> %s", SAFE_BUF_STR(dc->key), con->cond_cache[dc->context_ndx].result == COND_RESULT_FALSE ? "false" : "we will see");
- }
-
- switch (con->cond_cache[dc->context_ndx].result) {
- case COND_RESULT_FALSE: /* one of prev set me to FALSE */
- return con->cond_cache[dc->context_ndx].result;
- default:
- break;
- }
- }
-
- if (!con->conditional_is_valid[dc->comp]) {
- if (con->conf.log_condition_handling) {
- TRACE("is condition [%d] (%s) already valid ? %s",
- dc->comp,
- SAFE_BUF_STR(dc->key),
- con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
- }
-
- return COND_RESULT_UNSET;
- }
-
- /* pass the rules */
-
- switch (dc->comp) {
- case COMP_HTTP_HOST: {
- char *ck_colon = NULL, *val_colon = NULL;
-
- if (!buffer_is_empty(con->uri.authority)) {
-
- /*
- * append server-port to the HTTP_POST if necessary
- */
-
- l = con->uri.authority;
-
- switch(dc->cond) {
- case CONFIG_COND_NE:
- case CONFIG_COND_EQ:
- ck_colon = strchr(dc->string->ptr, ':');
- val_colon = strchr(l->ptr, ':');
-
- if (NULL != ck_colon && NULL == val_colon) {
- /* condition "host:port" but client send "host" */
- buffer_copy_string_buffer(srv->cond_check_buf, l);
- buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
- buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
- l = srv->cond_check_buf;
- } else if (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;
- }
-#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
- } else if (!buffer_is_empty(con->sock->tlsext_server_name)) {
- l = con->sock->tlsext_server_name;
-#endif
- } 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) &&
- (con->dst_addr.plain.sa_family == AF_INET) &&
- (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
- int nm_bits;
- long nm;
- char *err;
- struct in_addr val_inp;
-
- if (con->conf.log_condition_handling) {
- l = srv->empty_string;
-
- log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
- "(", l, ") compare to", dc->string);
- }
-
- if (*(nm_slash+1) == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
-
- return COND_RESULT_FALSE;
- }
-
- nm_bits = strtol(nm_slash + 1, &err, 10);
-
- if (*err) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
-
- return COND_RESULT_FALSE;
- }
-
- /* take IP convert to the native */
- buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
-#ifdef _WIN32
- if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
-
- return COND_RESULT_FALSE;
- }
-
-#else
- if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
-
- return COND_RESULT_FALSE;
- }
-#endif
-
- /* build netmask */
- nm = htonl(~((1 << (32 - nm_bits)) - 1));
-
- if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
- return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
- } else {
- return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
- }
- } else {
- 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_REFERER: {
- data_string *ds;
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Referer")))) {
- l = ds->value;
- } else {
- l = srv->empty_string;
- }
- break;
- }
- case COMP_HTTP_COOKIE: {
- data_string *ds;
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Cookie")))) {
- l = ds->value;
- } else {
- l = srv->empty_string;
- }
- break;
- }
- case COMP_HTTP_USER_AGENT: {
- data_string *ds;
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("User-Agent")))) {
- l = ds->value;
- } else {
- l = srv->empty_string;
- }
- break;
- }
- case COMP_HTTP_REQUEST_METHOD: {
- const char *method = get_http_method_name(con->request.http_method);
-
- /* we only have the request method as const char but we need a buffer for comparing */
-
- buffer_copy_string(srv->tmp_buf, method);
-
- l = srv->tmp_buf;
-
- break;
- }
- case COMP_PHYSICAL_PATH_EXISTS:
- case COMP_PHYSICAL_PATH:
- l = con->physical.path;
- 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) {
- TRACE("'%s': '%s' is matched against '%s'",
- SAFE_BUF_STR(dc->comp_key),
- SAFE_BUF_STR(l),
- SAFE_BUF_STR(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;
- }
- break;
-#ifdef HAVE_PCRE_H
- case CONFIG_COND_NOMATCH:
- case CONFIG_COND_MATCH: {
- cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
- int n;
-
-#ifndef elementsof
-#define elementsof(x) (sizeof(x) / sizeof(x[0]))
-#endif
- n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
- cache->matches, elementsof(cache->matches));
-
- cache->patterncount = n;
- if (n > 0) {
- cache->comp_value = l;
- cache->comp_type = dc->comp;
-
- return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
- } else {
- /* cache is already cleared */
- return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
- }
- break;
- }
-#endif
- 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) {
- if (con->conf.log_condition_handling) {
- TRACE("=== start of %d condition block ===", dc->context_ndx);
- }
- if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
- /* a node evaluted to true, all else nodes have to false */
- if (dc->next) {
- data_config *c;
- if (con->conf.log_condition_handling) {
- TRACE("setting remains of chaining to %s", "false");
- }
- for (c = dc->next; c; c = c->next) {
- caches[c->context_ndx].result = COND_RESULT_FALSE;
- }
- }
- }
- caches[dc->context_ndx].comp_type = dc->comp;
-
- if (con->conf.log_condition_handling) {
- TRACE("[%d] result: %s",
- dc->context_ndx,
- caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
- (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false")
- );
- }
- } else {
- if (con->conf.log_condition_cache_handling) {
- TRACE("[%d] (cached) result: %s",
- dc->context_ndx,
- caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
- (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false")
- );
- }
- }
-
- return caches[dc->context_ndx].result;
-}
-
-/**
- * reset the config-cache for a named item
- *
- * if the item is COND_LAST_ELEMENT we reset all items
- */
-void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- if (item == COMP_LAST_ELEMENT ||
- con->cond_cache[i].comp_type == item) {
- con->cond_cache[i].result = COND_RESULT_UNSET;
- con->cond_cache[i].patterncount = 0;
- con->cond_cache[i].comp_value = NULL;
- }
- }
-}
-
-/**
- * reset the config cache to its initial state at connection start
- */
-void config_cond_cache_reset(server *srv, connection *con) {
- size_t i;
-
- config_cond_cache_reset_all_items(srv, con);
-
- for (i = 0; i < COMP_LAST_ELEMENT; i++) {
- con->conditional_is_valid[i] = 0;
- }
-}
-
-int config_check_cond(server *srv, connection *con, data_config *dc) {
- return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
-}
-
-int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
-{
- cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
- if (n >= cache->patterncount) {
- return 0;
- }
-
- n <<= 1; /* n *= 2 */
- buffer_append_string_len(buf,
- cache->comp_value->ptr + cache->matches[n],
- cache->matches[n + 1] - cache->matches[n]);
- return 1;
-}
-
-/* return <0 on error
- * return 0-x if matched (and replaced)
- */
-int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
-{
-#ifdef HAVE_PCRE_H
- pcre *match;
- pcre_extra *extra;
- const char *pattern;
- size_t pattern_len;
- int n;
- size_t i;
- pcre_keyvalue *kv;
-# define N 10
- int ovec[N * 3];
-
- for (i = 0; i < kvb->used; i++) {
- kv = kvb->kv[i];
-
- match = kv->key;
- extra = kv->key_extra;
- pattern = kv->value->ptr;
- pattern_len = kv->value->used - 1;
-
- if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
- if (n != PCRE_ERROR_NOMATCH) {
- return n;
- }
- } else {
- const char **list;
- size_t start, end;
- size_t k;
-
- /* it matched */
- pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
-
- /* search for $[0-9] */
-
- buffer_reset(result);
-
- start = 0; end = pattern_len;
- for (k = 0; k < pattern_len; k++) {
- if ((pattern[k] == '$' || pattern[k] == '%') &&
- isdigit((unsigned char)pattern[k + 1])) {
- /* got one */
-
- size_t num = pattern[k + 1] - '0';
-
- end = k;
-
- buffer_append_string_len(result, pattern + start, end - start);
-
- if (pattern[k] == '$') {
- /* n is always > 0 */
- if (num < (size_t)n) {
- buffer_append_string(result, list[num]);
- }
- } else {
- config_append_cond_match_buffer(con, context, result, num);
- }
-
- k++;
- start = k + 1;
- }
- }
-
- buffer_append_string_len(result, pattern + start, pattern_len - start);
-
- pcre_free(list);
-
- return i;
- }
- }
-
- return PCRE_ERROR_NOMATCH;
-#undef N
-#else
- UNUSED(kvb);
- return -2;
-#endif
-}
-
diff --git a/src/configfile.c b/src/configfile.c
deleted file mode 100644
index 1254c270..00000000
--- a/src/configfile.c
+++ /dev/null
@@ -1,1376 +0,0 @@
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include "server.h"
-#include "log.h"
-#include "stream.h"
-#include "plugin.h"
-#include "configparser.h"
-#include "configfile.h"
-#include "proc_open.h"
-#include "fdevent.h"
-#include "network_backends.h"
-
-#include "sys-files.h"
-#include "sys-process.h"
-
-#ifndef PATH_MAX
-/* win32 */
-#define PATH_MAX 64
-#endif
-
-static int config_insert(server *srv) {
- size_t i;
- int ret = 0;
- buffer *stat_cache_string;
-
- config_values_t cv[] = {
- { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
- { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
- { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */
- { "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_SERVER }, /* 15 */
- { "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 16 */
- { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
- { "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
- { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
-
- { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
- { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
- { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
- { "server.max-fds", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 23 */
-#ifdef HAVE_LSTAT
- { "server.follow-symlink", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
-#else
- { "server.follow-symlink",
- "Your system lacks lstat(). We cant differ symlinks from files."
- "Please remove server.follow-symlinks from your config.",
- T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET }, /* 24 */
-#endif
- { "server.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 25 */
- { "connection.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 26 */
- { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
- { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
- { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */
-
- { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */
-
- { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */
- { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */
- { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */
- { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */
-
- { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
- { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
- { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
- { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
-
- { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
- { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
- { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
- { "server.max-connections", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 42 */
- { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
- { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
- { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
- { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 46 */
- { "server.use-noatime", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 49 */
- { "server.max-stat-threads", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 48 */
- { "server.max-read-threads", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 49 */
- { "server.max-connection-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 50 */
- { "debug.log-timing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 51 */
- { "ssl.cipher-list", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 52 */
- { "ssl.use-sslv2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 53 */
- { "etag.use-inode", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 54 */
- { "etag.use-mtime", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 55 */
- { "etag.use-size", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 56 */
- { "server.breakagelog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 57 */
- { "debug.log-timeouts", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 58 */
- { "debug.log-ssl-noise", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 59 */
- { "ssl.verifyclient.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 60 */
- { "ssl.verifyclient.enforce", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 61 */
- { "ssl.verifyclient.depth", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 62 */
- { "ssl.verifyclient.username", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 63 */
- { "ssl.verifyclient.exportcert", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 64 */
-
- { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.virtual-default-host", "load mod_simple_vhost and use simple-vhost.default-host instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.virtual-docroot", "load mod_simple_vhost and use simple-vhost.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.userid", "use server.username instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
- { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
-
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
-
- /* 0 */
- cv[0].destination = srv->srvconf.bindhost;
- cv[1].destination = srv->srvconf.errorlog_file;
- 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[36].destination = &(srv->srvconf.log_request_header_on_error);
- cv[37].destination = &(srv->srvconf.log_state_handling);
-
- cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
-
- stat_cache_string = buffer_init();
- cv[41].destination = stat_cache_string;
- cv[43].destination = srv->srvconf.network_backend;
- cv[44].destination = srv->srvconf.upload_tempdirs;
- cv[45].destination = &(srv->srvconf.enable_cores);
-
- cv[42].destination = &(srv->srvconf.max_conns);
- cv[12].destination = &(srv->srvconf.max_request_size);
- cv[47].destination = &(srv->srvconf.use_noatime);
- cv[48].destination = &(srv->srvconf.max_stat_threads);
- cv[49].destination = &(srv->srvconf.max_read_threads);
-
- cv[51].destination = &(srv->srvconf.log_timing);
- cv[57].destination = srv->srvconf.breakagelog_file;
-
- srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- assert(srv->config_storage);
-
- for (i = 0; i < srv->config_context->used; i++) {
- specific_config *s;
-
- s = calloc(1, sizeof(specific_config));
- assert(s);
- s->document_root = buffer_init();
- s->mimetypes = array_init();
- s->server_name = buffer_init();
- s->ssl_pemfile = buffer_init();
- s->ssl_ca_file = buffer_init();
- s->error_handler = buffer_init();
- s->server_tag = buffer_init();
- s->errorfile_prefix = buffer_init();
- s->ssl_cipher_list = buffer_init();
- s->ssl_use_sslv2 = 1;
- 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->max_keep_alive_requests = 16;
- s->max_keep_alive_idle = 5;
- s->max_read_idle = 60;
- s->max_write_idle = 360;
- s->max_connection_idle = 360;
- s->use_xattr = 0;
- s->is_ssl = 0;
- s->use_ipv6 = 0;
-#ifdef HAVE_LSTAT
- s->follow_symlink = 1;
-#endif
- s->kbytes_per_second = 0;
- s->allow_http11 = 1;
- s->range_requests = 1;
- s->etag_use_inode = 1;
- s->etag_use_mtime = 1;
- s->etag_use_size = 1;
- s->force_lowercase_filenames = 0;
- 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;
-
- cv[2].destination = s->errorfile_prefix;
-
- cv[7].destination = s->server_tag;
- cv[8].destination = &(s->use_ipv6);
-
-
- /* 13 max-worker */
- cv[14].destination = s->document_root;
- cv[15].destination = &(s->force_lowercase_filenames);
- cv[16].destination = &(s->log_condition_handling);
- cv[46].destination = &(s->log_condition_cache_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
- /* 23 -> max-fds */
- 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->ssl_pemfile;
- cv[30].destination = &(s->is_ssl);
-
- cv[31].destination = &(s->log_file_not_found);
- cv[32].destination = &(s->log_request_handling);
- cv[33].destination = &(s->log_response_header);
- cv[34].destination = &(s->log_request_header);
-
- cv[35].destination = &(s->allow_http11);
- cv[38].destination = s->ssl_ca_file;
- cv[40].destination = &(s->range_requests);
-
- cv[50].destination = &(s->max_connection_idle);
- cv[52].destination = s->ssl_cipher_list;
- cv[53].destination = &(s->ssl_use_sslv2);
-
- cv[54].destination = &(s->etag_use_inode);
- cv[55].destination = &(s->etag_use_mtime);
- cv[56].destination = &(s->etag_use_size);
- cv[58].destination = &(s->log_timeouts);
- cv[59].destination = &(s->log_ssl_noise);
-
- /* ssl.verify */
- cv[60].destination = &(s->ssl_verifyclient);
- cv[61].destination = &(s->ssl_verifyclient_enforce);
- cv[62].destination = &(s->ssl_verifyclient_depth);
- cv[63].destination = s->ssl_verifyclient_username;
- cv[64].destination = &(s->ssl_verifyclient_export_cert);
-
- srv->config_storage[i] = s;
-
- if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
- break;
- }
- }
-
- if (buffer_is_empty(stat_cache_string)) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
- } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
-#ifdef HAVE_FAM_H
- } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
-#endif
-#if defined(HAVE_SYS_INOTIFY_H)
- } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("inotify"))) {
- srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_INOTIFY;
-#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
-#if defined(HAVE_SYS_INOTIFY_H)
- ", \"inotify\""
-#endif
- " but not:", stat_cache_string);
- ret = HANDLER_ERROR;
- }
-
- buffer_free(stat_cache_string);
-
- return ret;
-
-}
-
-#define PATCH(x) \
- con->conf.x = s->x
-int config_setup_connection(server *srv, connection *con) {
- specific_config *s = srv->config_storage[0];
-
- PATCH(allow_http11);
- PATCH(mimetypes);
- PATCH(document_root);
- PATCH(max_keep_alive_requests);
- PATCH(max_keep_alive_idle);
- PATCH(max_read_idle);
- PATCH(max_write_idle);
- PATCH(max_connection_idle);
- PATCH(use_xattr);
- PATCH(error_handler);
- PATCH(errorfile_prefix);
-#ifdef HAVE_LSTAT
- PATCH(follow_symlink);
-#endif
- PATCH(server_tag);
- PATCH(kbytes_per_second);
- PATCH(global_kbytes_per_second);
- PATCH(global_bytes_per_second_cnt);
-
- con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
- buffer_copy_string_buffer(con->server_name, s->server_name);
-
- PATCH(log_request_header);
- PATCH(log_response_header);
- PATCH(log_request_handling);
- PATCH(log_condition_handling);
- PATCH(log_condition_cache_handling);
- PATCH(log_file_not_found);
- PATCH(log_ssl_noise);
- PATCH(log_timeouts);
-
- PATCH(range_requests);
- PATCH(force_lowercase_filenames);
- PATCH(is_ssl);
-
- PATCH(ssl_pemfile);
-#ifdef USE_OPENSSL
- PATCH(ssl_ctx);
-#endif
- PATCH(ssl_ca_file);
- PATCH(ssl_cipher_list);
- PATCH(ssl_use_sslv2);
- PATCH(etag_use_inode);
- PATCH(etag_use_mtime);
- PATCH(etag_use_size);
-
- PATCH(ssl_verifyclient);
- PATCH(ssl_verifyclient_enforce);
- PATCH(ssl_verifyclient_depth);
- PATCH(ssl_verifyclient_username);
- PATCH(ssl_verifyclient_export_cert);
-
- return 0;
-}
-
-int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
- size_t i, j;
-
- con->conditional_is_valid[comp] = 1;
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- specific_config *s = srv->config_storage[i];
-
- /* 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-404"))) {
- PATCH(error_handler);
- } 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-connection-idle"))) {
- PATCH(max_connection_idle);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.use-xattr"))) {
- PATCH(use_xattr);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
- PATCH(ssl_pemfile);
-#ifdef USE_OPENSSL
- PATCH(ssl_ctx);
-#endif
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
- PATCH(ssl_ca_file);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
- PATCH(is_ssl);
- } 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.use-sslv2"))) {
- PATCH(ssl_use_sslv2);
- } 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_string_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("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-condition-cache-handling"))) {
- PATCH(log_condition_cache_handling);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
- PATCH(log_file_not_found);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-ssl-noise"))) {
- PATCH(log_ssl_noise);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-timeouts"))) {
- PATCH(log_timeouts);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
- PATCH(allow_http11);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
- PATCH(force_lowercase_filenames);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
- PATCH(global_kbytes_per_second);
- PATCH(global_bytes_per_second_cnt);
- con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.activate"))) {
- PATCH(ssl_verifyclient);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.enforce"))) {
- PATCH(ssl_verifyclient_enforce);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.depth"))) {
- PATCH(ssl_verifyclient_depth);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
- PATCH(ssl_verifyclient_username);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
- PATCH(ssl_verifyclient_export_cert);
- }
- }
- }
-
-
- 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_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;
- 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;
- 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 '{':
- 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])
- ); 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 (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
- tid = TK_INCLUDE;
- } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
- tid = TK_INCLUDE_SHELL;
- } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
- tid = TK_GLOBAL;
- } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
- 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) {
- fprintf(stderr, "%s.%d: %d, %s\n",
- __FILE__, __LINE__,
- tid, token->ptr);
- }
- 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 );
- lasttoken = buffer_init();
- token = buffer_init();
-
- while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
- buffer_copy_string_buffer(lasttoken, token);
- configparser(pParser, token_id, token, context);
-
- token = buffer_init();
- }
- buffer_free(token);
-
- 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:", 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;
-}
-
-int config_parse_file(server *srv, config_t *context, const char *fn) {
- tokenizer_t t;
- stream s;
- int ret;
- buffer *filename;
-
- if (buffer_is_empty(context->basedir) ||
- (fn[0] == '/' || fn[0] == '\\') ||
- (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
- filename = buffer_init_string(fn);
- } else {
- filename = buffer_init_buffer(context->basedir);
- buffer_append_string(filename, fn);
- }
-
- if (0 != stream_open(&s, filename)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening configfile ", filename, "failed:", strerror(errno));
- ret = -1;
- } else {
- tokenizer_init(&t, filename, s.start, s.size);
- ret = config_parse(srv, context, &t);
- }
-
- stream_close(&s);
- buffer_free(filename);
- return ret;
-}
-
-int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
- tokenizer_t t;
- int ret;
- buffer *source;
- buffer *out;
- char oldpwd[PATH_MAX];
-
- if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "cannot get cwd", strerror(errno));
- return -1;
- }
-
- source = buffer_init_string(cmd);
- out = buffer_init();
-
- if (!buffer_is_empty(context->basedir)) {
- chdir(context->basedir->ptr);
- }
-
- if (0 != proc_open_buffer(cmd, NULL, out, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening", source, "failed:", strerror(errno));
- ret = -1;
- } else {
- tokenizer_init(&t, source, out->ptr, out->used);
- ret = config_parse(srv, context, &t);
- }
-
- buffer_free(source);
- buffer_free(out);
- chdir(oldpwd);
- return ret;
-}
-
-static void context_init(server *srv, config_t *context) {
- context->srv = srv;
- context->ok = 1;
- context->configs_stack = buffer_ptr_init(NULL);
- context->basedir = buffer_init();
-}
-
-static void context_free(config_t *context) {
- buffer_ptr_free(context->configs_stack);
- buffer_free(context->basedir);
-}
-
-int config_read(server *srv, const char *fn) {
- config_t context;
- data_config *dc;
- data_integer *dpid;
- data_string *dcwd;
- int ret;
- char *pos;
- data_array *modules;
-
- context_init(srv, &context);
- context.all_configs = srv->config_context;
-
- /* use the current dir as basedir for all other includes
- */
- pos = strrchr(fn, DIR_SEPERATOR);
-
- if (pos) {
- buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
- fn = pos + 1;
- }
-
- dc = data_config_init();
- buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));
-
- 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 */
- srv->config = dc->value;
- dpid = data_integer_init();
- dpid->value = getpid();
- buffer_copy_string_len(dpid->key, CONST_STR_LEN("var.PID"));
- array_insert_unique(srv->config, (data_unset *)dpid);
-
- dcwd = data_string_init();
- buffer_prepare_copy(dcwd->value, 1024);
- if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
- dcwd->value->used = strlen(dcwd->value->ptr) + 1;
- buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
- array_insert_unique(srv->config, (data_unset *)dcwd);
- }
-
- ret = config_parse_file(srv, &context, fn);
-
- /* remains nothing if parser is ok */
- assert(!(0 == ret && context.ok && 0 != context.configs_stack->used));
- context_free(&context);
-
- if (0 != ret) {
- return ret;
- }
-
- if (NULL != (dc = (data_config *)array_get_element(srv->config_context, CONST_STR_LEN("global")))) {
- srv->config = dc->value;
- } else {
- return -1;
- }
-
- if (NULL != (modules = (data_array *)array_get_element(srv->config, CONST_STR_LEN("server.modules")))) {
- data_string *ds;
- data_array *prepends;
- int prepend_mod_indexfile = 1;
- int append_mod_dirlisting = 1;
- int append_mod_staticfile = 1;
- int append_mod_chunked = 1;
- size_t i;
-
- if (modules->type != TYPE_ARRAY) {
- fprintf(stderr, "server.modules must be an array");
- return -1;
- }
-
- prepends = data_array_init();
-
- /* prepend default modules */
- for (i = 0; i < modules->value->used; i++) {
- ds = (data_string *)modules->value->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_chunked"))) {
- append_mod_chunked = 0;
- }
-
- if (0 == prepend_mod_indexfile &&
- 0 == append_mod_dirlisting &&
- 0 == append_mod_staticfile &&
- 0 == append_mod_chunked) {
-
- break;
- }
- }
-
- if (prepend_mod_indexfile) {
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
- array_insert_unique(prepends->value, (data_unset *)ds);
- }
-
- prepends = (data_array *)configparser_merge_data((data_unset *)prepends, (data_unset *)modules);
- buffer_copy_string_buffer(prepends->key, modules->key);
- array_replace(srv->config, (data_unset *)prepends);
- modules->free((data_unset *)modules);
- modules = prepends;
-
- /* append default modules */
- if (append_mod_dirlisting) {
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
- array_insert_unique(modules->value, (data_unset *)ds);
- }
-
- if (append_mod_staticfile) {
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
- array_insert_unique(modules->value, (data_unset *)ds);
- }
-
- if (append_mod_chunked) {
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_chunked"));
- array_insert_unique(modules->value, (data_unset *)ds);
- }
- } else {
- data_string *ds;
-
- modules = data_array_init();
-
- /* server.modules is not set */
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
- array_insert_unique(modules->value, (data_unset *)ds);
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
- array_insert_unique(modules->value, (data_unset *)ds);
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
- array_insert_unique(modules->value, (data_unset *)ds);
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_chunked"));
- array_insert_unique(modules->value, (data_unset *)ds);
-
- buffer_copy_string_len(modules->key, CONST_STR_LEN("server.modules"));
- array_insert_unique(srv->config, (data_unset *)modules);
- }
-
-
- if (0 != config_insert(srv)) {
- return -1;
- }
-
- return 0;
-}
-
-
-int config_set_defaults(server *srv) {
- specific_config *s = srv->config_storage[0];
- const fdevent_handler_info_t *handler;
- const network_backend_info_t *backend;
- struct stat st1, st2;
-
- if (buffer_is_empty(s->document_root)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "a default document-root has to be set");
-
- return -1;
- }
-
- if (buffer_is_empty(srv->srvconf.changeroot)) {
- pathname_unix2local(s->document_root);
- if (-1 == stat(s->document_root->ptr, &st1)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "base-docroot doesn't exist:",
- s->document_root, strerror(errno));
- return -1;
- }
-
- } else {
- buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
- buffer_append_string_buffer(srv->tmp_buf, s->document_root);
-
- if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "base-docroot doesn't exist:",
- srv->tmp_buf);
- return -1;
- }
-
- }
-
- buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
-
- buffer_to_lower(srv->tmp_buf);
-
- 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_string_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->is_ssl ? 443 : 80;
- }
-
- if (srv->srvconf.event_handler->used == 0) {
- /* get a useful default */
- handler = fdevent_get_defaulthandler();
- if (!handler) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "sorry, there is no event handler for this system");
-
- return -1;
- }
- } else {
- /*
- * User override
- */
-
- handler = fdevent_get_handler_info_by_name(srv->srvconf.event_handler->ptr);
- if (!handler) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "the selected event-handler is unknown:",
- srv->srvconf.event_handler );
-
- return -1;
- }
-
- if (!handler->init) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "the selected event-handler is known but not supported:",
- srv->srvconf.event_handler );
-
- return -1;
- }
- }
- srv->event_handler = handler->type;
-
- if (buffer_is_empty(srv->srvconf.network_backend)) {
- /* get a useful default */
- backend = network_get_defaultbackend();
- if (!backend) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "sorry, there is no network backend for this system");
-
- return -1;
- }
- } else {
- /*
- * User override
- */
-
- backend = network_get_backend_info_by_name(srv->srvconf.network_backend->ptr);
- if (!backend) {
- /* we don't know it */
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "server.network-backend has a unknown value:",
- srv->srvconf.network_backend);
-
- return -1;
- }
-
- if (backend->write_handler == NULL) {
- /* we know it but not supported */
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "server.network-backend not supported:",
- srv->srvconf.network_backend);
-
- return -1;
- }
- }
- srv->network_backend = backend->type;
-
- if (s->is_ssl) {
- if (buffer_is_empty(s->ssl_pemfile)) {
- /* PEM file is require */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "ssl.pemfile has to be set");
- return -1;
- }
-
-#ifndef USE_OPENSSL
- log_error_write(srv, __FILE__, __LINE__, "s",
- "ssl support is missing, recompile with --with-openssl");
-
- return -1;
-#endif
- }
-
- return 0;
-}
diff --git a/src/configfile.h b/src/configfile.h
deleted file mode 100644
index 5694517d..00000000
--- a/src/configfile.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _CONFIG_PARSER_H_
-#define _CONFIG_PARSER_H_
-
-#include "settings.h"
-#include "server.h"
-#include "array.h"
-#include "buffer.h"
-
-typedef struct {
- server *srv;
- int ok;
- array *all_configs;
- buffer_ptr *configs_stack; /* to parse nested block */
- data_config *current; /* current started with { */
- buffer *basedir;
-} config_t;
-
-LI_API void * configparserAlloc(void *(*mallocProc)(size_t));
-LI_API void configparserFree(void *p, void (*freeProc)(void*));
-LI_API void configparser(void *yyp, int yymajor, buffer *yyminor, config_t *ctx);
-LI_API int config_parse_file(server *srv, config_t *context, const char *fn);
-LI_API int config_parse_cmd(server *srv, config_t *context, const char *cmd);
-LI_API data_unset * configparser_merge_data(data_unset *op1, const data_unset *op2);
-LI_API void config_cond_cache_reset(server *srv, connection *con);
-LI_API void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item);
-
-#define config_cond_cache_reset_all_items(srv, con) \
- config_cond_cache_reset_item(srv, con, COMP_LAST_ELEMENT);
-
-#endif
diff --git a/src/configparser.y b/src/configparser.y
deleted file mode 100644
index 3d8caa57..00000000
--- a/src/configparser.y
+++ /dev/null
@@ -1,571 +0,0 @@
-%token_prefix TK_
-%extra_argument {config_t *ctx}
-%name configparser
-
-%include {
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "configfile.h"
-#include "buffer.h"
-#include "array.h"
-
-static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
- if (isnew) {
- dc->context_ndx = ctx->all_configs->used;
- assert(dc->context_ndx > ctx->current->context_ndx);
- array_insert_unique(ctx->all_configs, (data_unset *)dc);
- dc->parent = ctx->current;
- array_insert_unique(dc->parent->childs, (data_unset *)dc);
- }
- buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
- ctx->current = dc;
-}
-
-static data_config *configparser_pop(config_t *ctx) {
- data_config *old = ctx->current;
- ctx->current = (data_config *) buffer_ptr_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(dc->value, CONST_BUF_LEN(key)))) {
- return du->copy(du);
- }
- }
- return NULL;
-}
-
-/* op1 is to be eat/return by this function, 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_long(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_long(ds->value, ((data_integer*)op1)->value);
- buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
- op1->free(op1);
- return (data_unset *)ds;
- } else {
- fprintf(stderr, "data type mismatch, cannot be merge\n");
- op1->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) {
- array_insert_unique(dst, du->copy(du));
- }
- }
- break;
- default:
- assert(0);
- break;
- }
- }
- return op1;
-}
-
-}
-
-%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 condlines {data_config *}
-%type global {data_config *}
-%type aelements {array *}
-%type array {array *}
-%type key {buffer *}
-%type stringop {buffer *}
-
-%type cond {config_cond_t }
-
-%destructor value { $$->free($$); }
-%destructor expression { $$->free($$); }
-%destructor aelement { $$->free($$); }
-%destructor 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). {
- buffer_copy_string_buffer(B->key, A);
- if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
- fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, A->ptr);
- ctx->ok = 0;
- } else if (NULL == array_get_element(ctx->current->value, CONST_BUF_LEN(B->key))) {
- array_insert_unique(ctx->current->value, B);
- B = NULL;
- } else {
- if (0 == strcmp(B->key->ptr, "var.PID") ||
- 0 == strcmp(B->key->ptr, "var.CWD")) {
- fprintf(stderr, "var.PID and var.CWD are magic config vars and can't be set in the config file itself\n");
- } else {
- fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, B->key->ptr);
- }
- ctx->ok = 0;
- B->free(B);
- B = NULL;
- }
- buffer_free(A);
- A = NULL;
-}
-
-varline ::= key(A) APPEND expression(B). {
- 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_get_element(vars, CONST_BUF_LEN(A)))) {
- /* exists in current block */
- du = configparser_merge_data(du, B);
- if (NULL == du) {
- ctx->ok = 0;
- }
- else {
- buffer_copy_string_buffer(du->key, A);
- array_replace(vars, du);
- }
- B->free(B);
- } else if (NULL != (du = configparser_get_variable(ctx, A))) {
- du = configparser_merge_data(du, B);
- if (NULL == du) {
- ctx->ok = 0;
- }
- else {
- buffer_copy_string_buffer(du->key, A);
- array_insert_unique(ctx->current->value, du);
- }
- B->free(B);
- } else {
- buffer_copy_string_buffer(B->key, A);
- array_insert_unique(ctx->current->value, B);
- }
- buffer_free(A);
- A = NULL;
- B = NULL;
-}
-
-key(A) ::= LKEY(B). {
- if (strchr(B->ptr, '.') == NULL) {
- /* prepend the user-vars with var. */
- A = buffer_init_string("var.");
- buffer_append_string_buffer(A, B);
- buffer_free(B);
- B = NULL;
- } else {
- A = B;
- B = NULL;
- }
-}
-
-expression(A) ::= expression(B) PLUS value(C). {
- A = configparser_merge_data(B, C);
- if (NULL == A) {
- ctx->ok = 0;
- }
- B = NULL;
- C->free(C);
- C = NULL;
-}
-
-expression(A) ::= value(B). {
- A = B;
- B = NULL;
-}
-
-value(A) ::= key(B). {
- 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 {
- A = NULL;
- fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
- ctx->ok = 0;
- }
- } else if (NULL == (A = configparser_get_variable(ctx, B))) {
- fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
- ctx->ok = 0;
- }
- if (!A) {
- /* make a dummy so it won't crash */
- A = (data_unset *)data_string_init();
- }
- buffer_free(B);
- B = NULL;
-}
-
-value(A) ::= STRING(B). {
- A = (data_unset *)data_string_init();
- buffer_copy_string_buffer(((data_string *)(A))->value, B);
- buffer_free(B);
- B = NULL;
-}
-
-value(A) ::= INTEGER(B). {
- A = (data_unset *)data_integer_init();
- ((data_integer *)(A))->value = strtol(B->ptr, NULL, 10);
- 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). {
- if (buffer_is_empty(B->key) ||
- NULL == array_get_element(C, CONST_BUF_LEN(B->key))) {
- array_insert_unique(C, B);
- B = NULL;
- } else {
- fprintf(stderr, "Duplicate array-key: %s\n",
- B->key->ptr);
- ctx->ok = 0;
- B->free(B);
- B = NULL;
- }
-
- A = C;
- C = NULL;
-}
-
-aelements(A) ::= aelements(C) COMMA. {
- A = C;
- C = NULL;
-}
-
-aelements(A) ::= aelement(B). {
- A = array_init();
- array_insert_unique(A, B);
- B = NULL;
-}
-
-aelement(A) ::= expression(B). {
- A = B;
- B = NULL;
-}
-aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
- buffer_copy_string_buffer(C->key, B);
- buffer_free(B);
- B = NULL;
-
- A = C;
- C = NULL;
-}
-
-eols ::= EOL.
-eols ::= .
-
-globalstart ::= GLOBAL. {
- data_config *dc;
- dc = (data_config *)array_get_element(ctx->srv->config_context, CONST_STR_LEN("global"));
- assert(dc);
- configparser_push(ctx, dc, 0);
-}
-
-global(A) ::= globalstart LCURLY metalines RCURLY. {
- data_config *cur;
-
- cur = ctx->current;
- configparser_pop(ctx);
-
- assert(cur && ctx->current);
-
- A = cur;
-}
-
-condlines(A) ::= condlines(B) eols ELSE condline(C). {
- assert(B->context_ndx < C->context_ndx);
- C->prev = B;
- B->next = C;
- A = C;
- B = NULL;
- C = NULL;
-}
-
-condlines(A) ::= condline(B). {
- A = B;
- B = NULL;
-}
-
-condline(A) ::= context LCURLY metalines RCURLY. {
- data_config *cur;
-
- cur = ctx->current;
- configparser_pop(ctx);
-
- assert(cur && ctx->current);
-
- A = cur;
-}
-
-context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
- data_config *dc;
- buffer *b, *rvalue, *op;
-
- if (ctx->ok && D->type != TYPE_STRING) {
- fprintf(stderr, "rvalue must be string");
- ctx->ok = 0;
- }
-
- 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:
- assert(0);
- return;
- }
-
- b = buffer_init();
- buffer_copy_string_buffer(b, ctx->current->key);
- buffer_append_string(b, "/");
- 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(ctx->all_configs, CONST_BUF_LEN(b)))) {
- configparser_push(ctx, dc, 0);
- } else {
- struct {
- comp_key_t comp;
- char *comp_key;
- size_t len;
- } comps[] = {
- { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
- { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
- { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
- { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
- { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
- { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
- { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
- { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
- { COMP_HTTP_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_PHYSICAL_PATH, CONST_STR_LEN("PHYSICAL[\"path\"]") },
- { COMP_PHYSICAL_PATH_EXISTS,CONST_STR_LEN("PHYSICAL[\"existing-path\"]") },
-
- { COMP_UNSET, NULL, 0 },
- };
- size_t i;
-
- dc = data_config_init();
-
- buffer_copy_string_buffer(dc->key, b);
- buffer_copy_string_buffer(dc->op, op);
- buffer_copy_string_buffer(dc->comp_key, B);
- 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) {
- fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
- ctx->ok = 0;
- }
-
- switch(E) {
- case CONFIG_COND_NE:
- case CONFIG_COND_EQ:
- dc->string = buffer_init_buffer(rvalue);
- break;
- case CONFIG_COND_NOMATCH:
- case CONFIG_COND_MATCH: {
-#ifdef HAVE_PCRE_H
- const char *errptr;
- int erroff;
-
- if (NULL == (dc->regex =
- pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
- dc->string = buffer_init_string(errptr);
- dc->cond = CONFIG_COND_UNSET;
-
- fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
- rvalue->ptr, errptr, erroff);
-
- ctx->ok = 0;
- } else if (NULL == (dc->regex_study =
- pcre_study(dc->regex, 0, &errptr)) &&
- errptr != NULL) {
- fprintf(stderr, "studying regex failed: %s -> %s\n",
- rvalue->ptr, errptr);
- ctx->ok = 0;
- } else {
- dc->string = buffer_init_buffer(rvalue);
- }
-#else
- fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
- "(perhaps just a missing pcre-devel package ?) \n",
- B->ptr, C->ptr);
- ctx->ok = 0;
-#endif
- break;
- }
-
- default:
- fprintf(stderr, "unknown condition for $%s[%s]\n",
- B->ptr, C->ptr);
- ctx->ok = 0;
- break;
- }
-
- configparser_push(ctx, dc, 1);
- }
-
- buffer_free(b);
- buffer_free(op);
- buffer_free(B);
- B = NULL;
- buffer_free(C);
- C = NULL;
- D->free(D);
- D = NULL;
-}
-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 = buffer_init_buffer(((data_string*)B)->value);
- } else if (B->type == TYPE_INTEGER) {
- A = buffer_init();
- buffer_copy_long(A, ((data_integer *)B)->value);
- } else {
- fprintf(stderr, "operand must be string");
- ctx->ok = 0;
- }
- }
- B->free(B);
- B = NULL;
-}
-
-include ::= INCLUDE stringop(A). {
- if (ctx->ok) {
- if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
- ctx->ok = 0;
- }
- buffer_free(A);
- A = NULL;
- }
-}
-
-include_shell ::= INCLUDE_SHELL stringop(A). {
- if (ctx->ok) {
- if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
- ctx->ok = 0;
- }
- buffer_free(A);
- A = NULL;
- }
-}
diff --git a/src/connections-glue.c b/src/connections-glue.c
deleted file mode 100644
index fa5cf36f..00000000
--- a/src/connections-glue.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "base.h"
-#include "connections.h"
-
-const char *connection_get_state(connection_state_t state) {
- switch (state) {
- case CON_STATE_CONNECT: return "connect";
-
- case CON_STATE_REQUEST_START: return "req-start";
- case CON_STATE_READ_REQUEST_HEADER: return "read-header";
- case CON_STATE_HANDLE_REQUEST_HEADER: return "handle-req";
- case CON_STATE_READ_REQUEST_CONTENT: return "read-content";
-
- case CON_STATE_HANDLE_RESPONSE_HEADER: return "resp-start";
- case CON_STATE_WRITE_RESPONSE_HEADER: return "write-header";
- case CON_STATE_WRITE_RESPONSE_CONTENT: return "write-content";
- case CON_STATE_RESPONSE_END: return "resp-end";
-
- case CON_STATE_CLOSE: return "close";
- case CON_STATE_ERROR: return "error";
- default: return "(unknown)";
- }
-}
-
-const char *connection_get_short_state(connection_state_t state) {
- switch (state) {
- case CON_STATE_CONNECT: return ".";
- case CON_STATE_REQUEST_START: return "q";
-
- case CON_STATE_READ_REQUEST_HEADER: return "r";
- case CON_STATE_HANDLE_REQUEST_HEADER: return "h";
- case CON_STATE_READ_REQUEST_CONTENT: return "R";
-
- case CON_STATE_HANDLE_RESPONSE_HEADER: return "s";
- case CON_STATE_WRITE_RESPONSE_HEADER: return "w";
- case CON_STATE_WRITE_RESPONSE_CONTENT: return "W";
- case CON_STATE_RESPONSE_END: return "S";
-
- case CON_STATE_CLOSE: return "C";
- case CON_STATE_ERROR: return "E";
- default: return "x";
- }
-}
-
-int connection_set_state(server *srv, connection *con, connection_state_t state) {
- UNUSED(srv);
-
- con->state = state;
-
- return 0;
-}
-
diff --git a/src/connections.c b/src/connections.c
deleted file mode 100644
index 1069adab..00000000
--- a/src/connections.c
+++ /dev/null
@@ -1,1599 +0,0 @@
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "settings.h"
-
-#include "server.h"
-#include "connections.h"
-#include "fdevent.h"
-#include "log.h"
-
-#include "request.h"
-#include "response.h"
-#include "network.h"
-#include "stat_cache.h"
-#include "joblist.h"
-
-#include "plugin.h"
-
-#include "inet_ntop_cache.h"
-#include "configfile.h"
-#include "http_req.h"
-
-#ifdef USE_OPENSSL
-# include <openssl/ssl.h>
-# include <openssl/err.h>
-#endif
-
-#ifdef HAVE_SYS_FILIO_H
-# include <sys/filio.h>
-#endif
-
-#include "sys-socket.h"
-#include "sys-files.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 == 0) {
- conns->size = 128;
- conns->ptr = NULL;
- conns->ptr = malloc(sizeof(*conns->ptr) * conns->size);
- for (i = 0; i < conns->size; i++) {
- conns->ptr[i] = connection_init(srv);
- }
- } else if (conns->size == conns->used) {
- conns->size += 128;
- conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
-
- for (i = conns->used; i < conns->size; i++) {
- conns->ptr[i] = connection_init(srv);
- }
- }
-
- connection_reset(srv, conns->ptr[conns->used]);
-
- 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;
-
- 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;
-
- return 0;
-}
-
-int connection_close(server *srv, connection *con) {
-#ifdef USE_OPENSSL
- /* should be in iosocket_close() */
-
- if (con->sock->ssl) {
- int ret, ssl_r;
- unsigned long err;
-
- ERR_clear_error();
- switch (ret = SSL_shutdown(con->sock->ssl)) {
- case 1:
- /* done */
- break;
- case 0:
- /* wait for fd-event
- *
- * FIXME: wait for fdevent and call SSL_shutdown again
- * (But it is not that important as we close the underlying connection anyway)
- */
-
- break;
- default:
- switch ((ssl_r = SSL_get_error(con->sock->ssl, ret))) {
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- break;
- case SSL_ERROR_SYSCALL:
- /* perhaps we have error waiting in our error-queue */
- if (0 != (err = ERR_get_error())) {
- do {
- ERROR("SSL_shutdown failed (%i, %i): %s", ssl_r, ret, ERR_error_string(err, NULL));
- } while((err = ERR_get_error()));
- } else {
- ERROR("SSL_shutdown failed (%i, %i, %i): %s", ssl_r, ret, errno, strerror(errno));
- }
-
- break;
- default:
- while((err = ERR_get_error())) {
- ERROR("SSL_shutdown failed (%i, %i): %s", ssl_r, ret, ERR_error_string(err, NULL));
- }
- }
- }
-
- SSL_free(con->sock->ssl);
- ERR_clear_error();
- con->sock->ssl = NULL;
- }
-#endif
-
- fdevent_event_del(srv->ev, con->sock);
- fdevent_unregister(srv->ev, con->sock);
-
- if (closesocket(con->sock->fd)) {
- ERROR("close failed (%i): %s", con->sock->fd, strerror(errno));
- }
-
- connection_del(srv, con);
- connection_set_state(srv, con, CON_STATE_CONNECT);
-
- return 0;
-}
-
-#if 0
-static void dump_packet(const unsigned char *data, size_t len) {
- size_t i, j;
-
- if (len == 0) return;
-
- for (i = 0; i < len; i++) {
- if (i % 16 == 0) fprintf(stderr, " ");
-
- fprintf(stderr, "%02x ", data[i]);
-
- if ((i + 1) % 16 == 0) {
- fprintf(stderr, " ");
- for (j = 0; j <= i % 16; j++) {
- unsigned char c;
-
- if (i-15+j >= len) break;
-
- c = data[i-15+j];
-
- fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
- }
-
- fprintf(stderr, "\n");
- }
- }
-
- if (len % 16 != 0) {
- for (j = i % 16; j < 16; j++) {
- fprintf(stderr, " ");
- }
-
- fprintf(stderr, " ");
- for (j = i & ~0xf; j < len; j++) {
- unsigned char c;
-
- c = data[j];
- fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
- }
- fprintf(stderr, "\n");
- }
-}
-#endif
-
-static int connection_handle_response_header(server *srv, connection *con) {
- int no_response_body = 0;
-
- if (con->mode == DIRECT) {
- /* static files */
- switch(con->request.http_method) {
- case HTTP_METHOD_GET:
- case HTTP_METHOD_POST:
- case HTTP_METHOD_HEAD:
- /* webdav */
- case HTTP_METHOD_PUT:
- case HTTP_METHOD_MKCOL:
- case HTTP_METHOD_DELETE:
- case HTTP_METHOD_COPY:
- case HTTP_METHOD_MOVE:
- case HTTP_METHOD_PROPFIND:
- case HTTP_METHOD_PROPPATCH:
- case HTTP_METHOD_LOCK:
- case HTTP_METHOD_UNLOCK:
- break;
- case HTTP_METHOD_OPTIONS:
- /*
- * 400 is coming from the request-parser BEFORE uri.path is set
- * 403 is from the response handler when noone else catched it
- *
- * */
- if ((!con->http_status || con->http_status == 200 || con->http_status == 403) &&
- con->uri.path->used && con->uri.path->ptr[0] != '*') {
- response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
-
- /* trash the content */
- no_response_body = 1;
-
- con->http_status = 200;
- }
- break;
- default:
- switch(con->http_status) {
- case 400: /* bad request */
- case 414: /* overload request header */
- case 505: /* unknown protocol */
- case 207: /* this was webdav */
- break;
- default:
- con->http_status = 501;
- break;
- }
- break;
- }
- }
-
- if (con->http_status == 0) {
- TRACE("%s", "no status, setting 403");
- con->http_status = 403;
- }
-
- switch(con->http_status) {
- case 400: /* class: header + custom body */
- case 401:
- case 403:
- case 404:
- case 408:
- case 409:
- case 410:
- case 411:
- case 416:
- case 423:
- case 500:
- case 501:
- case 502:
- case 503:
- case 504:
- case 505:
- case 509:
- if (con->mode != DIRECT) break;
-
- con->send->is_closed = 0;
- con->response.content_length = -1;
-
- buffer_reset(con->physical.path);
-
- /* try to send static errorfile */
- if (!buffer_is_empty(con->conf.errorfile_prefix)) {
- stat_cache_entry *sce = NULL;
-
- buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
- buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
-
- if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
- con->send->bytes_in += sce->st.st_size;
- con->send->is_closed = 1;
- if (buffer_is_empty(sce->content_type)) {
- /* for error docs default to html instead of application-data */
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- } else {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
- }
- }
- }
-
- if (!con->send->is_closed) {
- buffer *b;
-
- buffer_reset(con->physical.path);
-
- con->send->is_closed = 1;
- b = chunkqueue_get_append_buffer(con->send);
-
- /* 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>"));
- buffer_append_long(b, con->http_status);
- buffer_append_string_len(b, CONST_STR_LEN(" - "));
- buffer_append_string(b, get_http_status_name(con->http_status));
-
- buffer_append_string(b,
- "</title>\n"
- " </head>\n"
- " <body>\n"
- " <h1>");
- buffer_append_long(b, con->http_status);
- buffer_append_string_len(b, CONST_STR_LEN(" - "));
- buffer_append_string(b, get_http_status_name(con->http_status));
-
- buffer_append_string(b,"</h1>\n"
- " </body>\n"
- "</html>\n"
- );
-
- con->send->bytes_in += b->used - 1;
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- }
- /* fall through */
- case 207:
- case 200: /* class: header + body */
- case 201:
- case 301:
- case 302:
- case 303:
- break;
-
- case 206: /* write_queue is already prepared */
- break;
- case 205: /* class: header only */
- case 304:
- default:
- if (con->mode == DIRECT) {
- /* only if we have handled the request internally
- * we will see no response-content
- *
- * if it was a fastcgi request we will see a END_REQUEST packet
- * after the header was parsed.
- *
- * */
- no_response_body = 1;
- }
- break;
- }
-
- if (no_response_body) {
- /* disable chunked encoding again as we have no body */
- con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
- chunkqueue_reset(con->send);
-
- con->send->is_closed = 1;
- }
-
- return 0;
-}
-
-connection *connection_init(server *srv) {
- connection *con;
-
- UNUSED(srv);
-
- con = calloc(1, sizeof(*con));
-
- con->sock = iosocket_init();
- con->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);
- CLEAN(request.pathinfo);
- CLEAN(request.http_host);
-
- CLEAN(request.orig_uri);
-
- CLEAN(uri.scheme);
- CLEAN(uri.authority);
- CLEAN(uri.path);
- CLEAN(uri.path_raw);
- CLEAN(uri.query);
-
- CLEAN(physical.doc_root);
- CLEAN(physical.path);
- CLEAN(physical.basedir);
- CLEAN(physical.rel_path);
- CLEAN(physical.etag);
- CLEAN(parse_request);
-
- CLEAN(authed_user);
- CLEAN(server_name);
- CLEAN(error_handler);
- CLEAN(dst_addr_buf);
-
-#undef CLEAN
- con->send_filters = filter_chain_init();
- /* send is the chunkqueue of the first send filter */
- con->send = con->send_filters->first->cq;
- con->recv = chunkqueue_init();
- chunkqueue_set_tempdirs(con->recv, srv->srvconf.upload_tempdirs);
-
- con->send_raw = chunkqueue_init();
- con->recv_raw = chunkqueue_init();
-
- con->request.headers = array_init();
- con->response.headers = array_init();
- con->environment = array_init();
-
- con->http_req = http_request_init();
-
- /* init plugin specific connection structures */
-
- con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
-
- con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
- config_setup_connection(srv, con);
-
- return con;
-}
-
-void connections_free(server *srv) {
- connections *conns = srv->conns;
- size_t i;
-
- for (i = 0; i < conns->size; i++) {
- connection *con = conns->ptr[i];
-
- connection_reset(srv, con);
- iosocket_free(con->sock);
-
- filter_chain_free(con->send_filters);
- con->send = NULL;
- chunkqueue_free(con->recv);
- chunkqueue_free(con->send_raw);
- chunkqueue_free(con->recv_raw);
- 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);
- CLEAN(request.pathinfo);
- CLEAN(request.http_host);
-
- CLEAN(request.orig_uri);
-
- CLEAN(uri.scheme);
- CLEAN(uri.authority);
- CLEAN(uri.path);
- CLEAN(uri.path_raw);
- CLEAN(uri.query);
-
- CLEAN(physical.doc_root);
- CLEAN(physical.path);
- CLEAN(physical.basedir);
- CLEAN(physical.etag);
- CLEAN(physical.rel_path);
- CLEAN(parse_request);
-
- CLEAN(authed_user);
- CLEAN(server_name);
- CLEAN(error_handler);
- CLEAN(dst_addr_buf);
-#undef CLEAN
- free(con->plugin_ctx);
- free(con->cond_cache);
-
- http_request_free(con->http_req);
-
- free(con);
- }
-
- free(conns->ptr);
-}
-
-
-int connection_reset(server *srv, connection *con) {
- size_t i;
-
- plugins_call_connection_reset(srv, con);
-
- con->is_readable = 1;
- con->is_writable = 1;
- con->http_status = 0;
- con->file_started = 0;
- con->got_response = 0;
-
- con->bytes_written = 0;
- con->bytes_written_cur_second = 0;
- con->bytes_read = 0;
- con->bytes_header = 0;
- con->loops_per_request = 0;
-
- con->request.http_method = HTTP_METHOD_UNSET;
- con->request.http_version = HTTP_VERSION_UNSET;
- con->request.content_length = -1;
-
- con->response.keep_alive = 0;
- con->response.content_length = -1;
- con->response.transfer_encoding = 0;
-
- con->mode = DIRECT;
-
-#define CLEAN(x) \
- if (con->x) buffer_reset(con->x);
-
- CLEAN(request.uri);
- CLEAN(request.pathinfo);
- CLEAN(request.request);
- CLEAN(request.http_host);
-
- CLEAN(request.orig_uri);
-
- CLEAN(uri.scheme);
- CLEAN(uri.authority);
- CLEAN(uri.path);
- CLEAN(uri.path_raw);
- CLEAN(uri.query);
-
- CLEAN(physical.doc_root);
- CLEAN(physical.path);
- CLEAN(physical.basedir);
- CLEAN(physical.rel_path);
- CLEAN(physical.etag);
-
- CLEAN(parse_request);
-
- CLEAN(authed_user);
- CLEAN(server_name);
- CLEAN(error_handler);
-#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
- CLEAN(sock->tlsext_server_name);
-#endif
-#undef CLEAN
-
-#define CLEAN(x) \
- if (con->x) con->x->used = 0;
-
-#undef CLEAN
-
- array_reset(con->request.headers);
- array_reset(con->response.headers);
- array_reset(con->environment);
-
- filter_chain_reset(con->send_filters);
- con->send = con->send_filters->first->cq;
- chunkqueue_reset(con->recv);
- chunkqueue_reset(con->send_raw);
-
- http_request_reset(con->http_req);
-
- /* the plugins should cleanup themself */
- for (i = 0; i < srv->plugins.used; i++) {
- plugin *p = ((plugin **)(srv->plugins.ptr))[i];
- plugin_data *pd = p->data;
-
- if (!pd) continue;
-
- if (con->plugin_ctx[pd->id] != NULL) {
- ERROR("missing cleanup in %s", SAFE_BUF_STR(p->name));
- }
-
- con->plugin_ctx[pd->id] = NULL;
- }
-
- config_cond_cache_reset(srv, con);
-
- con->header_len = 0;
- con->in_error_handler = 0;
-
- config_setup_connection(srv, con);
-
- return 0;
-}
-
-/**
- * handle all header and content read
- *
- * we get called by the state-engine and by the fdevent-handler
- */
-static handler_t connection_handle_read_request_header(server *srv, connection *con) {
- /* let's see if we need more data later */
- fdevent_event_del(srv->ev, con->sock);
-
- con->read_idle_ts = srv->cur_ts; /* start a read-call() */
-
- /* read from the network */
- switch (network_read(srv, con, con->sock, con->recv_raw)) {
- case NETWORK_STATUS_SUCCESS:
- /* we read everything from the socket, do we have a full header ? */
- break;
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
- return HANDLER_WAIT_FOR_EVENT;
- case NETWORK_STATUS_CONNECTION_CLOSE:
- /* the connection went away before we got something back */
- con->close_timeout_ts = srv->cur_ts - 2;
- connection_set_state(srv, con, CON_STATE_CLOSE);
-
- return HANDLER_GO_ON;
- default:
- ERROR("++ %s", "oops, something went wrong while reading");
- return HANDLER_ERROR;
- }
-
- switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
- case PARSE_ERROR:
- con->http_status = 400; /* the header is broken */
- con->send->is_closed = 1; /* we have nothing to send */
-
- chunkqueue_remove_finished_chunks(con->recv_raw);
-
- return HANDLER_FINISHED;
- case PARSE_NEED_MORE:
- /* we need more */
- fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
-
- return HANDLER_WAIT_FOR_EVENT;
- case PARSE_SUCCESS:
- chunkqueue_remove_finished_chunks(con->recv_raw);
- break;
- default:
- chunkqueue_remove_finished_chunks(con->recv_raw);
- TRACE("%s", "(error)");
- return HANDLER_ERROR;
- }
-
- return HANDLER_GO_ON;
-}
-
-/* decode the HTTP/1.1 chunk encoding */
-
-static handler_t connection_handle_read_request_content(server *srv, connection *con) {
- /* read data from the socket and push it to the backend */
-
- chunkqueue *in = con->recv_raw;
- chunkqueue *out = con->recv; /* the pure content */
- chunk *c;
-
- /* let's see if we need more data later */
- fdevent_event_del(srv->ev, con->sock);
-
- con->read_idle_ts = srv->cur_ts; /* start a read-call() */
-
- if (con->request.content_length == -1) return HANDLER_GO_ON;
-
- /* if the content was short enough, it might be read already */
- if (in->first &&
- chunkqueue_length(in) - in->first->offset > 0) {
-
- /*
- * looks like the request-header also had some content for us
- */
-
- } else {
- /* read from the network */
- switch (network_read(srv, con, con->sock, in)) {
- case NETWORK_STATUS_SUCCESS:
- /* we have data */
- break;
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
- return HANDLER_WAIT_FOR_EVENT;
- case NETWORK_STATUS_CONNECTION_CLOSE:
- /* the connection went away before we got something back */
- con->close_timeout_ts = srv->cur_ts - 2;
- connection_set_state(srv, con, CON_STATE_CLOSE);
-
- return HANDLER_GO_ON;
- default:
- ERROR("++ %s", "oops, something went wrong while reading");
- return HANDLER_ERROR;
- }
- }
-
- /* how much data do we want to extract ? */
- for (c = in->first; c && (out->bytes_in != con->request.content_length); c = c->next) {
- off_t weWant, weHave, toRead;
-
- weWant = con->request.content_length - out->bytes_in;
-
- if (c->mem->used == 0) continue;
-
- weHave = c->mem->used - c->offset - 1;
-
- toRead = weHave > weWant ? weWant : weHave;
-
- /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
- if (con->request.content_length > 64 * 1024) {
- chunk *dst_c = NULL;
- /* copy everything to max 1Mb sized tempfiles */
-
- /*
- * if the last chunk is
- * - smaller than 1Mb (size < 1Mb)
- * - not read yet (offset == 0)
- * -> append to it
- * otherwise
- * -> create a new chunk
- *
- * */
-
- if (out->last &&
- out->last->type == FILE_CHUNK &&
- out->last->file.is_temp &&
- out->last->offset == 0) {
- /* ok, take the last chunk for our job */
-
- if (out->last->file.length < 1 * 1024 * 1024) {
- dst_c = out->last;
-
- if (dst_c->file.fd == -1) {
- /* this should not happen as we cache the fd, but you never know */
- dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
- }
- } else {
- /* the chunk is too large now, close it */
- dst_c = out->last;
-
- if (dst_c->file.fd != -1) {
- close(dst_c->file.fd);
- dst_c->file.fd = -1;
- }
- dst_c = chunkqueue_get_append_tempfile(out);
- }
- } else {
- dst_c = chunkqueue_get_append_tempfile(out);
- }
-
- /* we have a chunk, let's write to it */
-
- if (dst_c->file.fd == -1) {
- /* we don't have file to write to,
- * EACCES might be one reason.
- *
- * Instead of sending 500 we send 413 and say the request is too large
- * */
-
- ERROR("denying upload as opening to temp-file for upload failed: '%s': %s",
- SAFE_BUF_STR(dst_c->file.name), strerror(errno));
-
- con->http_status = 413; /* Request-Entity too large */
- con->keep_alive = 0;
- return HANDLER_FINISHED;
- }
-
- if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
- /* write failed for some reason ... disk full ? */
- ERROR("denying upload as writing to file failed: '%s': %s",
- SAFE_BUF_STR(dst_c->file.name), strerror(errno));
-
- con->http_status = 413; /* Request-Entity too large */
- con->keep_alive = 0;
-
- close(dst_c->file.fd);
- dst_c->file.fd = -1;
-
- return HANDLER_FINISHED;
- }
-
- dst_c->file.length += toRead;
-
- if (out->bytes_in + toRead == con->request.content_length) {
- /* we read everything, close the chunk */
- close(dst_c->file.fd);
- dst_c->file.fd = -1;
- }
- } else {
- buffer *b;
-
- b = (out->last) ? out->last->mem : NULL;
-
- if (NULL == b) {
- b = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(b, con->request.content_length - out->bytes_in + 1);
- }
-
- buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
- }
-
- c->offset += toRead;
-
- out->bytes_in += toRead;
- in->bytes_out += toRead;
- }
-
- if (out->bytes_in < con->request.content_length) {
- /* we have to read more content */
- fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
- }
-
- return HANDLER_GO_ON;
-}
-
-static handler_t connection_handle_fdevent(void *s, void *context, int revents) {
- server *srv = (server *)s;
- connection *con = context;
-
- if (revents & FDEVENT_IN) {
- switch (con->state) {
- case CON_STATE_READ_REQUEST_HEADER:
- case CON_STATE_READ_REQUEST_CONTENT:
- joblist_append(srv, con);
- break;
- case CON_STATE_CLOSE: /* ignore the even, we will clean-up soon */
- break;
- case CON_STATE_ERROR:
- ERROR("we are in (CON_STATE_ERROR), but still get a FDEVENT_IN, removing event from fd = %d, %04x for (%s)",
- con->sock->fd,
- revents,
- SAFE_BUF_STR(con->uri.path));
-
- fdevent_event_del(srv->ev, con->sock);
-
- joblist_append(srv, con);
- break;
- default:
- ERROR("I thought only READ_REQUEST_* need fdevent-in: %d, fd = %d, %04x for (%s)",
- con->state,
- con->sock->fd,
- revents,
- SAFE_BUF_STR(con->uri.path));
- break;
- }
- }
-
- if (revents & FDEVENT_OUT) {
- switch (con->state) {
- case CON_STATE_WRITE_RESPONSE_HEADER:
- case CON_STATE_WRITE_RESPONSE_CONTENT:
- joblist_append(srv, con);
- break;
- case CON_STATE_ERROR:
- ERROR("we are in (CON_STATE_ERROR), but still get a FDEVENT_OUT, removing event from fd = %d, %04x for (%s)",
- con->sock->fd,
- revents,
- SAFE_BUF_STR(con->uri.path));
-
- fdevent_event_del(srv->ev, con->sock);
-
- joblist_append(srv, con);
- break;
- default:
- TRACE("got FDEVENT_OUT for state %d, calling the job-handler, let's see what happens", con->state);
- joblist_append(srv, con);
- break;
- }
- }
-
- if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
- /* looks like an error */
-
- connection_set_state(srv, con, CON_STATE_ERROR);
- joblist_append(srv, con);
- }
-
-
- return HANDLER_FINISHED;
-}
-
-
-connection *connection_accept(server *srv, server_socket *srv_socket) {
- /* accept everything */
-
- /* search an empty place */
- int cnt;
- sock_addr cnt_addr;
- socklen_t cnt_len;
- /* accept it and register the fd */
-
- cnt_len = sizeof(cnt_addr);
-
- if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
-#ifdef _WIN32
- errno = WSAGetLastError();
-#endif
- 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: /* we are out of FDs */
- server_out_of_fds(srv, NULL);
- break;
- default:
- ERROR("accept failed on fd=%d with error: (%d) %s", srv_socket->sock->fd, errno, strerror(errno));
- break;
- }
- return NULL;
- } else {
- connection *con;
-
- /* ok, we have the connection, register it */
-#if 0
- TRACE("appected() = %i", cnt);
-#endif
- srv->con_opened++;
-
- con = connections_get_new_connection(srv);
- con->sock->fd = cnt;
- con->sock->fde_ndx = -1;
-#if 0
- gettimeofday(&(con->start_tv), NULL);
-#endif
- fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
-
- connection_set_state(srv, con, CON_STATE_REQUEST_START);
-
- con->connection_start = srv->cur_ts;
- con->dst_addr = cnt_addr;
- buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
- con->srv_socket = srv_socket;
-
- if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
- ERROR("fcntl failed: %s", strerror(errno));
- connection_close(srv, con);
- return NULL;
- }
-
-#ifdef USE_OPENSSL
- /* connect FD to SSL */
- if (srv_socket->is_ssl) {
- if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
- ERROR("SSL: %s",
- ERR_error_string(ERR_get_error(), NULL));
- connection_close(srv, con);
- return NULL;
- }
-
-#ifndef OPENSSL_NO_TLSEXT
- SSL_set_app_data(con->sock->ssl, con);
-#endif
- SSL_set_accept_state(con->sock->ssl);
- con->conf.is_ssl=1;
-
- if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
- ERROR("SSL: %s",
- ERR_error_string(ERR_get_error(), NULL));
- connection_close(srv, con);
- return NULL;
- }
- }
-#endif
- return con;
- }
-}
-
-void connection_state_machine(server *srv, connection *con) {
- int done = 0, r;
- off_t bytes_moved = 0;
-#ifdef USE_OPENSSL
- server_socket *srv_sock = con->srv_socket;
-#endif
-
- if (srv->srvconf.log_state_handling) {
- TRACE("state at start for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- while (done == 0) {
- size_t ostate = con->state;
- int b;
-
- switch (con->state) {
- case CON_STATE_CONNECT:
- if (srv->srvconf.log_state_handling) {
- TRACE("state for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- chunkqueue_reset(con->recv_raw); /* this is a new connection, trash the pipeline */
-
- con->request_count = 0;
-
- break;
- case CON_STATE_REQUEST_START:
- /* init the request handling */
- if (srv->srvconf.log_state_handling) {
- TRACE("state for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- con->request_start = srv->cur_ts; /* start of the request */
- con->read_idle_ts = srv->cur_ts; /* start a read-call() */
-
- con->request_count++; /* max-keepalive requests */
- con->loops_per_request = 0; /* infinite loops */
-
- /* if the content was short enough, it might have a header already in the pipe */
- if (con->recv_raw->first &&
- chunkqueue_length(con->recv_raw) - con->recv_raw->first->offset > 0) {
- /* pipelining */
-
- switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
- case PARSE_ERROR:
- con->http_status = 400; /* the header is broken */
- con->keep_alive = 0;
-
- chunkqueue_remove_finished_chunks(con->recv_raw);
-
- connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
- break;
- case PARSE_NEED_MORE:
- /* the read() call is on the way */
- connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER);
- break;
- case PARSE_SUCCESS:
- /* pipelining worked, validate the header */
- chunkqueue_remove_finished_chunks(con->recv_raw);
-
- connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER);
- break;
- default:
- chunkqueue_remove_finished_chunks(con->recv_raw);
- TRACE("%s", "(error)");
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
- } else {
- connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER);
- }
-
- break;
- case CON_STATE_READ_REQUEST_HEADER:
- /* read us much data as needed into the recv_raw-cq for a valid header */
- if (srv->srvconf.log_state_handling) {
- TRACE("state for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- switch (connection_handle_read_request_header(srv, con)) {
- case HANDLER_GO_ON: /** we have a full header, or connection close */
- if (con->state == CON_STATE_READ_REQUEST_HEADER) {
- connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER);
- }
- break;
- case HANDLER_FINISHED: /** parsing failed, ->http_status is set */
- connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
- break;
- case HANDLER_WAIT_FOR_EVENT:
- return;
- case HANDLER_ERROR:
- TRACE("%s", "(error)");
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- default:
- TRACE("%s", "(error)");
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
- break;
- case CON_STATE_VALIDATE_REQUEST_HEADER:
- /* we have the full header, parse it */
-
- http_request_parse(srv, con, con->http_req);
-
- if (con->http_status != 0) {
- con->keep_alive = 0;
- con->send->is_closed = 1; /* there is no content */
-
- connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
- } else if (array_get_element(con->request.headers, CONST_STR_LEN("Expect"))) {
- /* write */
- con->http_status = 100;
- con->send->is_closed = 1;
-
- connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
- } else {
- /* parsing the request went fine
- * let's find a handler for this request */
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
- }
-
- break;
- case CON_STATE_HANDLE_REQUEST_HEADER:
- /* the request header is parsed,
- * find someone who wants to handle this request */
-
- if (srv->srvconf.log_state_handling) {
- TRACE("state for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- switch (r = handle_get_backend(srv, con)) {
- case HANDLER_GO_ON:
- case HANDLER_FINISHED:
- break;
- case HANDLER_WAIT_FOR_FD:
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
-
- server_out_of_fds(srv, con);
-
- break;
- case HANDLER_COMEBACK:
- done = -1;
- case HANDLER_WAIT_FOR_EVENT:
- /* come back here */
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
-
- break;
- case HANDLER_ERROR:
- /* something went wrong */
- TRACE("%s", "(error)");
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- default:
- TRACE("handle_get_backend returned %d on fd %d", r, con->sock->fd);
- break;
- }
-
- if (r != HANDLER_FINISHED && r != HANDLER_GO_ON) break;
-
- if (con->http_status == 404 ||
- con->http_status == 403) {
- /* 404 error-handler */
-
- if (con->in_error_handler == 0 &&
- (!buffer_is_empty(con->conf.error_handler) ||
- !buffer_is_empty(con->error_handler))) {
- /* call error-handler */
-
- con->error_handler_saved_status = con->http_status;
- con->http_status = 0;
-
- if (buffer_is_empty(con->error_handler)) {
- buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
- } else {
- buffer_copy_string_buffer(con->request.uri, con->error_handler);
- }
- buffer_reset(con->physical.path);
-
- con->in_error_handler = 1;
-
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
-
- /* need to reset condition cache since request uri changed. */
- config_cond_cache_reset(srv, con);
-
- done = -1;
- break;
- } else if (con->in_error_handler) {
- /* error-handler is a 404 */
-
- /* continue as normal, status is the same */
- ERROR("Warning: Either the error-handler returned status 404 or the error-handler itself was not found: %s", SAFE_BUF_STR(con->request.uri));
- ERROR("returning the original status: %i", con->error_handler_saved_status);
- ERROR("%s", "If this is a rails app: check your production.log");
- con->http_status = con->error_handler_saved_status;
- }
- } else if (con->in_error_handler) {
- /* error-handler is back and has generated content */
- /* if Status: was set, take it otherwise use 200 */
- con->http_status = con->error_handler_saved_status;
- }
-
- if (con->http_status == 0) con->http_status = 200;
-
- /* the backend is prepared, forward the content */
- connection_set_state(srv, con, CON_STATE_READ_REQUEST_CONTENT);
-
- break;
- case CON_STATE_READ_REQUEST_CONTENT:
- /* the request-handle is setup, read all the data and push it into the request-handler */
-
- if (con->request.content_length == -1 ||
- con->request.content_length == 0) {
- con->recv->is_closed = 1;
- }
-
- if (!con->recv->is_closed &&
- con->recv->bytes_in < con->request.content_length) {
- switch (connection_handle_read_request_content(srv, con)) {
- case HANDLER_GO_ON:
- break;
- case HANDLER_ERROR:
- TRACE("%s", "(error)");
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- case HANDLER_WAIT_FOR_EVENT:
- break;
- default:
- ERROR("%s", "oops, unknown return value: ...");
- }
-
- if (con->recv->bytes_in == con->request.content_length) {
- /* we read everything */
- fdevent_event_del(srv->ev, con->sock);
- con->recv->is_closed = 1;
- }
- chunkqueue_remove_finished_chunks(con->recv_raw);
- }
-
- chunkqueue_remove_finished_chunks(con->recv);
-
- /*
- * this should call the backend
- * they might build the connection now or stream the content to the upstream server
- * */
-
- switch(r = plugins_call_handle_send_request_content(srv, con)) {
- case HANDLER_GO_ON:
- /* everything was forwarded */
- break;
- case HANDLER_FINISHED:
- /* oops, we don't want this here */
- break;
- case HANDLER_COMEBACK:
- break;
- case HANDLER_WAIT_FOR_EVENT:
- return;
- default:
- /* something strange happened */
- TRACE("(error) plugins_call_handle_send_request_content(): r = %d", r);
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
-
- chunkqueue_remove_finished_chunks(con->recv);
-
- /* jump back, this should be proceeded by mod_staticfile */
- if (r == HANDLER_COMEBACK && con->mode == DIRECT) {
- connection_set_state(srv,con,CON_STATE_HANDLE_REQUEST_HEADER);
- break;
- }
-
- if (con->state == CON_STATE_ERROR) break;
-
- if (con->recv->is_closed &&
- con->recv->bytes_in == con->recv->bytes_out) {
- /* everything we read is sent */
- connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
- }
-
- break;
- case CON_STATE_HANDLE_RESPONSE_HEADER:
- /* handle the HTTP response headers, or generate error-page */
- connection_handle_response_header(srv, con);
-
- /* we got a response header from the backend
- * call all plugins who want to modify the response header
- * - mod_compress/deflate
- * - HTTP/1.1 chunking
- *
- */
- switch (plugins_call_handle_response_header(srv, con)) {
- case HANDLER_GO_ON:
- case HANDLER_FINISHED:
- break;
- case HANDLER_WAIT_FOR_EVENT:
- /* need to wait for more data */
- return;
- default:
- /* something strange happened */
- if (con->conf.log_request_handling) {
- TRACE("%s", "handle response header failed");
- }
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
-
- if (con->state == CON_STATE_ERROR) break;
-
- /* all the response-headers are set, check if we have a */
-
- connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
-
- break;
- case CON_STATE_WRITE_RESPONSE_HEADER:
- /* write response headers */
- http_response_write_header(srv, con, con->send_raw);
-
- connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_CONTENT);
-
- if (con->request.http_method == HTTP_METHOD_HEAD) {
- /* remove the content now */
- chunkqueue_reset(con->send);
-
- con->send->is_closed = 1;
- }
-
- break;
- case CON_STATE_WRITE_RESPONSE_CONTENT:
- fdevent_event_del(srv->ev, con->sock);
-
- con->write_request_ts = srv->cur_ts;
-
- /* looks like we shall read some content from the backend */
- switch (plugins_call_handle_read_response_content(srv, con)) {
- case HANDLER_WAIT_FOR_EVENT:
- if (!con->send->is_closed && con->send->bytes_in == con->send->bytes_out) {
- /* need to wait for more data */
- return;
- }
- break;
- case HANDLER_GO_ON:
- case HANDLER_FINISHED:
- break;
- default:
- /* something strange happened */
- if (con->conf.log_request_handling) {
- TRACE("%s", "read response content failed");
- }
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
-
- if (con->state == CON_STATE_ERROR) break;
-
- /* we might have new content in the con->send buffer
- * encode it for the network
- * - chunking
- * - compression
- */
- switch (plugins_call_handle_filter_response_content(srv, con)) {
- case HANDLER_GO_ON:
- case HANDLER_FINISHED:
- break;
- case HANDLER_WAIT_FOR_EVENT:
- /* need to wait for more data */
- return;
- default:
- /* something strange happened */
- if (con->conf.log_request_handling) {
- TRACE("%s", "filter response content failed");
- }
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
-
- if (con->state == CON_STATE_ERROR) break;
-
- /* copy output from filters into send_raw. */
- bytes_moved = filter_chain_copy_output(con->send_filters, con->send_raw);
-
- /**
- * check that all previous filters have cleaned there chunkqueue
- */
- if (con->send_raw->is_closed) {
- filter *f;
-
- for (f = con->send_filters->first;
- f;
- f = f->next) {
- off_t cq_len;
-
- cq_len = chunkqueue_length(f->cq);
-
- if (cq_len > 0) {
- TRACE("filter[%d] is not empty: %jd (report me)", f->id, (intmax_t) cq_len);
- }
- }
- }
-
-
- /* limit download speed. */
- if (con->traffic_limit_reached) {
- return;
- }
-
- /* no response data available to send right now. wait for more. */
- if (!con->send_raw->is_closed &&
- con->send_raw->bytes_in == con->send_raw->bytes_out) {
- return;
- }
-
- switch(network_write_chunkqueue(srv, con, con->send_raw)) {
- case NETWORK_STATUS_SUCCESS:
- /* we send everything from the chunkqueue and the chunkqueue-sender signaled it is finished */
- if (con->send_raw->is_closed) {
- if (con->http_status == 100) {
- /* send out the 100 Continue header and handle the request as normal afterwards */
- con->http_status = 0;
-
- /* cleanup send chunkqueue's. */
- chunkqueue_reset(con->send);
- chunkqueue_reset(con->send_raw);
-
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
- } else {
- connection_set_state(srv, con, CON_STATE_RESPONSE_END);
- }
- } else {
- /* still have data to send in send_raw queue */
- fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
- return;
- }
- break;
- case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
- TRACE("%s", "(network-subsys sent us a fatal-error)");
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- case NETWORK_STATUS_WAIT_FOR_AIO_EVENT:
- return;
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
-
- return;
- case NETWORK_STATUS_WAIT_FOR_FD:
- /* the backend received a EMFILE
- * - e.g. for a mmap() of /dev/zero */
-
- server_out_of_fds(srv, con);
-
- return;
- case NETWORK_STATUS_INTERRUPTED:
- case NETWORK_STATUS_UNSET:
- break;
- }
-
-
- break;
- case CON_STATE_RESPONSE_END: /* transient */
- /* log the request */
-
- if (srv->srvconf.log_state_handling) {
- TRACE("state for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- plugins_call_handle_response_done(srv, con);
-
- srv->con_written++;
-
- if (con->keep_alive) {
- connection_set_state(srv, con, CON_STATE_REQUEST_START);
-
-#if 0
- con->request_start = srv->cur_ts;
- con->read_idle_ts = srv->cur_ts;
-#endif
- } else {
- switch(r = plugins_call_handle_connection_close(srv, con)) {
- case HANDLER_GO_ON:
- case HANDLER_FINISHED:
- break;
- default:
- ERROR("unhandled return value from plugins_call_handle_connection_close: %i", r);
- break;
- }
-
- connection_close(srv, con);
-
- srv->con_closed++;
- }
-
- connection_reset(srv, con);
-
- break;
- case CON_STATE_CLOSE:
- if (srv->srvconf.log_state_handling) {
- TRACE("state for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- if (con->keep_alive) {
- if (ioctl(con->sock->fd, FIONREAD, &b)) {
- ERROR("ioctl() failed: %s", strerror(errno));
- }
- if (b > 0) {
- char buf[1024];
- ERROR("CLOSE-read() for fd %i, %i bytes", con->sock->fd, b);
-
- /* */
- sockread(con->sock->fd, buf, sizeof(buf));
- } else {
- /* nothing to read */
-
- con->close_timeout_ts = srv->cur_ts - 2;
- }
- } else {
- con->close_timeout_ts = srv->cur_ts - 2;
- }
-
- if (srv->cur_ts - con->close_timeout_ts > 1) {
- connection_close(srv, con);
-
- if (srv->srvconf.log_state_handling) {
- TRACE("connection closed for fd %i", con->sock->fd);
- }
- }
-
- break;
- case CON_STATE_ERROR: /* transient */
- /* even if the connection was drop we still have to write it to the access log */
- if (con->http_status) {
- plugins_call_handle_response_done(srv, con);
- }
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- int ret;
- switch ((ret = SSL_shutdown(con->sock->ssl))) {
- case 1:
- /* ok */
- break;
- case 0:
- SSL_shutdown(con->sock->ssl);
- break;
- default:
- ERROR("SSL (%i): %s",
- SSL_get_error(con->sock->ssl, ret),
- ERR_error_string(ERR_get_error(), NULL));
- break;
- }
- }
-#endif
-
- switch(con->mode) {
- case DIRECT:
-#if 0
- TRACE("emergency exit for fd %i: direct", con->sock->fd);
-#endif
- break;
- default:
- switch(r = plugins_call_handle_connection_close(srv, con)) {
- case HANDLER_GO_ON:
- case HANDLER_FINISHED:
- break;
- default:
- ERROR("unhandled return value from plugins_call_handle_connection_close: %i", r);
- break;
- }
- break;
- }
-
- connection_reset(srv, con);
-
- /* close the connection */
- if ((con->keep_alive == 1) &&
- (0 == shutdown(con->sock->fd, SHUT_WR))) {
- con->close_timeout_ts = srv->cur_ts;
- connection_set_state(srv, con, CON_STATE_CLOSE);
-
- if (srv->srvconf.log_state_handling) {
- TRACE("shutdown for fd %i", con->sock->fd);
- }
- } else {
- connection_close(srv, con);
- }
-
- con->keep_alive = 0;
-
- srv->con_closed++;
-
- break;
- default:
- ERROR("unknown state for fd %i: %i", con->sock->fd, con->state);
- connection_set_state(srv, con, CON_STATE_ERROR);
- break;
- }
-
- if (done == -1) {
- done = 0;
- } else if (ostate == con->state) {
- done = 1;
- }
- }
-
- if (srv->srvconf.log_state_handling) {
- TRACE("state at exit for fd %i: %s", con->sock->fd, connection_get_state(con->state));
- }
-
- return;
-}
diff --git a/src/connections.h b/src/connections.h
deleted file mode 100644
index 1d15b806..00000000
--- a/src/connections.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _CONNECTIONS_H_
-#define _CONNECTIONS_H_
-
-#include "settings.h"
-#include "server.h"
-#include "fdevent.h"
-
-LI_API connection* connection_init(server *srv);
-LI_API int connection_reset(server *srv, connection *con);
-LI_API void connections_free(server *srv);
-
-LI_API connection* connection_accept(server *srv, server_socket *srv_sock);
-LI_API int connection_close(server *srv, connection *con);
-
-LI_API int connection_set_state(server *srv, connection *con, connection_state_t state);
-LI_API const char * connection_get_state(connection_state_t state);
-LI_API const char * connection_get_short_state(connection_state_t state);
-LI_API void connection_state_machine(server *srv, connection *con);
-
-#endif
diff --git a/src/crc32.c b/src/crc32.c
deleted file mode 100644
index cdad7bce..00000000
--- a/src/crc32.c
+++ /dev/null
@@ -1,82 +0,0 @@
-#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(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/src/crc32.h b/src/crc32.h
deleted file mode 100644
index 22b112d9..00000000
--- a/src/crc32.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __crc32cr_table_h__
-#define __crc32cr_table_h__
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/types.h>
-#include <stdlib.h>
-
-#if defined HAVE_STDINT_H
-#include <stdint.h>
-#elif defined HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
-#ifdef _WIN32
-#define uint32_t unsigned __int32
-#endif
-
-#include "settings.h"
-
-LI_API uint32_t generate_crc32c(char *string, size_t length);
-
-#endif
diff --git a/src/data_array.c b/src/data_array.c
deleted file mode 100644
index c07effb5..00000000
--- a/src/data_array.c
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "array.h"
-
-static data_unset *data_array_copy(const data_unset *s) {
- data_array *src = (data_array *)s;
- data_array *ds = data_array_init();
-
- buffer_copy_string_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->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) {
- data_array *ds;
-
- ds = calloc(1, sizeof(*ds));
-
- ds->key = buffer_init();
- ds->value = array_init();
-
- ds->copy = data_array_copy;
- ds->free = data_array_free;
- ds->reset = data_array_reset;
- ds->insert_dup = data_array_insert_dup;
- ds->print = data_array_print;
- ds->type = TYPE_ARRAY;
-
- return ds;
-}
diff --git a/src/data_config.c b/src/data_config.c
deleted file mode 100644
index 8e2e75d6..00000000
--- a/src/data_config.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "array.h"
-
-static data_unset *data_config_copy(const data_unset *s) {
- data_config *src = (data_config *)s;
- data_config *ds = data_config_init();
-
- buffer_copy_string_buffer(ds->key, src->key);
- buffer_copy_string_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_key);
-
- array_free(ds->value);
- array_free(ds->childs);
-
- if (ds->string) buffer_free(ds->string);
-#ifdef HAVE_PCRE_H
- if (ds->regex) pcre_free(ds->regex);
- if (ds->regex_study) pcre_free(ds->regex_study);
-#endif
-
- free(d);
-}
-
-static void data_config_reset(data_unset *d) {
- data_config *ds = (data_config *)d;
-
- /* reused array elements */
- buffer_reset(ds->key);
- buffer_reset(ds->comp_key);
- array_reset(ds->value);
-}
-
-static int data_config_insert_dup(data_unset *dst, data_unset *src) {
- UNUSED(dst);
-
- src->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, "$%s %s \"%s\" {\n",
- ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
- 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 = strlen(du->key->ptr);
- 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->print(du, depth);
- fprintf(stdout, "\n");
- }
-
- if (ds->childs) {
- fprintf(stdout, "\n");
- for (i = 0; i < ds->childs->used; i ++) {
- data_unset *du = ds->childs->data[i];
-
- /* only the 1st block of chaining */
- if (NULL == ((data_config *)du)->prev) {
- fprintf(stdout, "\n");
- array_print_indent(depth);
- du->print(du, depth);
- fprintf(stdout, "\n");
- }
- }
- }
-
- if (0 != ds->context_ndx) {
- depth --;
- array_print_indent(depth);
- fprintf(stdout, "}");
-
- fprintf(stdout, " # end of $%s %s \"%s\"",
- ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
- }
-
- if (ds->next) {
- fprintf(stdout, "\n");
- array_print_indent(depth);
- fprintf(stdout, "else ");
- ds->next->print((data_unset *)ds->next, depth);
- }
-}
-
-data_config *data_config_init(void) {
- data_config *ds;
-
- ds = calloc(1, sizeof(*ds));
-
- ds->key = buffer_init();
- ds->op = buffer_init();
- ds->comp_key = buffer_init();
- ds->value = array_init();
- ds->childs = array_init();
- ds->childs->is_weakref = 1;
-
- ds->copy = data_config_copy;
- ds->free = data_config_free;
- ds->reset = data_config_reset;
- ds->insert_dup = data_config_insert_dup;
- ds->print = data_config_print;
- ds->type = TYPE_CONFIG;
-
- return ds;
-}
diff --git a/src/data_count.c b/src/data_count.c
deleted file mode 100644
index 5c5a5f06..00000000
--- a/src/data_count.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "array.h"
-
-static data_unset *data_count_copy(const data_unset *s) {
- data_count *src = (data_count *)s;
- data_count *ds = data_count_init();
-
- buffer_copy_string_buffer(ds->key, src->key);
- ds->count = src->count;
- ds->is_index_key = src->is_index_key;
- return (data_unset *)ds;
-}
-
-static void data_count_free(data_unset *d) {
- data_count *ds = (data_count *)d;
-
- buffer_free(ds->key);
-
- free(d);
-}
-
-static void data_count_reset(data_unset *d) {
- data_count *ds = (data_count *)d;
-
- buffer_reset(ds->key);
-
- ds->count = 0;
-}
-
-static int data_count_insert_dup(data_unset *dst, data_unset *src) {
- data_count *ds_dst = (data_count *)dst;
- data_count *ds_src = (data_count *)src;
-
- ds_dst->count += ds_src->count;
-
- src->free(src);
-
- return 0;
-}
-
-static void data_count_print(const data_unset *d, int depth) {
- data_count *ds = (data_count *)d;
- UNUSED(depth);
-
- fprintf(stdout, "count(%d)", ds->count);
-}
-
-
-data_count *data_count_init(void) {
- data_count *ds;
-
- ds = calloc(1, sizeof(*ds));
-
- ds->key = buffer_init();
- ds->count = 1;
-
- ds->copy = data_count_copy;
- ds->free = data_count_free;
- ds->reset = data_count_reset;
- ds->insert_dup = data_count_insert_dup;
- ds->print = data_count_print;
- ds->type = TYPE_COUNT;
-
- return ds;
-}
diff --git a/src/data_integer.c b/src/data_integer.c
deleted file mode 100644
index 54234077..00000000
--- a/src/data_integer.c
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "array.h"
-
-static data_unset *data_integer_copy(const data_unset *s) {
- data_integer *src = (data_integer *)s;
- data_integer *ds = data_integer_init();
-
- buffer_copy_string_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_reset(ds->key);
- ds->value = 0;
-}
-
-static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
- UNUSED(dst);
-
- src->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) {
- data_integer *ds;
-
- ds = calloc(1, sizeof(*ds));
-
- ds->key = buffer_init();
- ds->value = 0;
-
- ds->copy = data_integer_copy;
- ds->free = data_integer_free;
- ds->reset = data_integer_reset;
- ds->insert_dup = data_integer_insert_dup;
- ds->print = data_integer_print;
- ds->type = TYPE_INTEGER;
-
- return ds;
-}
diff --git a/src/data_string.c b/src/data_string.c
deleted file mode 100644
index 1b9da692..00000000
--- a/src/data_string.c
+++ /dev/null
@@ -1,121 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "array.h"
-
-static data_unset *data_string_copy(const data_unset *s) {
- data_string *src = (data_string *)s;
- data_string *ds = data_string_init();
-
- buffer_copy_string_buffer(ds->key, src->key);
- buffer_copy_string_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 (ds_dst->value->used) {
- buffer_append_string_len(ds_dst->value, CONST_STR_LEN(", "));
- buffer_append_string_buffer(ds_dst->value, ds_src->value);
- } else {
- buffer_copy_string_buffer(ds_dst->value, ds_src->value);
- }
-
- src->free(src);
-
- return 0;
-}
-
-static int data_response_insert_dup(data_unset *dst, data_unset *src) {
- data_string *ds_dst = (data_string *)dst;
- data_string *ds_src = (data_string *)src;
-
- if (ds_dst->value->used) {
- buffer_append_string_len(ds_dst->value, CONST_STR_LEN("\r\n"));
- buffer_append_string_buffer(ds_dst->value, ds_dst->key);
- buffer_append_string_len(ds_dst->value, CONST_STR_LEN(": "));
- buffer_append_string_buffer(ds_dst->value, ds_src->value);
- } else {
- buffer_copy_string_buffer(ds_dst->value, ds_src->value);
- }
-
- src->free(src);
-
- return 0;
-}
-
-
-static void data_string_print(const data_unset *d, int depth) {
- data_string *ds = (data_string *)d;
- unsigned int i = 0;
- UNUSED(depth);
-
- // empty and uninitialized strings
- if (ds->value->used < 1) {
- fputs("\"\"", stdout);
- return;
- }
-
- // print out the string as is, except prepend " with backslash
- putc('"', stdout);
- for (i = 0; i < ds->value->used - 1; i++) {
- unsigned char c = ds->value->ptr[i];
- if (c == '"') {
- fputs("\\\"", stdout);
- } else {
- putc(c, stdout);
- }
- }
- putc('"', stdout);
-}
-
-
-data_string *data_string_init(void) {
- data_string *ds;
-
- ds = calloc(1, sizeof(*ds));
- assert(ds);
-
- ds->key = buffer_init();
- ds->value = buffer_init();
-
- ds->copy = data_string_copy;
- ds->free = data_string_free;
- ds->reset = data_string_reset;
- ds->insert_dup = data_string_insert_dup;
- ds->print = data_string_print;
- ds->type = TYPE_STRING;
-
- return ds;
-}
-
-data_string *data_response_init(void) {
- data_string *ds;
-
- ds = data_string_init();
- ds->insert_dup = data_response_insert_dup;
-
- return ds;
-}
diff --git a/src/etag.c b/src/etag.c
deleted file mode 100644
index 0e16c598..00000000
--- a/src/etag.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <string.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#if defined HAVE_STDINT_H
-#include <stdint.h>
-#elif defined HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
-#include "buffer.h"
-#include "etag.h"
-
-int etag_is_equal(buffer *etag, const char *matches) {
- if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
- return 0;
-}
-
-int etag_create(buffer *etag, struct stat *st, etag_flags_t flags) {
-
- if (0 == flags) return 0;
-
- buffer_reset(etag);
-
- if (flags & ETAG_USE_INODE) {
- buffer_append_off_t(etag, st->st_ino);
- buffer_append_string_len(etag, CONST_STR_LEN("-"));
- }
- if (flags & ETAG_USE_SIZE) {
- buffer_append_off_t(etag, st->st_size);
- buffer_append_string_len(etag, CONST_STR_LEN("-"));
- }
- if (flags & ETAG_USE_MTIME) {
- buffer_append_long(etag, st->st_mtime);
- }
- return 0;
-}
-
-int etag_mutate(buffer *mut, buffer *etag) {
- size_t i;
- uint32_t h;
-
- for (h=0, i=0; i < etag->used-1; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
-
- buffer_reset(mut);
- buffer_copy_string_len(mut, CONST_STR_LEN("\""));
- buffer_append_long(mut, h);
- buffer_append_string_len(mut, CONST_STR_LEN("\""));
-
- return 0;
-}
diff --git a/src/etag.h b/src/etag.h
deleted file mode 100644
index 80e9ab9c..00000000
--- a/src/etag.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef ETAG_H
-#define ETAG_H
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "buffer.h"
-
-typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t;
-
-LI_API int etag_is_equal(buffer *etag, const char *matches);
-LI_API int etag_create(buffer *etag, struct stat *st, etag_flags_t flags);
-LI_API int etag_mutate(buffer *mut, buffer *etag);
-
-
-#endif
diff --git a/src/fastcgi.h b/src/fastcgi.h
deleted file mode 100644
index 31c00ad6..00000000
--- a/src/fastcgi.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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 $
- */
-
-#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/src/fcgi-stat-accel.c b/src/fcgi-stat-accel.c
deleted file mode 100644
index bae39e6b..00000000
--- a/src/fcgi-stat-accel.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- compile with:
-
- $ gcc -lfcgi -lpthread fcgi-stat-accel.c -o fcgi-stat-accel
-
- fcgi-stat-accel will use the PHP_FCGI_CHILDREN environment variable to set the thread count.
-
- The default value, if spawned from lighttpd, is 20.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <string.h>
-#include <fcntl.h>
-
-#include <stdlib.h>
-#ifdef HAVE_FASTCGI_FASTCGI_H
-#include <fastcgi/fcgiapp.h>
-#elif defined (HAVE_FASTCGI_H)
-#include <fcgiapp.h>
-#endif
-
-#define THREAD_COUNT 20
-
-#define FORBIDDEN(stream) \
- FCGX_FPrintF(stream, "Status: 403 Forbidden\r\nContent-Type: text/html\r\n\r\n<h1>403 Forbidden</h1>\n");
-#define NOTFOUND(stream, filename) \
- FCGX_FPrintF(stream, "Status: 404 Not Found\r\nContent-Type: text/html\r\n\r\n<h1>404 Not Found</h1>\r\n%s", filename);
-#define SENDFILE(stream, filename) \
- FCGX_FPrintF(stream, "X-LIGHTTPD-send-file: %s\r\n\r\n", filename);
-
-#define UNUSED(x) ( (void)(x) )
-
-static void *doit(void *a){
- FCGX_Request request;
- int rc;
- char *filename;
- UNUSED(a);
-
- FCGX_InitRequest(&request, 0, /* FCGI_FAIL_ACCEPT_ON_INTR */ 0);
-
- while(1){
- int fd;
- //Some platforms require accept() serialization, some don't. The documentation claims it to be thread safe
-// static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
-// pthread_mutex_lock(&accept_mutex);
- rc = FCGX_Accept_r(&request);
-// pthread_mutex_unlock(&accept_mutex);
-
- if(rc < 0)
- break;
-
- //get the filename
- if((filename = FCGX_GetParam("SCRIPT_FILENAME", request.envp)) == NULL){
- FORBIDDEN(request.out);
- //don't try to open directories
- }else if(filename[strlen(filename)-1] == '/'){
- FORBIDDEN(request.out);
- //open the file
- }else if((fd = open(filename, O_RDONLY)) == -1){
- NOTFOUND(request.out, filename);
- //no error, serve it
- }else{
- SENDFILE(request.out, filename);
-
- close(fd);
- }
-
- FCGX_Finish_r(&request);
- }
- return NULL;
-}
-
-int main(void){
- int i,j,thread_count;
- pthread_t* id;
- char* env_val;
-
- FCGX_Init();
-
- thread_count = THREAD_COUNT;
- env_val = getenv("PHP_FCGI_CHILDREN");
- if (env_val != NULL) {
- j = atoi(env_val);
- if (j != 0) {
- thread_count = j;
- };
- };
-
- id = malloc(sizeof(*id) * thread_count);
-
- for (i = 0; i < thread_count; i++) {
- pthread_create(&id[i], NULL, doit, NULL);
- }
-
- /* block the current thread by executing one */
- doit(NULL);
-
- for (i = 0; i < thread_count; i++) {
- pthread_join(id[i], NULL);
- }
-
- free(id);
-
- return 0;
-}
-
diff --git a/src/fdevent.c b/src/fdevent.c
deleted file mode 100644
index 9386b1d9..00000000
--- a/src/fdevent.c
+++ /dev/null
@@ -1,390 +0,0 @@
-#include <sys/types.h>
-
-#include "settings.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "fdevent.h"
-#include "buffer.h"
-#include "log.h"
-
-#include "sys-socket.h"
-
-static fdevent_handler_info_t fdevent_handlers[] = {
- /* - poll is most reliable
- * - select works everywhere
- * - linux-* are experimental
- */
- {
- FDEVENT_HANDLER_LINUX_SYSEPOLL,
- "linux-sysepoll",
- "epoll (Linux 2.6)",
-#ifdef USE_LINUX_EPOLL
- fdevent_linux_sysepoll_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_POLL,
- "poll",
- "poll (Unix)",
-#ifdef USE_POLL
- fdevent_poll_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_SELECT,
- "select",
- "select (generic)",
-#ifdef USE_SELECT
- fdevent_select_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_LINUX_RTSIG,
- "linux-rtsig",
- "rt-signals (Linux 2.4+)",
-#ifdef USE_LINUX_SIGIO
- fdevent_linux_rtsig_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll",
- "/dev/poll (Solaris)",
-#ifdef USE_SOLARIS_DEVPOLL
- fdevent_solaris_devpoll_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_FREEBSD_KQUEUE,
- "freebsd-kqueue",
- "kqueue (FreeBSD)",
-#ifdef USE_FREEBSD_KQUEUE
- fdevent_freebsd_kqueue_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_FREEBSD_KQUEUE,
- "kqueue",
- "kqueue (FreeBSD)",
-#ifdef USE_FREEBSD_KQUEUE
- fdevent_freebsd_kqueue_init
-#else
- NULL
-#endif
- },
- {
- FDEVENT_HANDLER_UNSET,
- NULL,
- NULL,
- NULL
- }
-};
-
-
-
-const fdevent_handler_info_t *fdevent_get_handlers() {
- return fdevent_handlers;
-}
-
-const fdevent_handler_info_t *fdevent_get_defaulthandler() {
- const fdevent_handler_info_t *handler = fdevent_get_handlers();
-
- while (handler->name) {
- if (handler->init) {
- return handler;
- }
- handler ++;
- }
-
- return NULL;
-}
-
-const fdevent_handler_info_t *fdevent_get_handler_info_by_type(fdevent_handler_t type) {
- const fdevent_handler_info_t *handler = fdevent_get_handlers();
-
- while (handler->name) {
- if (type == handler->type) {
- return handler;
- }
- handler ++;
- }
-
- return NULL;
-}
-
-const fdevent_handler_info_t *fdevent_get_handler_info_by_name(const char *name) {
- const fdevent_handler_info_t *handler = fdevent_get_handlers();
-
- while (handler->name) {
- if (strcmp(name, handler->name) == 0) {
- return handler;
- }
- handler ++;
- }
-
- return NULL;
-}
-
-fdevent_revent *fdevent_revent_init(void) {
- STRUCT_INIT(fdevent_revent, revent);
-
- return revent;
-}
-
-void fdevent_revent_free(fdevent_revent *revent) {
- if (!revent) return;
-
- free(revent);
-}
-
-fdevent_revents *fdevent_revents_init(void) {
- STRUCT_INIT(fdevent_revents, revents);
-
- return revents;
-}
-
-void fdevent_revents_reset(fdevent_revents *revents) {
- if (!revents) return;
-
- revents->used = 0;
-}
-
-void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
- fdevent_revent *revent;
-
- if (revents->used == revents->size) {
- /* resize the events-array */
- revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
- revents->ptr[revents->size++] = fdevent_revent_init();
- }
-
- revent = revents->ptr[revents->used++];
- revent->fd = fd;
- revent->revents = events;
-}
-
-void fdevent_revents_free(fdevent_revents *revents) {
- size_t i;
-
- if (!revents) return;
-
- if (revents->size) {
- for (i = 0; i < revents->size; i++) {
- fdevent_revent_free(revents->ptr[i]);
- }
-
- free(revents->ptr);
- }
- free(revents);
-}
-
-fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
- fdevents *ev;
- const fdevent_handler_info_t *handler = fdevent_get_handler_info_by_type(type);
-
- ev = calloc(1, sizeof(*ev));
- ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
- ev->maxfds = maxfds;
-
- assert(handler && handler->init);
- if (0 != handler->init(ev)) {
- switch(type) {
- case FDEVENT_HANDLER_POLL:
- ERROR("event-handler poll failed %s", "");
- return NULL;
-
- case FDEVENT_HANDLER_SELECT:
- ERROR("event-handler select failed %s", "");
- return NULL;
-
- default:
- if (0 != fdevent_linux_rtsig_init(ev)) {
- ERROR("event-handler '%s' failed, use 'poll' or 'select' instead", handler->name);
-
- return NULL;
- }
- }
- }
-
- return ev;
-}
-
-void fdevent_free(fdevents *ev) {
- size_t i;
- if (!ev) return;
-
- if (ev->free) ev->free(ev);
-
- for (i = 0; i < ev->maxfds; i++) {
- if (ev->fdarray[i]) free(ev->fdarray[i]);
- }
-
- free(ev->fdarray);
- free(ev);
-}
-
-int fdevent_reset(fdevents *ev) {
- if (ev->reset) return ev->reset(ev);
-
- return 0;
-}
-
-static fdnode *fdnode_init() {
- fdnode *fdn;
-
- fdn = calloc(1, sizeof(*fdn));
- fdn->fd = -1;
-
- return fdn;
-}
-
-static void fdnode_free(fdnode *fdn) {
- free(fdn);
-}
-
-/* Unix file descriptors begin at zero for each process, but not so win32.
-The fdevent system uses the file descriptors as indexers into the fdarray, but we can't
-just do that on windows. Lazily, this is O(n) on the number of file descriptors/sockets, but
-with select's limit of 64 events, this is not really a bottleneck. For the sake of win32,
-it would be nice if all file/socket descriptors were references to IO devices in our own
-global table, instead of just using the system-provided fd directly.
-*/
-#ifdef _WIN32
-
-size_t fdevent_find_free_slot(fdevents *ev, int fd) {
- size_t i;
- for ( i = 0; i < ev->maxfds; i++ )
- {
- if ( ev->fdarray[i] == NULL )
- return i;
- }
- SEGFAULT("no more free fdevent.fdarray slots: %s", "");
- return -1;
-}
-
-size_t fdevent_find_slot(fdevents *ev, int fd) {
- size_t i;
- for ( i = 0; i < ev->maxfds; i++ )
- {
- if ( ev->fdarray[i] && ev->fdarray[i]->fd == fd ) return i;
- }
- DebugBreak();
- return -1;
-}
-
-#else
-
-#define fdevent_find_free_slot( ev, fd ) (fd)
-#define fdevent_find_slot( ev, fd ) (fd)
-
-#endif
-
-int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
- fdnode *fdn;
- size_t fda_ndx;
-
- fda_ndx = fdevent_find_free_slot(ev, sock->fd);
-
- fdn = fdnode_init();
- fdn->handler = handler;
- fdn->fd = sock->fd;
- fdn->ctx = ctx;
-
- ev->fdarray[fda_ndx] = fdn;
-
- return 0;
-}
-
-int fdevent_unregister(fdevents *ev, iosocket *sock) {
- fdnode *fdn;
- size_t fda_ndx;
- if (!ev) return 0;
- fda_ndx = fdevent_find_slot(ev, sock->fd);
-
- fdn = ev->fdarray[fda_ndx];
-
- fdnode_free(fdn);
-
- ev->fdarray[fda_ndx] = NULL;
-
- return 0;
-}
-
-int fdevent_event_del(fdevents *ev, iosocket *sock) {
- if (ev->event_del) ev->event_del(ev, sock);
-
- return 0;
-}
-
-int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
- if (ev->event_add) ev->event_add(ev, sock, events);
-
- return 0;
-}
-
-int fdevent_poll(fdevents *ev, int timeout_ms) {
- if (ev->poll == NULL) SEGFAULT("ev->poll is %p", (void*) (intptr_t) ev->poll);
- return ev->poll(ev, timeout_ms);
-}
-
-int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
- size_t i;
-
- if (ev->get_revents == NULL) SEGFAULT("ev->get_revents is %p", (void*) (intptr_t) ev->get_revents);
-
- fdevent_revents_reset(revents);
-
- ev->get_revents(ev, event_count, revents);
- /* select() reports more events, as it counts per event and per fd (e.g. READ+WRITE on one fd == two events) */
- /* assert(revents->used == event_count); */
-
- /* patch the event handlers */
- for (i = 0; i < revents->used; i++) {
- size_t fda_ndx;
- fdevent_revent *r = revents->ptr[i];
-
- fda_ndx = fdevent_find_slot(ev, r->fd);
-
- r->handler = ev->fdarray[fda_ndx]->handler;
- r->context = ev->fdarray[fda_ndx]->ctx;
- }
-
- return 0;
-}
-
-int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
-#ifdef _WIN32
- int i = 1;
-#endif
-#ifdef FD_CLOEXEC
- /* close fd on exec (cgi) */
- fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
-#endif
- if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
-#ifdef O_NONBLOCK
- return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
-#elif defined _WIN32
- return ioctlsocket(sock->fd, FIONBIO, &i);
-#else
- return 0;
-#endif
-}
-
-
diff --git a/src/fdevent.h b/src/fdevent.h
deleted file mode 100644
index 13ae07f7..00000000
--- a/src/fdevent.h
+++ /dev/null
@@ -1,280 +0,0 @@
-#ifndef _FDEVENT_H_
-#define _FDEVENT_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "settings.h"
-#include "bitset.h"
-
-#include "iosocket.h"
-#include "array-static.h"
-
-/* select event-system */
-
-#if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
-# if defined HAVE_STDINT_H
-# include <stdint.h>
-# endif
-# define USE_LINUX_EPOLL
-# include <sys/epoll.h>
-#endif
-
-/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
- * under /usr/include/sys/ */
-#if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
-# define USE_POLL
-# ifdef HAVE_POLL_H
-# include <poll.h>
-# else
-# include <sys/poll.h>
-# endif
-# if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
-# define USE_LINUX_SIGIO
-# include <signal.h>
-# endif
-#endif
-#ifdef _WIN32
-# define HAVE_SELECT
-#endif
-#if defined HAVE_SELECT
-# ifdef _WIN32
-# include <winsock2.h>
-# endif
-# define USE_SELECT
-# ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-# endif
-#endif
-
-#if defined HAVE_SYS_DEVPOLL_H && defined(__sun)
-# define USE_SOLARIS_DEVPOLL
-# include <sys/devpoll.h>
-#endif
-
-#if defined HAVE_SYS_EVENT_H && defined HAVE_KQUEUE
-# define USE_FREEBSD_KQUEUE
-# include <sys/event.h>
-#endif
-
-#if defined HAVE_SYS_PORT_H && defined HAVE_PORT_CREATE
-# define USE_SOLARIS_PORT
-# include <sys/port.h>
-#endif
-
-
-typedef handler_t (*fdevent_handler)(void *srv, void *ctx, int revents);
-
-#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)
-
-typedef enum { FD_EVENT_TYPE_UNSET = -1,
- FD_EVENT_TYPE_CONNECTION,
- FD_EVENT_TYPE_FCGI_CONNECTION,
- FD_EVENT_TYPE_DIRWATCH,
- FD_EVENT_TYPE_CGI_CONNECTION
-} fd_event_t;
-
-typedef enum { FDEVENT_HANDLER_UNSET,
- FDEVENT_HANDLER_SELECT,
- FDEVENT_HANDLER_POLL,
- FDEVENT_HANDLER_LINUX_RTSIG,
- FDEVENT_HANDLER_LINUX_SYSEPOLL,
- FDEVENT_HANDLER_SOLARIS_DEVPOLL,
- FDEVENT_HANDLER_FREEBSD_KQUEUE,
- FDEVENT_HANDLER_SOLARIS_PORT
-} fdevent_handler_t;
-
-/**
- * a mapping from fd to connection structure
- *
- */
-typedef struct {
- int fd; /**< the fd */
- void *conn; /**< a reference the corresponding data-structure */
- fd_event_t fd_type; /**< type of the fd */
- int events; /**< registered events */
- int revents;
-} fd_conn;
-
-ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
-
-/**
- * revents
- */
-typedef struct {
- int fd;
- int revents;
-
- fdevent_handler handler;
- void *context;
-} fdevent_revent;
-
-ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
-
-/**
- * array of unused fd's
- *
- */
-
-typedef struct _fdnode {
- fdevent_handler handler; /* who handles the events for this fd */
- void *ctx; /* opaque pointer which is passed as 3rd parameter to the handler */
- int fd; /* fd */
-
- struct _fdnode *prev, *next;
-} fdnode;
-
-typedef struct {
- int *ptr;
-
- size_t used;
- size_t size;
-} buffer_int;
-
-/**
- * fd-event handler for select(), poll() and rt-signals on Linux 2.4
- *
- */
-typedef struct fdevents {
- fdevent_handler_t type;
-
- fdnode **fdarray; /* a list of fdnodes */
- size_t maxfds;
-
-#ifdef USE_LINUX_SIGIO
- int in_sigio;
- int signum;
- sigset_t sigset;
- siginfo_t siginfo;
- bitset *sigbset;
-#endif
-#ifdef USE_LINUX_EPOLL
- int epoll_fd;
- struct epoll_event *epoll_events;
-#endif
-#ifdef USE_POLL
- struct pollfd *pollfds;
-
- size_t size;
- size_t used;
-
- buffer_int unused;
-#endif
-#ifdef USE_SELECT
- /* Temporary sets, cloned from permanent sets, and passed to select() */
- fd_set select_read;
- fd_set select_write;
- fd_set select_error;
-
- /* Permanent sets */
- fd_set select_set_read;
- fd_set select_set_write;
- fd_set select_set_error;
-
- /* Since windows socket IDs are as good as unpredictable, we need to keep track of each one.
- *nix socket IDs start at zero for each process and are reused throughout the life of the process. */
-#ifdef _WIN32
- /* We could simply use select_set_error, because that is currently always inclusive,
- but better to keep it separate. */
- fd_set select_set_all;
-#else
- int select_max_fd;
-#endif
-#endif
-
-
-#ifdef USE_SOLARIS_DEVPOLL
- int devpoll_fd;
- struct pollfd *devpollfds;
-#endif
-#ifdef USE_FREEBSD_KQUEUE
- int kq_fd;
- struct kevent *kq_results;
- bitset *kq_read_bevents;
- bitset *kq_write_bevents;
-#endif
-#ifdef USE_SOLARIS_PORT
- int port_fd;
-#endif
- int (*reset)(struct fdevents *ev);
- void (*free)(struct fdevents *ev);
-
- int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
- int (*event_del)(struct fdevents *ev, iosocket *sock);
- int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
-
- int (*poll)(struct fdevents *ev, int timeout_ms);
-
- int (*fcntl_set)(struct fdevents *ev, int fd);
-} fdevents;
-
-typedef struct {
- fdevent_handler_t type;
- const char *name;
- const char *description;
- int (*init)(fdevents *ev);
-} fdevent_handler_info_t;
-
-LI_API const fdevent_handler_info_t *fdevent_get_handlers();
-LI_API const fdevent_handler_info_t *fdevent_get_defaulthandler();
-LI_API const fdevent_handler_info_t *fdevent_get_handler_info_by_type(fdevent_handler_t type);
-LI_API const fdevent_handler_info_t *fdevent_get_handler_info_by_name(const char *name);
-
-LI_API fdevents* fdevent_init(size_t maxfds, fdevent_handler_t type);
-LI_API int fdevent_reset(fdevents *ev);
-LI_API void fdevent_free(fdevents *ev);
-
-/**
- * call the plugin for the number of available events
- */
-LI_API int fdevent_poll(fdevents *ev, int timeout_ms);
-/**
- * get all available events
- */
-LI_API int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
-
-/**
- * add or remove a fd to the handled-pool
- */
-LI_API int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
-LI_API int fdevent_unregister(fdevents *ev, iosocket *sock);
-
-/**
- * add a event to a registered fd
- */
-LI_API int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
-LI_API int fdevent_event_del(fdevents *ev, iosocket *sock);
-
-/**
- * set non-blocking
- */
-LI_API int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
-
-LI_API fdevent_revents* fdevent_revents_init(void);
-LI_API void fdevent_revents_reset(fdevent_revents *revents);
-LI_API void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
-LI_API void fdevent_revents_free(fdevent_revents *revents);
-
-LI_API fdevent_revent* fdevent_revent_init(void);
-LI_API void fdevent_revent_free(fdevent_revent *revent);
-
-
-/**
- * plugin init
- */
-LI_API int fdevent_select_init(fdevents *ev);
-LI_API int fdevent_poll_init(fdevents *ev);
-LI_API int fdevent_linux_rtsig_init(fdevents *ev);
-LI_API int fdevent_linux_sysepoll_init(fdevents *ev);
-LI_API int fdevent_solaris_devpoll_init(fdevents *ev);
-LI_API int fdevent_freebsd_kqueue_init(fdevents *ev);
-
-#endif
-
-
-
diff --git a/src/fdevent_freebsd_kqueue.c b/src/fdevent_freebsd_kqueue.c
deleted file mode 100644
index 64af9a91..00000000
--- a/src/fdevent_freebsd_kqueue.c
+++ /dev/null
@@ -1,221 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-
-#include "server.h"
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
-#ifdef USE_FREEBSD_KQUEUE
-#include <sys/event.h>
-#include <sys/time.h>
-
-#include "sys-files.h"
-#include "log.h"
-
-static int fdevent_freebsd_kqueue_event_add(fdevents *ev, iosocket *sock, int events);
-
-static void fdevent_freebsd_kqueue_free(fdevents *ev) {
- close(ev->kq_fd);
- free(ev->kq_results);
- bitset_free(ev->kq_read_bevents);
- bitset_free(ev->kq_write_bevents);
-}
-
-static int fdevent_freebsd_kqueue_event_del(fdevents *ev, iosocket *sock) {
- int ret;
-
- if (sock->fde_ndx < 0) return -1;
-
- /* delete events */
- ret = fdevent_freebsd_kqueue_event_add(ev, sock, 0);
- sock->fde_ndx = -1;
- return 0;
-}
-
-static int fdevent_freebsd_kqueue_event_add(fdevents *ev, iosocket *sock, int events) {
- int ret;
- struct kevent kev[2];
- struct timespec ts;
- int nchanges = 0;
- int changed_events = 0;
-
- if (bitset_test_bit(ev->kq_read_bevents, sock->fd)) {
- changed_events |= FDEVENT_IN;
- }
- if (bitset_test_bit(ev->kq_write_bevents, sock->fd)) {
- changed_events |= FDEVENT_OUT;
- }
- /* use XOR on changed_events and events to see which events changed. */
- changed_events ^= events;
-
- if (changed_events & FDEVENT_IN) {
- /* add/delete FDEVENT_IN */
- if (events & FDEVENT_IN) {
- /* add */
- EV_SET(&(kev[nchanges]), sock->fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
- nchanges++;
- bitset_set_bit(ev->kq_read_bevents, sock->fd);
- } else {
- /* delete */
- EV_SET(&(kev[nchanges]), sock->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
- nchanges++;
- bitset_clear_bit(ev->kq_read_bevents, sock->fd);
- }
- }
-
- if (changed_events & FDEVENT_OUT) {
- /* add/delete FDEVENT_OUT */
- if (events & FDEVENT_OUT) {
- /* add */
- EV_SET(&(kev[nchanges]), sock->fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
- nchanges++;
- bitset_set_bit(ev->kq_write_bevents, sock->fd);
- } else {
- /* delete */
- EV_SET(&(kev[nchanges]), sock->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
- nchanges++;
- bitset_clear_bit(ev->kq_write_bevents, sock->fd);
- }
- }
-
- if (nchanges == 0) return 0;
-
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
-
- ret = kevent(ev->kq_fd,
- kev, nchanges,
- NULL, 0,
- &ts);
-
- if (ret == -1) {
- ERROR("kqueue failed polling: %s\n", strerror(errno));
-
- return -1;
- }
-
- sock->fde_ndx = sock->fd;
-
- return 0;
-}
-
-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:
- fprintf(stderr, "%s.%d: kqueue failed polling: %s\n",
- __FILE__, __LINE__, strerror(errno));
- break;
- }
- }
-
- return ret;
-}
-
-static int fdevent_freebsd_kqueue_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
- size_t ndx;
-
- for (ndx = 0; ndx < event_count; ndx++) {
- int events = 0, e;
-
- 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) {
- events |= FDEVENT_HUP;
- }
-
- if (e & EV_ERROR) {
- events |= FDEVENT_ERR;
- }
-
- fdevent_revents_add(revents, ev->kq_results[ndx].ident, events);
- }
-
- return 0;
-}
-
-static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
- if (-1 == (ev->kq_fd = kqueue())) {
- fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- 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_add);
-
- SET(get_revents);
-
- ev->kq_fd = -1;
-
- ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
- ev->kq_read_bevents = bitset_init(ev->maxfds);
- ev->kq_write_bevents = bitset_init(ev->maxfds);
-
- /* check that kqueue works */
-
- if (-1 == (ev->kq_fd = kqueue())) {
- fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- return -1;
- }
-
- close(ev->kq_fd);
- ev->kq_fd = -1;
-
- return 0;
-}
-#else
-int fdevent_freebsd_kqueue_init(fdevents *ev) {
- UNUSED(ev);
-
- fprintf(stderr, "%s.%d: kqueue not available, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
-
- return -1;
-}
-#endif
diff --git a/src/fdevent_linux_rtsig.c b/src/fdevent_linux_rtsig.c
deleted file mode 100644
index 95bebf2a..00000000
--- a/src/fdevent_linux_rtsig.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <limits.h>
-
-#ifndef _GNU_SOURCE
-/* seems we dont need this when using _GNU_SOURCE
- * #define __USE_GNU
- */
-#define __USE_GNU
-#endif
-#include <fcntl.h>
-
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-#include "sys-process.h"
-#include "log.h"
-
-#ifdef USE_LINUX_SIGIO
-static void fdevent_linux_rtsig_free(fdevents *ev) {
- free(ev->pollfds);
- if (ev->unused.ptr) free(ev->unused.ptr);
-
- bitset_free(ev->sigbset);
-}
-
-
-static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
- if (sock->fde_ndx < 0) return -1;
-
- if ((size_t)sock->fde_ndx >= ev->used) {
- SEGFAULT("del! out of range %d %zu", sock->fde_ndx, ev->used);
- }
-
- if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
- size_t k = sock->fde_ndx;
-
- ev->pollfds[k].fd = -1;
-
- bitset_clear_bit(ev->sigbset, sock->fd);
-
- if (ev->unused.size == 0) {
- ev->unused.size = 16;
- ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
- } else if (ev->unused.size == ev->unused.used) {
- ev->unused.size += 16;
- ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
- }
-
- ev->unused.ptr[ev->unused.used++] = k;
- } else {
- SEGFAULT("del! %d %d", ev->pollfds[sock->fde_ndx].fd, sock->fd);
- }
- sock->fde_ndx = -1;
-
- return 0;
-}
-
-#if 0
-static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
- size_t j;
-
- if (ev->used == 0) return 0;
- if (ev->unused.used != 0) return 0;
-
- for (j = ev->used - 1; j + 1 > 0; j--) {
- if (ev->pollfds[j].fd == -1) ev->used--;
- }
-
-
- return 0;
-}
-#endif
-
-static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
- /* known index */
- if (sock->fde_ndx != -1) {
- if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
- ev->pollfds[sock->fde_ndx].events = events;
-
- return sock->fde_ndx;
- }
- SEGFAULT("add: (%d, %d)", sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
- }
-
- if (ev->unused.used > 0) {
- int k = ev->unused.ptr[--ev->unused.used];
-
- ev->pollfds[k].fd = sock->fd;
- ev->pollfds[k].events = events;
-
- bitset_set_bit(ev->sigbset, sock->fd);
-
- return k;
- } else {
- if (ev->size == 0) {
- ev->size = 16;
- ev->pollfds = malloc(sizeof(*ev->pollfds) * ev->size);
- } else if (ev->size == ev->used) {
- ev->size += 16;
- ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
- }
-
- ev->pollfds[ev->used].fd = sock->fd;
- ev->pollfds[ev->used].events = events;
-
- bitset_set_bit(ev->sigbset, sock->fd);
-
- return ev->used++;
- }
-}
-
-static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
- struct timespec ts;
- int r;
-
-#if 0
- fdevent_linux_rtsig_event_compress(ev);
-#endif
-
- ev->in_sigio = 1;
-
- ts.tv_sec = timeout_ms / 1000;
- ts.tv_nsec = (timeout_ms % 1000) * 1000000;
- r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
-
- if (r == -1) {
- if (errno == EAGAIN) return 0;
- return r;
- } else if (r == SIGIO) {
- struct sigaction act;
-
- /* flush the signal queue */
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_IGN;
- sigaction(ev->signum, &act, NULL);
-
- /* re-enable the signal queue */
- act.sa_handler = SIG_DFL;
- sigaction(ev->signum, &act, NULL);
-
- ev->in_sigio = 0;
- r = poll(ev->pollfds, ev->used, timeout_ms);
-
- return r;
- } else if (r == ev->signum) {
-# if 0
- fprintf(stderr, "event: %d %02lx\n", ev->siginfo.si_fd, ev->siginfo.si_band);
-# endif
- return bitset_test_bit(ev->sigbset, ev->siginfo.si_fd);
- } else {
- /* ? */
- return -1;
- }
-}
-
-static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
- UNUSED(event_count);
-
- if (ev->in_sigio == 1) {
- /* only one event */
-
- fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
- } else {
- size_t ndx;
-
- for (ndx = 0; ndx < ev->used; ndx++) {
- if (ev->pollfds[ndx].revents) {
- fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
- }
- }
- }
-
- return 0;
-}
-
-static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
- static pid_t pid = 0;
-
- if (pid == 0) pid = getpid();
-
- if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
-
- if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
-
- return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
-}
-
-
-int fdevent_linux_rtsig_init(fdevents *ev) {
- ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
-#define SET(x) \
- ev->x = fdevent_linux_rtsig_##x;
-
- SET(free);
- SET(poll);
-
- SET(event_del);
- SET(event_add);
-
- SET(fcntl_set);
- SET(get_revents);
-
- ev->signum = SIGRTMIN + 1;
-
- sigemptyset(&(ev->sigset));
- sigaddset(&(ev->sigset), ev->signum);
- sigaddset(&(ev->sigset), SIGIO);
- if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
- fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- return -1;
- }
-
- ev->in_sigio = 1;
-
- ev->sigbset = bitset_init(ev->maxfds);
-
- return 0;
-}
-#else
-int fdevent_linux_rtsig_init(fdevents *ev) {
- UNUSED(ev);
-
- fprintf(stderr, "%s.%d: linux-rtsig not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
- return -1;
-}
-#endif
diff --git a/src/fdevent_linux_sysepoll.c b/src/fdevent_linux_sysepoll.c
deleted file mode 100644
index 24a6cc9e..00000000
--- a/src/fdevent_linux_sysepoll.c
+++ /dev/null
@@ -1,147 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-#include "log.h"
-
-#include "sys-files.h"
-
-#ifdef USE_LINUX_EPOLL
-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, iosocket *sock) {
- struct epoll_event ep;
-
- if (sock->fde_ndx < 0) return -1;
-
- memset(&ep, 0, sizeof(ep));
-
- ep.data.fd = sock->fd;
- ep.data.ptr = NULL;
-
- if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
- SEGFAULT("epoll_ctl (del) failed on fd=%d: %s", sock->fd, strerror(errno));
-
- return 0;
- }
-
- sock->fde_ndx = -1;
-
- return 0;
-}
-
-static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
- struct epoll_event ep;
- int add = 0;
-
- /* a new fd */
- if (sock->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;
-
- /**
- *
- * 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 = sock->fd;
-
- if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
- SEGFAULT("epoll_ctl (add/mod) failed on fd=%d: %s", sock->fd, strerror(errno));
-
- return 0;
- }
-
- sock->fde_ndx = sock->fd;
-
- return 0;
-}
-
-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_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
- size_t ndx;
-
- for (ndx = 0; ndx < event_count; 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;
-
- fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, events);
- }
-
- return 0;
-}
-
-int fdevent_linux_sysepoll_init(fdevents *ev) {
- ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
-#define SET(x) \
- ev->x = fdevent_linux_sysepoll_##x;
-
- SET(free);
- SET(poll);
-
- SET(event_del);
- SET(event_add);
-
- SET(get_revents);
-
- if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
- ERROR("epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"",
- strerror(errno));
-
- return -1;
- }
-
- if (-1 == fcntl(ev->epoll_fd, F_SETFD, FD_CLOEXEC)) {
- ERROR("fcntl after epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"",
- strerror(errno));
-
- close(ev->epoll_fd);
-
- return -1;
- }
-
- ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));
-
- return 0;
-}
-
-#else
-int fdevent_linux_sysepoll_init(fdevents *ev) {
- UNUSED(ev);
-
- ERROR("event-handler 'linux-sysepoll' is not supported, try to set server.event-handler = \"%s\" or \"%s\"", "select", "poll");
-
- return -1;
-}
-#endif
diff --git a/src/fdevent_poll.c b/src/fdevent_poll.c
deleted file mode 100644
index ebf149c7..00000000
--- a/src/fdevent_poll.c
+++ /dev/null
@@ -1,153 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-#include "log.h"
-
-#ifdef USE_POLL
-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, iosocket *sock) {
- if (sock->fde_ndx < 0) return -1;
-
- if ((size_t)sock->fde_ndx >= ev->used) {
- SEGFAULT("(fdevent-poll-del) out of range %d %zd", sock->fde_ndx, ev->used);
- }
-
- if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
- size_t k = sock->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);
- } else if (ev->unused.size == ev->unused.used) {
- ev->unused.size += 16;
- ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
- }
-
- ev->unused.ptr[ev->unused.used++] = k;
- } else {
- SEGFAULT("(fdevent-poll-del) sock->fde_ndx: %d, sock->fd: %d -> stored fd: %d", sock->fde_ndx, sock->fd, ev->pollfds[sock->fde_ndx].fd);
- }
-
- sock->fde_ndx = -1;
-
- return 0;
-}
-
-#if 0
-static int fdevent_poll_event_compress(fdevents *ev) {
- size_t j;
-
- if (ev->used == 0) return 0;
- if (ev->unused.used != 0) return 0;
-
- for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
-
- return 0;
-}
-#endif
-
-static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
- if (sock->fde_ndx != -1) {
- /* this fd was already added, just change the requested events */
-
- if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
- ev->pollfds[sock->fde_ndx].events = events;
-
- return sock->fde_ndx;
- }
- SEGFAULT("(fdevent-poll-add) (%d, %d)", sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
- }
-
- if (ev->unused.used > 0) {
- int k = ev->unused.ptr[--ev->unused.used];
-
- ev->pollfds[k].fd = sock->fd;
- ev->pollfds[k].events = events;
-
- sock->fde_ndx = k;
-
- } else {
- if (ev->size == 0) {
- ev->size = 16;
- ev->pollfds = malloc(sizeof(*ev->pollfds) * ev->size);
- } else if (ev->size == ev->used) {
- ev->size += 16;
- ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
- }
-
- ev->pollfds[ev->used].fd = sock->fd;
- ev->pollfds[ev->used].events = events;
-
- sock->fde_ndx = ev->used++;
- }
- return 0;
-}
-
-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_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
- size_t ndx;
-
- UNUSED(event_count);
-
- for (ndx = 0; ndx < ev->used; ndx++) {
- if (ev->pollfds[ndx].revents) {
- if (ev->pollfds[ndx].revents & POLLNVAL) {
- /* should never happen */
- SEGFAULT("ev->pollfds[%zu].revents has POLLNVAL", ndx);
- }
-
- fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
- }
- }
-
- return 0;
-}
-
-int fdevent_poll_init(fdevents *ev) {
- ev->type = FDEVENT_HANDLER_POLL;
-#define SET(x) \
- ev->x = fdevent_poll_##x;
-
- SET(free);
- SET(poll);
-
- SET(event_del);
- SET(event_add);
-
- SET(get_revents);
-
- return 0;
-}
-
-#else
-int fdevent_poll_init(fdevents *ev) {
- UNUSED(ev);
-
- ERROR("event-handler 'poll' is not supported, try to set server.event-handler = \"%s\"", "select");
-
- return -1;
-}
-#endif
diff --git a/src/fdevent_select.c b/src/fdevent_select.c
deleted file mode 100644
index 66997da6..00000000
--- a/src/fdevent_select.c
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <stdio.h>
-
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
-#include "sys-socket.h"
-
-#ifdef HAVE_SYS_TIME_H
-/* struct timeval tv needs it on IRIX + MIPS pro*/
-#include <sys/time.h>
-#endif
-
-#ifdef 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));
-#ifdef _WIN32
- FD_ZERO(&(ev->select_set_all));
-#endif
-#ifndef _WIN32
- ev->select_max_fd = -1;
-#endif
-
- return 0;
-}
-
-static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
- if (sock->fde_ndx < 0) return -1;
-
- FD_CLR(sock->fd, &(ev->select_set_read));
- FD_CLR(sock->fd, &(ev->select_set_write));
- FD_CLR(sock->fd, &(ev->select_set_error));
-#ifdef _WIN32
- FD_CLR(sock->fd, &(ev->select_set_all));
-#endif
-
- /* mark the fdevent as deleted */
- sock->fde_ndx = -1;
-
- return 0;
-}
-
-static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
- /* we should be protected by max-fds, but you never know */
-#ifndef _WIN32
- assert(sock->fd < ((int)FD_SETSIZE));
-#endif
-
- if (events & FDEVENT_IN) {
- FD_SET(sock->fd, &(ev->select_set_read));
- FD_CLR(sock->fd, &(ev->select_set_write));
- }
- if (events & FDEVENT_OUT) {
- FD_CLR(sock->fd, &(ev->select_set_read));
- FD_SET(sock->fd, &(ev->select_set_write));
- }
- FD_SET(sock->fd, &(ev->select_set_error));
-
- /* we need this for the poll */
-#ifdef _WIN32
- FD_SET(sock->fd, &(ev->select_set_all));
-#else
- if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
-#endif
-
- /* mark fd as added */
- sock->fde_ndx = sock->fd;
-
- return 0;
-}
-
-static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
- struct timeval tv;
-#ifndef _WIN32
- int max_ev = ev->select_max_fd + 1;
-#else
- // windows ignores this
- int max_ev = 0;
-#endif
-
- 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(max_ev, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
-}
-
-/**
- * scan the fdset for events
- */
-static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
-
- int ndx = 0;
-#ifndef _WIN32
- int top = ev->select_max_fd + 1;
-#else
- int top = ev->select_set_all.fd_count; // FD_SETSIZE;
-#endif
-
- UNUSED(event_count);
-
- for (ndx = 0; ndx < top; ndx++) {
- int events = 0;
-
-#ifdef _WIN32
- int fdx = ev->select_set_all.fd_array[ndx];
- if ( fdx <= 0 ) continue;
-#else
- int fdx = ndx;
-#endif
-
- if (FD_ISSET(fdx, &(ev->select_read))) {
- events |= FDEVENT_IN;
- }
- if (FD_ISSET(fdx, &(ev->select_write))) {
- events |= FDEVENT_OUT;
- }
- if (FD_ISSET(fdx, &(ev->select_error))) {
- events |= FDEVENT_ERR;
- }
-
- if (events) {
- fdevent_revents_add(revents, fdx, events);
- }
- }
-
- return 0;
-}
-
-int fdevent_select_init(fdevents *ev) {
- ev->type = FDEVENT_HANDLER_SELECT;
-#define SET(x) \
- ev->x = fdevent_select_##x;
-
- SET(reset);
- SET(poll);
-
- SET(event_del);
- SET(event_add);
-
- SET(get_revents);
-
- return 0;
-}
-
-#else
-int fdevent_select_init(fdevents *ev) {
- UNUSED(ev);
-
- return -1;
-}
-#endif
diff --git a/src/fdevent_solaris_devpoll.c b/src/fdevent_solaris_devpoll.c
deleted file mode 100644
index 60364230..00000000
--- a/src/fdevent_solaris_devpoll.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-#include "log.h"
-
-#ifdef USE_SOLARIS_DEVPOLL
-#include <unistd.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))) {
- fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
- __FILE__, __LINE__,
- fd, strerror(errno));
-
- return -1;
- }
-
- return -1;
-}
-
-static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
- struct pollfd pfd;
- int add = 0;
-
- if (fde_ndx == -1) add = 1;
-
- pfd.fd = fd;
- pfd.events = events;
- pfd.revents = 0;
-
- if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
- fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
- __FILE__, __LINE__,
- fd, strerror(errno));
-
- 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_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
- size_t ndx;
-
- for (ndx = 0; ndx < event_count; ndx++) {
- if (ev->devpollfds[ndx].revents) {
- if (ev->devpollfds[ndx].revents & POLLNVAL) {
- /* should never happen */
- SEGFAULT("ev->devpollfds[%d].revents = %d (POLLNVAL)", ndx, ev->devpollfds[ndx].revents);
- }
-
- fdevent_revents_add(revents, ev->devpollfds[ndx].fd, ev->devpollfds[ndx].revents);
- }
- }
-
- return 0;
-}
-
-#if 0
-static int fdevent_solaris_devpoll_event_get_revent(fdevents *ev, size_t ndx) {
- return ev->devpollfds[ndx].revents;
-}
-
-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;
-}
-#endif
-
-int fdevent_solaris_devpoll_reset(fdevents *ev) {
- /* a forked process does only inherit the filedescriptor,
- * but every operation on the device will lead to a EACCES */
- if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
- fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- return -1;
- }
-
- if (fcntl(ev->devpoll_fd, F_SETFD, FD_CLOEXEC) < 0) {
- fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- close(ev->devpoll_fd);
-
- return -1;
- }
- 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_add);
-
-#if 0
- SET(event_next_fdndx);
- SET(event_get_fd);
- SET(event_get_revent);
-#endif
- SET(get_revents);
-
- ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
-
- if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
- fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- 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);
-
- fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
-
- return -1;
-}
-#endif
diff --git a/src/filter.c b/src/filter.c
deleted file mode 100644
index efb5eb65..00000000
--- a/src/filter.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/**
- * the network filter-API
- *
- *
- */
-
-#include <stdlib.h>
-
-#include <string.h>
-#include <assert.h>
-
-#include "filter.h"
-
-/**
- * create the filter
- *
- * each filter has a chunkqueue with content and
- * a prev and a next pointer
- */
-static filter *filter_init(void) {
- filter *fl;
-
- fl = calloc(1, sizeof(*fl));
-
- fl->next = NULL;
- fl->prev = NULL;
-
- fl->cq = chunkqueue_init();
-
- return fl;
-}
-
-/**
- * free the filter
- */
-static void filter_free(filter *fl) {
- filter *next, *prev;
-
- /* free chunkqueue */
- if(fl->cq) {
- chunkqueue_free(fl->cq);
- }
-
- /* remove this filter from chain. */
- next = fl->next;
- prev = fl->prev;
-
- if(next) {
- next->prev = prev;
- }
- if(prev) {
- prev->next = next;
- }
-
- free(fl);
-}
-
-/**
- * reset the filter
- */
-static void filter_reset(filter *fl) {
- /* reset chunkqueue */
- if(fl->cq) {
- chunkqueue_reset(fl->cq);
- } else {
- fl->cq = chunkqueue_init();
- }
-}
-
-/**
- * create a filter chain
- */
-filter_chain *filter_chain_init(void) {
- filter_chain *chain;
-
- chain = calloc(1, sizeof(*chain));
-
- chain->first = NULL;
- chain->last = NULL;
- filter_chain_create_filter(chain, FILTER_ID_INPUT);
-
- return chain;
-}
-
-void filter_chain_free(filter_chain *chain) {
- filter *first;
- if (!chain) return;
-
- /* free all filters, after the first filter */
- first = chain->first;
- while(first->next) {
- filter_free(first->next);
- }
- /* free first filter */
- filter_free(first);
-
- free(chain);
-}
-
-void filter_chain_reset(filter_chain *chain) {
- filter *first;
- if (!chain) return;
-
- /* free all filters, except first filter */
- first = chain->first;
- while(first->next) {
- filter_free(first->next);
- }
- /* reset first filter */
- filter_reset(first);
- chain->last = first;
-}
-
-filter *filter_chain_create_filter(filter_chain *chain, int id) {
- filter *fl;
- if (!chain) return NULL;
-
- fl = filter_init();
- fl->id = id;
- /* add filter to end of chain. */
- if (chain->last != NULL) {
- chain->last->next = fl;
- }
- fl->prev = chain->last;
- chain->last = fl;
- if (chain->first == NULL) {
- chain->first = fl;
- }
-
- return fl;
-}
-
-filter *filter_chain_get_filter(filter_chain *chain, int id) {
- filter *fl;
- if (!chain) return NULL;
-
- /* find filter with id */
- fl = chain->first;
- while(fl) {
- if (fl->id == id) break;
- fl = fl->next;
- }
-
- return fl;
-}
-
-void filter_chain_remove_filter(filter_chain *chain, filter *fl) {
- if (!chain || !fl) return;
-
- if (chain->first == fl) {
- chain->first = fl->next;
- }
- if (chain->last == fl) {
- chain->last = fl->prev;
- }
- filter_free(fl);
-}
-
-/**
- * move all the content of the last filter to the chunk queue
- */
-off_t filter_chain_copy_output(filter_chain *chain, chunkqueue *out) {
- off_t total;
- chunkqueue *in;
-
- if (!chain || !out) return 0;
- if (out->is_closed) return 0;
-
- in = chain->last->cq;
- total = chunkqueue_steal_all_chunks(out, in);
- in->bytes_out += total;
- out->bytes_in += total;
-
- chunkqueue_remove_finished_chunks(in);
-
- if (in->is_closed) {
- out->is_closed = 1;
- }
-
- return total;
-}
-
diff --git a/src/filter.h b/src/filter.h
deleted file mode 100644
index 91749d42..00000000
--- a/src/filter.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _FILTER_H_
-#define _FILTER_H_
-
-#include "chunk.h"
-
-#define FILTER_ID_INPUT -1
-
-/*
- * The filter chain will always have an input filter to hold
- * the pre-filtered content. All other filters are added after
- * the last filter.
- *
- * Each filter uses the chunkqueue from the previous filter as
- * input and outputs to it's own chunkqueue.
- *
- */
-
-typedef struct filter {
- struct filter *prev;
- struct filter *next;
-
- int id; /* use plugin id */
- chunkqueue *cq; /* this filters output */
-} filter;
-
-typedef struct {
- filter *first;
- filter *last;
-
-} filter_chain;
-
-LI_API filter_chain * filter_chain_init(void);
-LI_API void filter_chain_free(filter_chain *chain);
-LI_API void filter_chain_reset(filter_chain *chain);
-
-LI_API filter * filter_chain_create_filter(filter_chain *chain, int id);
-LI_API filter * filter_chain_get_filter(filter_chain *chain, int id);
-LI_API void filter_chain_remove_filter(filter_chain *chain, filter *fl);
-
-LI_API off_t filter_chain_copy_output(filter_chain *chain, chunkqueue *out);
-
-#endif
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
deleted file mode 100644
index a16eec49..00000000
--- a/src/http-header-glue.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
-#include "base.h"
-#include "array.h"
-#include "buffer.h"
-#include "log.h"
-#include "etag.h"
-#include "response.h"
-
-/*
- * This was 'borrowed' from tcpdump.
- *
- *
- * This is fun.
- *
- * In older BSD systems, socket addresses were fixed-length, and
- * "sizeof (struct sockaddr)" gave the size of the structure.
- * All addresses fit within a "struct sockaddr".
- *
- * In newer BSD systems, the socket address is variable-length, and
- * there's an "sa_len" field giving the length of the structure;
- * this allows socket addresses to be longer than 2 bytes of family
- * and 14 bytes of data.
- *
- * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
- * variant of the old BSD scheme (with "struct sockaddr_storage" rather
- * than "struct sockaddr"), and some use the new BSD scheme.
- *
- * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
- * macro that determines the size based on the address family. Other
- * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
- * but not in the final version). On the latter systems, we explicitly
- * check the AF_ type to determine the length; we assume that on
- * all those systems we have "struct sockaddr_storage".
- */
-
-#ifdef HAVE_IPV6
-# ifndef SA_LEN
-# ifdef HAVE_SOCKADDR_SA_LEN
-# define SA_LEN(addr) ((addr)->sa_len)
-# else /* HAVE_SOCKADDR_SA_LEN */
-# ifdef HAVE_STRUCT_SOCKADDR_STORAGE
-static size_t get_sa_len(const struct sockaddr *addr) {
- switch (addr->sa_family) {
-
-# ifdef AF_INET
- case AF_INET:
- return (sizeof (struct sockaddr_in));
-# endif
-
-# ifdef AF_INET6
- case AF_INET6:
- return (sizeof (struct sockaddr_in6));
-# endif
-
- default:
- return (sizeof (struct sockaddr));
-
- }
-}
-# define SA_LEN(addr) (get_sa_len(addr))
-# else /* HAVE_SOCKADDR_STORAGE */
-# define SA_LEN(addr) (sizeof (struct sockaddr))
-# endif /* HAVE_SOCKADDR_STORAGE */
-# endif /* HAVE_SOCKADDR_SA_LEN */
-# endif /* SA_LEN */
-#endif
-
-
-
-
-int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
- data_string *ds;
-
- UNUSED(srv);
-
- if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
- ds = data_response_init();
- }
- buffer_copy_string_len(ds->key, key, keylen);
- buffer_copy_string_len(ds->value, value, vallen);
-
- array_insert_unique(con->response.headers, (data_unset *)ds);
-
- return 0;
-}
-
-int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
- data_string *ds;
-
- UNUSED(srv);
-
- /* if there already is a key by this name overwrite the value */
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key, keylen))) {
- buffer_copy_string(ds->value, value);
-
- return 0;
- }
-
- return response_header_insert(srv, con, key, keylen, value, vallen);
-}
-
-
-int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
- data_string *ds;
-
- UNUSED(srv);
-
- /* if there already is a key by this name append the value */
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key, keylen))) {
- buffer_append_string_len(ds->value, CONST_STR_LEN(", "));
- buffer_append_string_len(ds->value, value, vallen);
- return 0;
- }
-
- return response_header_insert(srv, con, key, keylen, value, vallen);
-}
-
-int http_response_redirect_to_directory(server *srv, connection *con) {
- buffer *o;
-
- o = buffer_init();
-
- if (con->conf.is_ssl) {
- buffer_copy_string_len(o, CONST_STR_LEN("https://"));
- } else {
- buffer_copy_string_len(o, CONST_STR_LEN("http://"));
- }
- if (con->uri.authority->used) {
- buffer_append_string_buffer(o, con->uri.authority);
- } else {
- /* get the name of the currently connected socket */
- struct hostent *he;
-#ifdef HAVE_IPV6
- char hbuf[256];
-#endif
- sock_addr our_addr;
- socklen_t our_addr_len;
-
- our_addr_len = sizeof(our_addr);
-
- if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
- con->http_status = 500;
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "can't get sockname", strerror(errno));
-
- buffer_free(o);
- return 0;
- }
-
-
- /* Lookup name: secondly try to get hostname for bind address */
- switch(our_addr.plain.sa_family) {
-#ifdef HAVE_IPV6
- case AF_INET6:
- if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
- SA_LEN((const struct sockaddr *)&our_addr.ipv6),
- hbuf, sizeof(hbuf), NULL, 0, 0)) {
-
- char dst[INET6_ADDRSTRLEN];
-
- ERROR("NOTICE: getnameinfo() failed: %s, using ip-address instead",
- strerror(errno));
-
- buffer_append_string(o,
- inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
- dst, sizeof(dst)));
- } else {
- buffer_append_string(o, hbuf);
- }
- break;
-#endif
- case AF_INET:
- if (NULL == (he = gethostbyaddr((char *)&our_addr.ipv4.sin_addr, sizeof(struct in_addr), AF_INET))) {
- ERROR("NOTICE: gethostbyaddr() failed: %d, using ip-address instead",
- h_errno);
-
- buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
- } else {
- buffer_append_string(o, he->h_name);
- }
- break;
- default:
- ERROR("ERROR: unsupported address-type, %d", our_addr.plain.sa_family);
-
- buffer_free(o);
- return -1;
- }
-
- if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
- (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
- buffer_append_string_len(o, CONST_STR_LEN(":"));
- buffer_append_long(o, srv->srvconf.port);
- }
- }
- buffer_append_string_buffer(o, con->uri.path);
- buffer_append_string_len(o, CONST_STR_LEN("/"));
- if (!buffer_is_empty(con->uri.query)) {
- buffer_append_string_len(o, CONST_STR_LEN("?"));
- buffer_append_string_buffer(o, con->uri.query);
- }
-
- response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
-
- con->http_status = 301;
- con->send->is_closed = 1; /* no content */
-
- buffer_free(o);
-
- return 0;
-}
-
-buffer * strftime_cache_get(server *srv, time_t last_mod) {
- struct tm *tm;
- size_t i;
-
- for (i = 0; i < FILE_CACHE_MAX; i++) {
- /* found cache-entry */
- if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
-
- /* found empty slot */
- if (srv->mtime_cache[i].mtime == 0) break;
- }
-
- if (i == FILE_CACHE_MAX) {
- i = 0;
- }
-
- srv->mtime_cache[i].mtime = last_mod;
- buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
- tm = gmtime(&(srv->mtime_cache[i].mtime));
- srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
- srv->mtime_cache[i].str->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", tm);
- srv->mtime_cache[i].str->used++;
-
- return srv->mtime_cache[i].str;
-}
-
-
-int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
- data_string *http_if_none_match;
- data_string *http_if_modified_since;
-
- 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.
- */
-
- http_if_none_match = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("if-none-match"));
- http_if_modified_since = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("if-modified-since"));
-
- /* last-modified handling */
- if (http_if_none_match) {
- if (etag_is_equal(con->physical.etag, BUF_STR(http_if_none_match->value))) {
- if (con->request.http_method == HTTP_METHOD_GET ||
- con->request.http_method == HTTP_METHOD_HEAD) {
-
- /* check if etag + last-modified */
- if (http_if_modified_since) {
- size_t used_len;
- char *semicolon;
-
- if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) {
- used_len = http_if_modified_since->value->used - 1;
- } else {
- used_len = semicolon - BUF_STR(http_if_modified_since->value);
- }
-
- if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) {
- if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
- return HANDLER_FINISHED;
- } else {
-#ifdef HAVE_STRPTIME
- char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
- time_t t_header, t_file;
- struct tm tm;
-
- /* check if we can safely copy the string */
- if (used_len >= sizeof(buf)) {
- TRACE("last-mod check failed as timestamp was too long: %s: %zu, %zu",
- SAFE_BUF_STR(http_if_modified_since->value),
- used_len, sizeof(buf) - 1);
-
- con->http_status = 412;
- return HANDLER_FINISHED;
- }
-
-
- strncpy(buf, BUF_STR(http_if_modified_since->value), used_len);
- buf[used_len] = '\0';
-
- if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
- con->http_status = 412;
- return HANDLER_FINISHED;
- }
- tm.tm_isdst = 0;
- t_header = mktime(&tm);
-
- strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
- tm.tm_isdst = 0;
- t_file = mktime(&tm);
-
- if (t_file > t_header) return HANDLER_GO_ON;
-
- con->http_status = 304;
- return HANDLER_FINISHED;
-#else
- return HANDLER_GO_ON;
-#endif
- }
- } else {
- con->http_status = 304;
- return HANDLER_FINISHED;
- }
- } else {
- con->http_status = 412;
- return HANDLER_FINISHED;
- }
- }
- } else if (http_if_modified_since) {
- size_t used_len;
- char *semicolon;
-
- if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) {
- used_len = http_if_modified_since->value->used - 1;
- } else {
- used_len = semicolon - BUF_STR(http_if_modified_since->value);
- }
-
- if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) {
- if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
- return HANDLER_FINISHED;
- } else {
-#ifdef HAVE_STRPTIME
- char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
- time_t t_header, t_file;
- struct tm tm;
-
- /* convert to timestamp */
- if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
-
- strncpy(buf, BUF_STR(http_if_modified_since->value), used_len);
- buf[used_len] = '\0';
-
- if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
- 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;
-#else
- return HANDLER_GO_ON;
-#endif
- }
- }
-
- return HANDLER_GO_ON;
-}
diff --git a/src/http_auth.c b/src/http_auth.c
deleted file mode 100644
index 357f4a1b..00000000
--- a/src/http_auth.c
+++ /dev/null
@@ -1,1252 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_CRYPT_H
-# include <crypt.h>
-#elif defined(__linux__)
-/* linux needs _XOPEN_SOURCE */
-#endif
-
-#ifdef HAVE_LIBCRYPT
-# define HAVE_CRYPT
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include "server.h"
-#include "log.h"
-#include "http_auth.h"
-#include "http_auth_digest.h"
-#include "stream.h"
-
-#include "inet_ntop_cache.h"
-
-#include "sys-strings.h"
-#include "sys-files.h"
-
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-
-typedef li_MD5_CTX MD5_CTX;
-#define MD5_Init li_MD5_Init
-#define MD5_Update li_MD5_Update
-#define MD5_Final li_MD5_Final
-
-#endif
-
-/**
- * the $apr1$ handling is taken from apache 1.3.x
- */
-
-/*
- * The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0
- * MD5 crypt() function, which is licenced as follows:
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- */
-
-handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
-#ifdef USE_LDAP
-void auth_ldap_cleanup(ldap_plugin_config *p);
-#endif
-
-static const char base64_pad = '=';
-
-/* "A-Z a-z 0-9 + /" maps to 0-63 */
-static const short base64_reverse_table[256] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 - 0x0F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 - 0x1F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 - 0x2F */
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 - 0x3F */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4F */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 - 0x5F */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6F */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 - 0x7F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 - 0x8F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 - 0x9F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 - 0xAF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 - 0xBF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 - 0xCF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 - 0xDF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 - 0xEF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xF0 - 0xFF */
-};
-
-
-static unsigned char * base64_decode(buffer *out, const char *in) {
- unsigned char *result;
- int ch, j = 0, k;
- size_t i;
-
- size_t in_len = strlen(in);
-
- buffer_prepare_copy(out, in_len);
-
- result = (unsigned char *)out->ptr;
-
- ch = in[0];
- /* run through the whole string, converting as we go */
- for (i = 0; i < in_len; i++) {
- ch = (unsigned char) in[i];
-
- if (ch == '\0') break;
-
- if (ch == base64_pad) break;
-
- ch = base64_reverse_table[ch];
- if (ch < 0) continue;
-
- switch(i % 4) {
- case 0:
- result[j] = ch << 2;
- break;
- case 1:
- result[j++] |= ch >> 4;
- result[j] = (ch & 0x0f) << 4;
- break;
- case 2:
- result[j++] |= ch >>2;
- result[j] = (ch & 0x03) << 6;
- break;
- case 3:
- result[j++] |= ch;
- break;
- }
- }
- k = j;
- /* mop things up if we ended on a boundary */
- if (ch == base64_pad) {
- switch(i % 4) {
- case 0:
- case 1:
- return NULL;
- case 2:
- k++;
- case 3:
- result[k++] = 0;
- }
- }
- result[k] = '\0';
-
- out->used = k;
-
- return result;
-}
-
-static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
- int ret = -1;
-
- if (!username->used|| !realm->used) return -1;
-
- if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
- stream f;
- char * f_line;
-
- if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
-
- if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
-
- return -1;
- }
-
- f_line = f.start;
-
- while (f_line - f.start != f.size) {
- char *f_user, *f_pwd, *e, *f_realm;
- size_t u_len, pwd_len, r_len;
-
- f_user = f_line;
-
- /*
- * htdigest format
- *
- * user:realm:md5(user:realm:password)
- */
-
- if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "parsed error in", p->conf.auth_htdigest_userfile,
- "expected 'username:realm:hashed password'");
-
- stream_close(&f);
-
- return -1;
- }
-
- if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "parsed error in", p->conf.auth_plain_userfile,
- "expected 'username:realm:hashed password'");
-
- stream_close(&f);
-
- return -1;
- }
-
- /* get pointers to the fields */
- u_len = f_realm - f_user;
- f_realm++;
- r_len = f_pwd - f_realm;
- f_pwd++;
-
- if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
- pwd_len = e - f_pwd;
- } else {
- pwd_len = f.size - (f_pwd - f.start);
- }
-
- if (username->used - 1 == u_len &&
- (realm->used - 1 == r_len) &&
- (0 == strncmp(username->ptr, f_user, u_len)) &&
- (0 == strncmp(realm->ptr, f_realm, r_len))) {
- /* found */
-
- buffer_copy_string_len(password, f_pwd, pwd_len);
-
- ret = 0;
- break;
- }
-
- /* EOL */
- if (!e) break;
-
- f_line = e + 1;
- }
-
- stream_close(&f);
- } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
- p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
- stream f;
- char * f_line;
- buffer *auth_fn;
-
- auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
-
- if (buffer_is_empty(auth_fn)) return -1;
-
- if (0 != stream_open(&f, auth_fn)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening plain-userfile", auth_fn, "failed:", strerror(errno));
-
- return -1;
- }
-
- f_line = f.start;
-
- while (f_line - f.start != f.size) {
- char *f_user, *f_pwd, *e;
- size_t u_len, pwd_len;
-
- f_user = f_line;
-
- /*
- * htpasswd format
- *
- * user:crypted passwd
- */
-
- if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "parsed error in", auth_fn,
- "expected 'username:hashed password'");
-
- stream_close(&f);
-
- return -1;
- }
-
- /* get pointers to the fields */
- u_len = f_pwd - f_user;
- f_pwd++;
-
- if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
- pwd_len = e - f_pwd;
- } else {
- pwd_len = f.size - (f_pwd - f.start);
- }
-
- if (username->used - 1 == u_len &&
- (0 == strncmp(username->ptr, f_user, u_len))) {
- /* found */
-
- buffer_copy_string_len(password, f_pwd, pwd_len);
-
- ret = 0;
- break;
- }
-
- /* EOL */
- if (!e) break;
-
- f_line = e + 1;
- }
-
- stream_close(&f);
- } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
- ret = 0;
- } else {
- return -1;
- }
-
- return ret;
-}
-
-static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const char *url, const char *username, const char *group, const char *host) {
- const char *r = NULL, *rules = NULL;
- size_t i;
- int username_len;
- data_string *require;
- array *req;
-
- UNUSED(group);
- UNUSED(host);
-
- /* check what has to be match to fullfil the request */
- /* search auth-directives for path */
- for (i = 0; i < p->conf.auth_require->used; i++) {
- if (p->conf.auth_require->data[i]->key->used == 0) continue;
-
- if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
- break;
- }
- }
-
- if (i == p->conf.auth_require->used) {
- return -1;
- }
-
- req = ((data_array *)(p->conf.auth_require->data[i]))->value;
-
- require = (data_string *)array_get_element(req, CONST_STR_LEN("require"));
-
- /* if we get here, the user we got a authed user */
- if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
- return 0;
- }
-
- /* user=name1|group=name3|host=name4 */
-
- /* seperate the string by | */
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
-#endif
-
- username_len = username ? strlen(username) : 0;
-
- r = rules = require->value->ptr;
-
- while (1) {
- const char *eq;
- const char *k, *v, *e;
- int k_len, v_len, r_len;
-
- e = strchr(r, '|');
-
- if (e) {
- r_len = e - r;
- } else {
- r_len = strlen(rules) - (r - rules);
- }
-
- /* from r to r + r_len is a rule */
-
- if (0 == strncmp(r, "valid-user", r_len)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
- require->value);
- return -1;
- }
-
- /* search for = in the rules */
- if (NULL == (eq = strchr(r, '='))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing the 'require' section in 'auth.require' failed: a = is missing",
- require->value);
- return -1;
- }
-
- /* = out of range */
- if (eq > r + r_len) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing the 'require' section in 'auth.require' failed: = out of range",
- require->value);
-
- return -1;
- }
-
- /* the part before the = is user|group|host */
-
- k = r;
- k_len = eq - r;
- v = eq + 1;
- v_len = r_len - k_len - 1;
-
- if (k_len == 4) {
- if (0 == strncmp(k, "user", k_len)) {
- if (username &&
- username_len == v_len &&
- 0 == strncmp(username, v, v_len)) {
- return 0;
- }
- } else if (0 == strncmp(k, "host", k_len)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "host ... (not implemented)");
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
- return -1;
- }
- } else if (k_len == 5) {
- if (0 == strncmp(k, "group", k_len)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "group ... (not implemented)");
- } else {
- log_error_write(srv, __FILE__, __LINE__, "ss", "unknown key", k);
- return -1;
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
- return -1;
- }
-
- if (!e) break;
- r = e + 1;
- }
-
- log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
-
- return -1;
-}
-
-#define APR_MD5_DIGESTSIZE 16
-#define APR1_ID "$apr1$"
-
-/*
- * The following MD5 password encryption code was largely borrowed from
- * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
- * licenced as stated at the top of this file.
- */
-
-static void to64(char *s, unsigned long v, int n)
-{
- static 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;
- 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..'
- */
- MD5_Init(&ctx);
-
- /*
- * The password first, since that is what is most unknown
- */
- MD5_Update(&ctx, (const unsigned char*) pw, strlen(pw));
-
- /*
- * Then our magic string
- */
- MD5_Update(&ctx, (const unsigned char*) APR1_ID, strlen(APR1_ID));
-
- /*
- * Then the raw salt
- */
- MD5_Update(&ctx, (const unsigned char*) sp, sl);
-
- /*
- * Then just as many characters of the MD5(pw, salt, pw)
- */
- MD5_Init(&ctx1);
- MD5_Update(&ctx1, (const unsigned char*) pw, strlen(pw));
- MD5_Update(&ctx1, (const unsigned char*) sp, sl);
- MD5_Update(&ctx1, (const unsigned char*) pw, strlen(pw));
- MD5_Final(final, &ctx1);
- for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
- 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) {
- MD5_Update(&ctx, final, 1);
- }
- else {
- MD5_Update(&ctx, (const unsigned char*) 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, "$");
-
- 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++) {
- MD5_Init(&ctx1);
- if (i & 1) {
- MD5_Update(&ctx1, (const unsigned char*) pw, strlen(pw));
- }
- else {
- MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
- }
- if (i % 3) {
- MD5_Update(&ctx1, (const unsigned char*) sp, sl);
- }
-
- if (i % 7) {
- MD5_Update(&ctx1, (const unsigned char*) pw, strlen(pw));
- }
-
- if (i & 1) {
- MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
- }
- else {
- MD5_Update(&ctx1, (const unsigned char*) pw, strlen(pw));
- }
- MD5_Final(final,&ctx1);
- }
-
- p = passwd + strlen(passwd);
-
- l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
- l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
- l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
- l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
- l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
- l = final[11] ; to64(p, l, 2); p += 2;
- *p = '\0';
-
- /*
- * Don't leave anything around in vm they could use.
- */
- memset(final, 0, sizeof(final));
-
- /* FIXME
- */
-#define apr_cpystrn strncpy
- apr_cpystrn(result, passwd, nbytes - 1);
-}
-
-
-/**
- *
- *
- * @param password password-string from the auth-backend
- * @param pw password-string from the client
- */
-
-static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p, array *req, buffer *username, buffer *realm, buffer *password, const char *pw) {
- UNUSED(srv);
- UNUSED(req);
-
- if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
- /*
- * htdigest format
- *
- * user:realm:md5(user:realm:password)
- */
-
- MD5_CTX Md5Ctx;
- HASH HA1;
- char a1[256];
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
- MD5_Final(HA1, &Md5Ctx);
-
- CvtHex(HA1, a1);
-
- if (buffer_is_equal_string(password, a1, strlen(a1))) {
- return 0;
- }
- } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
- char sample[120];
- if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) {
- /*
- * The hash was created using $apr1$ custom algorithm.
- */
- apr_md5_encode(pw, password->ptr, sample, sizeof(sample));
- return (strcmp(sample, password->ptr) == 0) ? 0 : 1;
- } else {
-#ifdef HAVE_CRYPT
- char salt[32];
- char *crypted;
- size_t salt_len = 0;
- /*
- * htpasswd format
- *
- * user:crypted password
- */
-
- /*
- * Algorithm Salt
- * CRYPT_STD_DES 2-character (Default)
- * CRYPT_EXT_DES 9-character
- * CRYPT_MD5 12-character beginning with $1$
- * CRYPT_BLOWFISH 16-character beginning with $2$
- */
-
- if (password->used < 13 + 1) {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
- return -1;
- }
-
- if (password->used == 13 + 1) {
- /* a simple DES password is 2 + 11 characters */
- salt_len = 2;
- } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
- char *dollar = NULL;
-
- if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
- return -1;
- }
-
- salt_len = dollar - password->ptr;
- }
-
- if (salt_len > sizeof(salt) - 1) {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
- return -1;
- }
-
- strncpy(salt, password->ptr, salt_len);
-
- salt[salt_len] = '\0';
-
- crypted = crypt(pw, salt);
-
- if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
- return 0;
- } else {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
- }
-
-#endif
- }
- } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
- if (buffer_is_equal_string(password, pw, strlen(pw))) {
- return 0;
- }
- } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
-#ifdef USE_LDAP
- LDAP *ldap = NULL;
- LDAPMessage *lm = NULL, *first = NULL;
- struct berval credentials;
- char *dn = NULL;
- int ret = 0;
- char *attrs[] = { LDAP_NO_ATTRS, NULL };
- size_t i = 0;
-
- /* for now we stay synchronous */
-
- /*
- * 1. connect anonymously (done in plugin init)
- * 2. get DN for uid = username
- * 3. auth against ldap server
- * 4. (optional) check a field
- * 5. disconnect
- *
- */
-
- /* check username
- *
- * we have to protect us againt username which modifies out filter in
- * a unpleasant way
- */
-
- for (i = 0; i < username->used - 1; i++) {
- char c = username->ptr[i];
-
- if (!isalpha(c) &&
- !isdigit(c) &&
- (c != ' ') &&
- (c != '@') &&
- (c != '-') &&
- (c != '_') &&
- (c != '.') ) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbd",
- "ldap: invalid character (- _.@a-zA-Z0-9 allowed) in username:", username, i);
-
- return -1;
- }
- }
-
- if (p->conf.auth_ldap_allow_empty_pw != 1 && pw[0] == '\0')
- return -1;
-
- /* 2. */
-
- if (p->conf.ldap->ldap == NULL) {
- if(auth_ldap_init(srv, &p->conf) != HANDLER_GO_ON)
- return -1;
- }
-
- /* build filter */
- buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap->ldap_filter_pre);
- buffer_append_string_buffer(p->ldap_filter, username);
- buffer_append_string_buffer(p->ldap_filter, p->conf.ldap->ldap_filter_post);
-
- ret = ldap_search_ext_s(p->conf.ldap->ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, NULL, NULL, NULL, 0, &lm);
-
- if (ret == LDAP_SERVER_DOWN) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "ldap: server down, try to reconnect");
-
- auth_ldap_cleanup(p->conf.ldap);
-
- if(auth_ldap_init(srv, &p->conf) != HANDLER_GO_ON)
- return -1;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "ldap: successfully reconnected");
- }
-
- if (ret != LDAP_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "sssb",
- "ldap:", ldap_err2string(ret), ", filter:", p->ldap_filter);
-
- return -1;
- }
-
- if (ldap_count_entries(p->conf.ldap->ldap, lm) > 1) {
- log_error_write(srv, __FILE__, __LINE__, "ssb",
- "ldap:", "more than one record returned, you might have to refine the filter:", p->ldap_filter);
- }
-
- first = ldap_first_entry(p->conf.ldap->ldap, lm);
- if (first == NULL) {
- ldap_get_option(p->conf.ldap->ldap, LDAP_OPT_ERROR_NUMBER, &ret);
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_msgfree(lm);
-
- return -1;
- }
-
- dn = ldap_get_dn(p->conf.ldap->ldap, first);
- if (dn == NULL) {
- ldap_get_option(p->conf.ldap->ldap, LDAP_OPT_ERROR_NUMBER, &ret);
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_msgfree(lm);
-
- return -1;
- }
-
- ldap_msgfree(lm);
-
- /* 3. */
- ret = ldap_initialize(&ldap, p->conf.auth_ldap_url->ptr);
- if (ret) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_memfree(dn);
-
- return -1;
- }
-
- {
- const int ldap_version = LDAP_VERSION3;
- ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
- }
- if (ret != LDAP_OPT_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_memfree(ldap);
- ldap_memfree(dn);
-
- return -1;
- }
-
- if (p->conf.auth_ldap_starttls == 1) {
- ret = ldap_start_tls_s(ldap, NULL, NULL);
- if (ret != LDAP_OPT_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
-
- ldap_memfree(ldap);
- ldap_memfree(dn);
-
- return -1;
- }
- }
-
- /* Don't initialize it using " = {...}" since upstream doesn't
- * guarantee an order and the compiler only issues a warning when
- * passing an int as the pointer and vice-versa.
- * We have to cast away the const since berval is a general struct,
- * but ldap_sasl_bind_s doesn't write to the *pw location
- */
- credentials.bv_val = (char*)pw;
- credentials.bv_len = strlen(pw);
-
- /* TODO: add funtionality to specify LDAP_SASL_EXTERNAL (or GSS-SPNEGO, etc.) */
- ret = ldap_sasl_bind_s(ldap, dn, LDAP_SASL_SIMPLE, &credentials, NULL, NULL, NULL);
- if (ret != LDAP_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_memfree(ldap);
- ldap_memfree(dn);
-
- return -1;
- }
-
- /* 5. */
- ldap_unbind_ext_s(ldap, NULL, NULL);
- ldap_memfree(dn);
-
- /* everything worked, good, access granted */
-
- return 0;
-#endif
- }
- return -1;
-}
-
-int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
- buffer *username, *password;
- char *pw;
-
- data_string *realm;
-
- realm = (data_string *)array_get_element(req, CONST_STR_LEN("realm"));
-
- username = buffer_init();
-
- if (!base64_decode(username, realm_str)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "decodeing base64-string failed", username);
-
- buffer_free(username);
- return 0;
- }
-
- /* r2 == user:password */
- if (NULL == (pw = strchr(username->ptr, ':'))) {
- log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
-
- buffer_free(username);
- return 0;
- }
-
- *pw++ = '\0';
-
- username->used = pw - username->ptr;
-
- password = buffer_init();
-
- /* copy password to r1 */
- if (http_auth_get_password(srv, p, username, realm->value, password)) {
- buffer_free(username);
- buffer_free(password);
-
- log_error_write(srv, __FILE__, __LINE__, "ss", "get_password failed, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
- return 0;
- }
-
- /* password doesn't match */
- if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
- log_error_write(srv, __FILE__, __LINE__, "sbsBss", "password doesn't match for", con->uri.path, "username:", username, ", IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
- buffer_free(username);
- buffer_free(password);
-
- return 0;
- }
-
- /* value is our allow-rules */
- if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
- buffer_free(username);
- buffer_free(password);
-
- log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
-
- return 0;
- }
-
- /* remember the username */
- buffer_copy_string_buffer(p->auth_user, username);
-
- buffer_free(username);
- buffer_free(password);
-
- return 1;
-}
-
-typedef struct {
- const char *key;
- int key_len;
- char **ptr;
-} digest_kv;
-
-int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
- char a1[256];
- char a2[256];
-
- char *username;
- char *realm;
- char *nonce;
- char *uri;
- char *algorithm;
- char *qop;
- char *cnonce;
- char *nc;
- char *respons;
-
- char *e, *c;
- const char *m = NULL;
- int i;
- buffer *password, *b, *username_buf, *realm_buf;
-
- 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;
- dkv[9].ptr = NULL;
-
- UNUSED(req);
-
- for (i = 0; dkv[i].key; i++) {
- *(dkv[i].ptr) = NULL;
- }
-
-
- if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
- p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "digest: unsupported backend (only htdigest or plain)");
-
- return -1;
- }
-
- b = buffer_init_string(realm_str);
-
- /* parse credentials from client */
- for (c = b->ptr; *c; c++) {
- /* skip whitespaces */
- while (*c == ' ' || *c == '\t') c++;
- if (!*c) break;
-
- for (i = 0; dkv[i].key; i++) {
- if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
- if ((c[dkv[i].key_len] == '"') &&
- (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;
- }
- }
- }
- }
-
- if (p->conf.auth_debug > 1) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
- log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
- log_error_write(srv, __FILE__, __LINE__, "ss", "nonce", nonce);
- log_error_write(srv, __FILE__, __LINE__, "ss", "uri", uri);
- log_error_write(srv, __FILE__, __LINE__, "ss", "algorigthm", algorithm);
- log_error_write(srv, __FILE__, __LINE__, "ss", "qop", qop);
- log_error_write(srv, __FILE__, __LINE__, "ss", "cnonce", cnonce);
- log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
- log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
- }
-
- /* check if everything is transmitted */
- if (!username ||
- !realm ||
- !nonce ||
- !uri ||
- (qop && (!nc || !cnonce)) ||
- !respons ) {
- /* missing field */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "digest: missing field");
-
- buffer_free(b);
- return -1;
- }
-
- /**
- * protect the md5-sess against missing cnonce and nonce
- */
- if (algorithm &&
- 0 == strcasecmp(algorithm, "md5-sess") &&
- (!nonce || !cnonce)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "digest: (md5-sess: missing field");
-
- buffer_free(b);
- return -1;
- }
-
- m = get_http_method_name(con->request.http_method);
-
- /* password-string == HA1 */
- password = buffer_init();
- username_buf = buffer_init_string(username);
- realm_buf = buffer_init_string(realm);
- if (http_auth_get_password(srv, p, username_buf, realm_buf, password)) {
- buffer_free(password);
- buffer_free(b);
- buffer_free(username_buf);
- buffer_free(realm_buf);
- return 0;
- }
-
- buffer_free(username_buf);
- buffer_free(realm_buf);
-
- if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
- /* generate password from plain-text */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1);
- MD5_Final(HA1, &Md5Ctx);
- } else if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
- /* HA1 */
- /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
- for (i = 0; i < HASHLEN; i++) {
- HA1[i] = hex2int(password->ptr[i*2]) << 4;
- HA1[i] |= hex2int(password->ptr[i*2+1]);
- }
- } else {
- /* we already check that above */
- SEGFAULT("p->conf.auth_backend is %d", p->conf.auth_backend);
- }
-
- buffer_free(password);
-
- if (algorithm &&
- strcasecmp(algorithm, "md5-sess") == 0) {
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)HA1, 16);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
- MD5_Final(HA1, &Md5Ctx);
- }
-
- CvtHex(HA1, a1);
-
- /* calculate H(A2) */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
- if (qop && strcasecmp(qop, "auth-int") == 0) {
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN);
- }
- MD5_Final(HA2, &Md5Ctx);
- CvtHex(HA2, HA2Hex);
-
- /* calculate response */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- if (qop && *qop) {
- MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- };
- MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
- MD5_Final(RespHash, &Md5Ctx);
- CvtHex(RespHash, a2);
-
- if (0 != strcmp(a2, respons)) {
- /* digest not ok */
-
- if (p->conf.auth_debug) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "digest: digest mismatch", a2, respons);
- }
-
- log_error_write(srv, __FILE__, __LINE__, "ssss",
- "digest: auth failed for ", username, ": wrong password, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
- buffer_free(b);
- return 0;
- }
-
- /* value is our allow-rules */
- if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
- buffer_free(b);
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "digest: rules did match");
-
- return 0;
- }
-
- /* remember the username */
- buffer_copy_string(p->auth_user, username);
-
- buffer_free(b);
-
- if (p->conf.auth_debug) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "digest: auth ok");
- }
- return 1;
-}
-
-
-int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer *fn, char out[33]) {
- HASH h;
- MD5_CTX Md5Ctx;
- char hh[32];
-
- UNUSED(p);
-
- /* generate shared-secret */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
-
- /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
- LI_ltostr(hh, srv->cur_ts);
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
- MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
- LI_ltostr(hh, rand());
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
-
- MD5_Final(h, &Md5Ctx);
-
- CvtHex(h, out);
-
- return 0;
-}
diff --git a/src/http_auth.h b/src/http_auth.h
deleted file mode 100644
index 84674fdb..00000000
--- a/src/http_auth.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef _HTTP_AUTH_H_
-#define _HTTP_AUTH_H_
-
-#include "server.h"
-#include "plugin.h"
-
-#if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
-# define USE_LDAP
-# include <ldap.h>
-#endif
-
-typedef enum {
- AUTH_BACKEND_UNSET,
- AUTH_BACKEND_PLAIN,
- AUTH_BACKEND_LDAP,
- AUTH_BACKEND_HTPASSWD,
- AUTH_BACKEND_HTDIGEST
-} auth_backend_t;
-
-#ifdef USE_LDAP
-typedef struct {
- LDAP *ldap;
-
- buffer *ldap_filter_pre;
- buffer *ldap_filter_post;
-} ldap_plugin_config;
-#endif
-
-typedef struct {
- /* auth */
- array *auth_require;
-
- buffer *auth_plain_groupfile;
- buffer *auth_plain_userfile;
-
- buffer *auth_htdigest_userfile;
- buffer *auth_htpasswd_userfile;
-
- buffer *auth_backend_conf;
-
- buffer *auth_ldap_url;
- buffer *auth_ldap_basedn;
- buffer *auth_ldap_binddn;
- buffer *auth_ldap_bindpw;
- buffer *auth_ldap_filter;
- buffer *auth_ldap_cafile;
- buffer *auth_ldap_cert;
- buffer *auth_ldap_key;
- unsigned short auth_ldap_starttls;
- unsigned short auth_ldap_allow_empty_pw;
-
- unsigned short auth_debug;
-
- /* generated */
- auth_backend_t auth_backend;
-
-#ifdef USE_LDAP
- ldap_plugin_config *ldap;
-#endif
-} mod_auth_plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
- buffer *tmp_buf;
-
- buffer *auth_user;
-
-#ifdef USE_LDAP
- buffer *ldap_filter;
-#endif
-
- mod_auth_plugin_config **config_storage;
-
- mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
-} mod_auth_plugin_data;
-
-int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str);
-int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str);
-int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer *fn, char hh[33]);
-
-#endif
diff --git a/src/http_auth_digest.c b/src/http_auth_digest.c
deleted file mode 100644
index 27b933ae..00000000
--- a/src/http_auth_digest.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <string.h>
-#include "http_auth_digest.h"
-
-#include "buffer.h"
-
-#ifndef USE_OPENSSL
-# include "md5.h"
-
-typedef li_MD5_CTX MD5_CTX;
-#define MD5_Init li_MD5_Init
-#define MD5_Update li_MD5_Update
-#define MD5_Final li_MD5_Final
-
-#endif
-
-void CvtHex(IN HASH Bin, OUT HASHHEX Hex) {
- unsigned short i;
-
- for (i = 0; i < HASHLEN; i++) {
- Hex[i*2] = int2hex((Bin[i] >> 4) & 0xf);
- Hex[i*2+1] = int2hex(Bin[i] & 0xf);
- }
- Hex[HASHHEXLEN] = '\0';
-}
-
diff --git a/src/http_auth_digest.h b/src/http_auth_digest.h
deleted file mode 100644
index 25d95ee4..00000000
--- a/src/http_auth_digest.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _DIGCALC_H_
-#define _DIGCALC_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define HASHLEN 16
-typedef unsigned char HASH[HASHLEN];
-#define HASHHEXLEN 32
-typedef char HASHHEX[HASHHEXLEN+1];
-#ifdef USE_OPENSSL
-#define IN const
-#else
-#define IN
-#endif
-#define OUT
-
-void CvtHex(
- IN HASH Bin,
- OUT HASHHEX Hex
- );
-
-#endif
diff --git a/src/http_parser.h b/src/http_parser.h
deleted file mode 100644
index ba86f16a..00000000
--- a/src/http_parser.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _HTTP_PARSER_H_
-#define _HTTP_PARSER_H_
-
-typedef enum {
- PARSE_UNSET,
- PARSE_SUCCESS,
- PARSE_ERROR,
- PARSE_NEED_MORE
-} parse_status_t;
-
-#endif
diff --git a/src/http_req.c b/src/http_req.c
deleted file mode 100644
index 004ca303..00000000
--- a/src/http_req.c
+++ /dev/null
@@ -1,323 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "log.h"
-#include "http_req.h"
-#include "http_req_parser.h"
-
-typedef struct {
- chunkqueue *cq;
-
- chunk *c; /* current chunk in the chunkqueue */
- size_t offset; /* current offset in current chunk */
-
- chunk *lookup_c;
- size_t lookup_offset;
-
- int last_token_id;
-
- int is_key;
- int is_statusline;
-} http_req_tokenizer_t;
-
-http_req *http_request_init(void) {
- http_req *req = calloc(1, sizeof(*req));
-
- req->uri_raw = buffer_init();
- req->headers = array_init();
-
- return req;
-}
-
-void http_request_reset(http_req *req) {
- if (!req) return;
-
- buffer_reset(req->uri_raw);
- array_reset(req->headers);
-
-}
-
-void http_request_free(http_req *req) {
- if (!req) return;
-
- buffer_free(req->uri_raw);
- array_free(req->headers);
-
- free(req);
-}
-
-static int http_req_get_next_char(http_req_tokenizer_t *t, unsigned char *c) {
- if (t->c->mem->used == 0) {
- TRACE("chunk-len: %zd", t->c->mem->used);
- }
-
- if (t->offset == t->c->mem->used - 1) {
- /* end of chunk, open next chunk */
-
- if (!t->c->next) return -1;
-
- t->c = t->c->next;
- /* skip empty chunks */
- while (t->c && t->c->mem->used == 0) t->c = t->c->next;
- if (!t->c) return -1;
-
- t->offset = 0;
- }
-
- *c = t->c->mem->ptr[t->offset++];
-
- t->lookup_offset = t->offset;
- t->lookup_c = t->c;
-
-#if 0
- fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
-#endif
-
- return 0;
-}
-
-static int http_req_lookup_next_char(http_req_tokenizer_t *t, unsigned char *c) {
- if (t->lookup_c->mem->used == 0) {
- TRACE("chunk-len: %zd", t->lookup_c->mem->used);
- }
- if (t->lookup_offset == t->lookup_c->mem->used - 1) {
- /* end of chunk, open next chunk */
-
- if (!t->lookup_c->next) return -1;
-
- t->lookup_c = t->lookup_c->next;
-
- /* skip empty chunks */
- while (t->lookup_c && t->lookup_c->mem->used == 0) t->lookup_c = t->lookup_c->next;
- if (!t->lookup_c) return -1;
-
- t->lookup_offset = 0;
- }
-
- *c = t->lookup_c->mem->ptr[t->lookup_offset++];
-#if 0
- fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
-#endif
-
- return 0;
-}
-
-typedef enum {
- PARSER_UNSET,
- PARSER_OK,
- PARSER_ERROR,
- PARSER_EOF
-} http_req_parser_t;
-
-static http_req_parser_t http_req_tokenizer(
- http_req_tokenizer_t *t,
- int *token_id,
- buffer *token
-) {
- unsigned char c;
- int tid = 0;
-
- /* push the token to the parser */
-
- while (tid == 0 && 0 == http_req_get_next_char(t, &c)) {
- switch (c) {
- case ':':
- tid = TK_COLON;
-
- t->is_key = 0;
-
- break;
- case ' ':
- case '\t':
- if (t->last_token_id == TK_CRLF) {
- /* WS as the start of a line */
-
- tid = TK_TAB;
- t->is_key = 0;
- }
- /* ignore the rest of the WS-chars */
- break;
- case '\r':
- if (0 != http_req_lookup_next_char(t, &c)) return PARSER_EOF;
-
- if (c == '\n') {
- tid = TK_CRLF;
-
- t->c = t->lookup_c;
- t->offset = t->lookup_offset;
-
- t->is_statusline = 0;
- t->is_key = 1;
- } else {
- ERROR("CR with out LF at pos: %zu", t->offset);
- return PARSER_ERROR;
- }
- break;
- case '\n':
- tid = TK_CRLF;
-
- t->is_statusline = 0;
- t->is_key = 1;
-
- break;
- default:
- while (c >= 32 && c != 127 && c != 255) {
- if (t->is_statusline) {
- if (c == 32) break; /* the space is a splitter in the statusline */
- } else {
- if (t->is_key) {
- if (c == ':') break; /* the : is the splitter between key and value */
- if (c == ' ') break; /* no spaces in keys */
- }
- }
- if (0 != http_req_lookup_next_char(t, &c)) return PARSER_EOF;
- }
-
- if (t->c == t->lookup_c &&
- t->offset == t->lookup_offset + 1) {
-
- ERROR("invalid char (%d) at pos: %zu", c, t->offset);
- return PARSER_ERROR;
- }
-
- tid = TK_STRING;
-
- /* the lookup points to the first invalid char */
- t->lookup_offset--;
-
- /* no overlapping string */
- if (t->c == t->lookup_c) {
- buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
- } else {
- /* first chunk */
- buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
-
- /* chunks in the middle */
- for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
- buffer_append_string_buffer(token, t->c->mem);
- t->offset = t->c->mem->used - 1;
- }
-
- /* last chunk */
- buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
- }
-
- t->offset = t->lookup_offset;
-
- break;
- }
- }
-
- if (tid) {
- *token_id = tid;
-
- return PARSER_OK;
- }
-
- return PARSER_EOF;
-}
-
-parse_status_t http_request_parse_cq(chunkqueue *cq, http_req *req) {
- http_req_tokenizer_t t;
- void *pParser = NULL;
- int token_id = 0;
- buffer *token = NULL;
- http_req_ctx_t context;
- parse_status_t ret = PARSE_UNSET;
- http_req_parser_t parser_ret;
-
- t.cq = cq;
- t.c = cq->first;
- t.offset = t.c->offset;
- t.is_key = 0;
- t.is_statusline = 1;
- t.last_token_id = 0;
-
- context.ok = 1;
- context.errmsg = buffer_init();
- context.req = req;
- context.unused_buffers = buffer_pool_init();
-
- pParser = http_req_parserAlloc( malloc );
- token = buffer_init();
-
- array_reset(req->headers);
-
- while((PARSER_OK == (parser_ret = http_req_tokenizer(&t, &token_id, token))) && context.ok) {
- http_req_parser(pParser, token_id, token, &context);
-
- token = buffer_pool_get(context.unused_buffers);
-
- /* CRLF CRLF ... the header end sequence */
- if (t.last_token_id == TK_CRLF &&
- token_id == TK_CRLF) break;
-
- t.last_token_id = token_id;
- }
-
- // Tokenizer failed
- if (parser_ret == PARSER_ERROR) {
- ret = PARSE_ERROR;
- }
-
- /* oops, the parser failed */
- if (context.ok == 0) {
- ret = PARSE_ERROR;
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- } else {
- chunk *c;
- buffer *hdr = buffer_init();
-
- for (c = cq->first; c; c = c->next) {
- if (c == cq->first) {
- buffer_append_string_len(hdr, c->mem->ptr + c->offset, c->mem->used - 1 - c->offset);
- } else {
- buffer_append_string_buffer(hdr, c->mem);
- }
- }
-
- TRACE("parsing failed at token (%s [%d]), header: %s", SAFE_BUF_STR(token), token_id, SAFE_BUF_STR(hdr));
-
- buffer_free(hdr);
- }
- }
-
- http_req_parser(pParser, 0, token, &context);
- http_req_parserFree(pParser, free);
-
- if (context.ok == 0) {
- /* we are missing the some tokens */
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- }
-
- if (ret == PARSE_UNSET) {
- ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
- }
- } else if (parser_ret == PARSER_EOF) { // didn't see CRLF CRLF, no other error till now
- ret = PARSE_NEED_MORE;
- } else {
- chunk *c;
-
- for (c = cq->first; c != t.c; c = c->next) {
- c->offset = c->mem->used - 1;
- }
-
- c->offset = t.offset;
-
- ret = PARSE_SUCCESS;
- }
-
- buffer_pool_append(context.unused_buffers, token);
- buffer_pool_free(context.unused_buffers);
- buffer_free(context.errmsg);
-
- return ret;
-}
-
-
diff --git a/src/http_req.h b/src/http_req.h
deleted file mode 100644
index 54b4a087..00000000
--- a/src/http_req.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _HTTP_REQ_H_
-#define _HTTP_REQ_H_
-
-#include <stdio.h>
-
-#include "array.h"
-#include "chunk.h"
-#include "http_parser.h"
-
-typedef struct {
- int protocol; /* http/1.0, http/1.1 */
- int method; /* e.g. GET */
- buffer *uri_raw; /* e.g. /foobar/ */
- array *headers;
-} http_req;
-
-typedef struct {
- int ok;
- buffer *errmsg;
-
- http_req *req;
- buffer_pool *unused_buffers;
-} http_req_ctx_t;
-
-LI_API http_req * http_request_init(void);
-LI_API void http_request_free(http_req *req);
-LI_API void http_request_reset(http_req *req);
-
-LI_API parse_status_t http_request_parse_cq(chunkqueue *cq, http_req *http_request);
-
-/* declare prototypes for the parser */
-void *http_req_parserAlloc(void *(*mallocProc)(size_t));
-void http_req_parserFree(void *p, void (*freeProc)(void*));
-void http_req_parserTrace(FILE *TraceFILE, char *zTracePrompt);
-void http_req_parser(void *, int, buffer *, http_req_ctx_t *);
-
-#endif
diff --git a/src/http_req_parser.y b/src/http_req_parser.y
deleted file mode 100644
index 54c2673a..00000000
--- a/src/http_req_parser.y
+++ /dev/null
@@ -1,160 +0,0 @@
-%token_prefix TK_
-%token_type {buffer *}
-%extra_argument {http_req_ctx_t *ctx}
-%name http_req_parser
-
-%include {
-#include <assert.h>
-#include <string.h>
-#include "http_req.h"
-#include "keyvalue.h"
-#include "array.h"
-#include "log.h"
-}
-
-%parse_failure {
- ctx->ok = 0;
-}
-
-%type protocol { http_version_t }
-%type method { http_method_t }
-%type request_hdr { http_req * }
-%type headers { array * }
-%type header { data_string * }
-%type multiline { buffer * }
-%token_destructor { buffer_free($$); }
-
-/**
-* GET ... HTTP/1.0
-* Host: ...
-*/
-request_hdr ::= method(B) STRING(C) protocol(D) CRLF headers CRLF . {
- http_req *req = ctx->req;
-
- req->method = B;
- req->protocol = D;
- buffer_copy_string_buffer(req->uri_raw, C);
- buffer_pool_append(ctx->unused_buffers, C);
-}
-
-/**
-* \r\n
-* GET ... HTTP/1.0\r\n
-* Host: ...\r\n
-* \r\n
-*/
-request_hdr ::= CRLF method(B) STRING(C) protocol(D) CRLF headers CRLF . {
- http_req *req = ctx->req;
-
- req->method = B;
- req->protocol = D;
- buffer_copy_string_buffer(req->uri_raw, C);
- buffer_pool_append(ctx->unused_buffers, C);
-}
-
-
-/**
-* GET ... HTTP/1.0\r\n
-* \r\n
-*
-*/
-request_hdr ::= method(B) STRING(C) protocol(D) CRLF CRLF . {
- http_req *req = ctx->req;
-
- req->method = B;
- req->protocol = D;
- buffer_copy_string_buffer(req->uri_raw, C);
- buffer_pool_append(ctx->unused_buffers, C);
-}
-
-/**
-* \r\n
-* GET ... HTTP/1.0\r\n
-* \r\n
-*
-*/
-request_hdr ::= CRLF method(B) STRING(C) protocol(D) CRLF CRLF . {
- http_req *req = ctx->req;
-
- req->method = B;
- req->protocol = D;
- buffer_copy_string_buffer(req->uri_raw, C);
- buffer_pool_append(ctx->unused_buffers, C);
-}
-
-
-method(A) ::= STRING(B) . {
- A = get_http_method_key(BUF_STR(B));
-
- buffer_pool_append(ctx->unused_buffers, B);
-}
-
-protocol(A) ::= STRING(B). {
- /* the protocol might be HTTP/1.0 or HTTP/1.1
- * the version string is allowed to have leading zeros
- */
- A = HTTP_VERSION_UNSET;
-
- if (0 == strncmp(BUF_STR(B), "HTTP/", 5)) {
- char *err = NULL;
- /* is there a dot */
- char *major, *minor;
-
- major = BUF_STR(B) + 5;
- minor = strchr(major, '.');
- if (minor) {
- int hi, lo;
- hi = strtol(major, &err, 10);
- minor++;
- if (*err == '.' && *minor != '\0') {
- lo = strtol(minor, &err, 10);
- if (*err == '\0') {
- if (hi == 1 && lo == 1) {
- A = HTTP_VERSION_1_1;
- } else if (hi == 1 && lo == 0) {
- A = HTTP_VERSION_1_0;
- }
- }
- }
- }
- }
-
- buffer_pool_append(ctx->unused_buffers, B);
-}
-
-headers ::= headers header.
-headers ::= header.
-
-header(HDR) ::= STRING(A) COLON multiline(B). {
- http_req *req = ctx->req;
-
- if (NULL == (HDR = (data_string *)array_get_unused_element(req->headers, TYPE_STRING))) {
- HDR = data_string_init();
- }
-
- buffer_copy_string_buffer(HDR->key, A);
- buffer_copy_string_buffer(HDR->value, B);
- buffer_pool_append(ctx->unused_buffers, A);
- buffer_pool_append(ctx->unused_buffers, B);
-
- array_insert_unique(req->headers, (data_unset *)HDR);
-}
-
-header ::= STRING COLON CRLF .
-
-multiline(A) ::= STRING(B) CRLF TAB multiline(C). {
- buffer_append_string_buffer(B, C);
- A = B;
-
- B = NULL;
- buffer_pool_append(ctx->unused_buffers, C);
-}
-
-/* the simple form */
-multiline(A) ::= STRING(B) CRLF. {
- A = B;
-
- B = NULL;
-}
-
-
diff --git a/src/http_req_range.c b/src/http_req_range.c
deleted file mode 100644
index 434959bb..00000000
--- a/src/http_req_range.c
+++ /dev/null
@@ -1,188 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "log.h"
-#include "http_req_range.h"
-#include "http_req_range_parser.h"
-
-typedef struct {
- buffer *hdr;
- size_t ndx;
-
- chunk *lookup_c;
- size_t lookup_offset;
-} http_req_range_tokenizer_t;
-
-http_req_range *http_request_range_init(void) {
- http_req_range *range = calloc(1, sizeof(*range));
-
- range->start = -1;
- range->end = -1;
-
- return range;
-}
-
-void http_request_range_reset(http_req_range *range) {
- if (!range) return;
-
- http_request_range_free(range->next);
-
- range->next = NULL;
-
- range->start = -1;
- range->end = -1;
-}
-
-void http_request_range_free(http_req_range *range) {
- if (!range) return;
-
- http_request_range_free(range->next);
-
- free(range);
-}
-
-static int http_req_range_tokenizer(
- http_req_range_tokenizer_t *t,
- int *token_id,
- buffer *token
-) {
- int tid = 0;
-
- /* push the token to the parser */
-
- while (tid == 0) {
- char c = t->hdr->ptr[t->ndx];
-
- switch (c) {
- case '-':
- tid = TK_MINUS;
- t->ndx++;
-
- break;
- case '=':
- tid = TK_EQUAL;
- t->ndx++;
-
- break;
- case ',':
- tid = TK_COMMA;
- t->ndx++;
-
- break;
-
- case ' ':
- case '\t':
- /* ignore WS */
- t->ndx++;
- break;
- case '\0':
- return 0;
- default:
- /* 'bytes' or a number */
- if (0 == strncmp(t->hdr->ptr + t->ndx, "bytes", 5)) {
- tid = TK_BYTES;
-
- t->ndx += 5;
- } else {
- size_t d;
- /* */
- for (d = t->ndx; d < t->hdr->used; d++) {
- char dc = t->hdr->ptr[d];
- if (dc < '0' || dc > '9') {
- break;
- }
- }
-
- if (d == t->ndx) {
- /* no digit found */
-
- TRACE("%s", "no digit found");
-
- return -1;
- }
-
- tid = TK_NUMBER;
-
- buffer_copy_string_len(token, t->hdr->ptr + t->ndx, d - t->ndx);
-
- t->ndx = d;
- }
-
- break;
- }
- }
-
- if (tid) {
- *token_id = tid;
-
- return 1;
- }
-
- return -1;
-}
-
-parse_status_t http_request_range_parse(buffer *hdr, http_req_range *ranges) {
- http_req_range_tokenizer_t t;
- void *pParser = NULL;
- int token_id = 0;
- buffer *token = NULL;
- http_req_range_ctx_t context;
- parse_status_t ret = PARSE_UNSET;
-
- t.hdr = hdr;
- t.ndx = 0;
-
- context.ok = 1;
- context.errmsg = buffer_init();
- context.ranges = ranges;
- context.unused_buffers = buffer_pool_init();
-
- pParser = http_req_range_parserAlloc( malloc );
- token = buffer_pool_get(context.unused_buffers);
-#if 0
- http_req_range_parserTrace(stderr, "range: ");
-#endif
-
- while((1 == http_req_range_tokenizer(&t, &token_id, token)) && context.ok) {
- http_req_range_parser(pParser, token_id, token, &context);
-
- token = buffer_pool_get(context.unused_buffers);
- }
-
- /* oops, the parser failed */
- if (context.ok == 0) {
- ret = PARSE_ERROR;
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- } else {
- TRACE("%s", "parsing failed ...");
- }
- }
-
- http_req_range_parser(pParser, 0, token, &context);
- http_req_range_parserFree(pParser, free);
-
- if (context.ok == 0) {
- /* we are missing the some tokens */
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- }
-
- if (ret == PARSE_UNSET) {
- ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
- }
- } else {
- ret = PARSE_SUCCESS;
- }
-
- buffer_pool_append(context.unused_buffers, token);
- buffer_pool_free(context.unused_buffers);
- buffer_free(context.errmsg);
-
- return ret;
-}
-
diff --git a/src/http_req_range.h b/src/http_req_range.h
deleted file mode 100644
index 32a862aa..00000000
--- a/src/http_req_range.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _HTTP_REQ_RANGE_H_
-#define _HTTP_REQ_RANGE_H_
-
-#include <stdio.h>
-
-#include "array.h"
-#include "chunk.h"
-#include "http_parser.h"
-
-typedef struct _http_req_range {
- off_t start;
- off_t end;
- struct _http_req_range *next;
-} http_req_range;
-
-typedef struct {
- int ok;
- buffer *errmsg;
-
- http_req_range *ranges;
-
- buffer_pool *unused_buffers;
-} http_req_range_ctx_t;
-
-LI_API http_req_range * http_request_range_init(void);
-LI_API void http_request_range_free(http_req_range *range);
-LI_API void http_request_range_reset(http_req_range *range);
-
-LI_API parse_status_t http_request_range_parse(buffer *range_hdr, http_req_range *ranges);
-
-/* declare prototypes for the parser */
-void *http_req_range_parserAlloc(void *(*mallocProc)(size_t));
-void http_req_range_parserFree(void *p, void (*freeProc)(void*));
-void http_req_range_parserTrace(FILE *TraceFILE, char *zTracePrompt);
-void http_req_range_parser(void *, int, buffer *, http_req_range_ctx_t *);
-
-#endif
diff --git a/src/http_req_range_parser.y b/src/http_req_range_parser.y
deleted file mode 100644
index 62241fb3..00000000
--- a/src/http_req_range_parser.y
+++ /dev/null
@@ -1,76 +0,0 @@
-%token_prefix TK_
-%token_type {buffer *}
-%extra_argument {http_req_range_ctx_t *ctx}
-%name http_req_range_parser
-
-%include {
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <sys/types.h>
-#include <string.h>
-#include "http_req_range.h"
-#include "log.h"
-#include "sys-strings.h"
-}
-
-%parse_failure {
- ctx->ok = 0;
-}
-
-%type num { off_t }
-%type range { http_req_range * }
-%type ranges { http_req_range * }
-%token_destructor { buffer_free($$); }
-
-
-range_hdr ::= BYTES EQUAL ranges(A) . {
- ctx->ranges->start = A->start;
- ctx->ranges->end = A->end;
- ctx->ranges->next = A->next;
-
- A->next = NULL;
- http_request_range_free(A);
-}
-
-ranges(A) ::= ranges(B) COMMA range(C) . {
- for (A = B; A->next; A = A->next);
-
- A->next = C;
-
- A = B;
-}
-ranges(A) ::= range(B) . {
- A = B;
-}
-range(A) ::= num(B) MINUS . {
- http_req_range *r = http_request_range_init();
-
- r->start = B;
- r->end = -1;
-
- A = r;
-}
-
-range(A) ::= num(B) MINUS num(C) . {
- http_req_range *r = http_request_range_init();
-
- r->start = B;
- r->end = C;
-
- A = r;
-}
-
-range(A) ::= MINUS num(B) . {
- http_req_range *r = http_request_range_init();
-
- r->start = -1;
- r->end = B;
-
- A = r;
-}
-
-num(A) ::= NUMBER(B) . {
- A = strtoull(BUF_STR(B), NULL, 10);
- buffer_pool_append(ctx->unused_buffers, B);
-}
diff --git a/src/http_req_range_test.c b/src/http_req_range_test.c
deleted file mode 100644
index 3532582c..00000000
--- a/src/http_req_range_test.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-#include <stdint.h>
-
-#include <tap.h>
-
-#include "http_req_range.h"
-#include "log.h"
-
-int main(void) {
- http_req_range *r, *ranges = http_request_range_init();
- buffer *b = buffer_init();
-
- log_init();
- plan_tests(7);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=0-0"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "0-0");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
- http_request_range_reset(ranges);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=1-2,3-4"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "1-2,3-4");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
- http_request_range_reset(ranges);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=-0"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "-0");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
- http_request_range_reset(ranges);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=0-"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "0-");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
- http_request_range_reset(ranges);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=0-0,0-"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "0-0,0-");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
- http_request_range_reset(ranges);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=0-0,-0"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "0-0,-0");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
- http_request_range_reset(ranges);
-
- buffer_copy_string_len(b, CONST_STR_LEN("bytes=1-2,3-4,5-"));
- ok(PARSE_SUCCESS == http_request_range_parse(b, ranges), "1-2,3-4,5-");
- for (r = ranges; r; r = r->next) {
- diag(".. %jd - %jd", (intmax_t) r->start, (intmax_t) r->end);
- }
-
- http_request_range_free(ranges);
-
- buffer_free(b);
- log_free();
-
- return exit_status();
-}
diff --git a/src/http_req_test.c b/src/http_req_test.c
deleted file mode 100644
index d53c0b85..00000000
--- a/src/http_req_test.c
+++ /dev/null
@@ -1,141 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#include <tap.h>
-
-#include "http_req.h"
-#include "log.h"
-
-const char* chunkqueue_to_buffer(chunkqueue *cq, buffer *b) {
- chunk *c;
-
- buffer_reset(b);
-
- for (c = cq->first; c; c = c->next) {
- buffer_append_string(b, c->mem->ptr + c->offset);
- }
-
- return b->ptr;
-}
-
-int main(void) {
- http_req *req = http_request_init();
- chunkqueue *cq = chunkqueue_init();
- buffer *b, *content = buffer_init();
- const char *body;
-
- log_init();
- plan_tests(8);
-
- /* basic request header + CRLF */
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "GET / HTTP/1.0\r\n"
- "Location: foobar\r\n"
- "Content-Lenght: 24\r\n"
- "\r\nABC"
- );
-
- ok(PARSE_SUCCESS == http_request_parse_cq(cq, req), "basic GET header");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- http_request_free(req);
-
- /* line-wrapping */
-
- chunkqueue_reset(cq);
- req = http_request_init();
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string(b,
- "GET /server-status HTTP/1.0\r\n"
- "User-Agent: Wget/1.9.1\r\n"
- "Authorization: Digest username=\"jan\", realm=\"jan\", nonce=\"9a5428ccc05b086a08d918e73b01fc6f\",\r\n"
- " uri=\"/server-status\", response=\"ea5f7d9a30b8b762f9610ccb87dea74f\"\r\n"
- "\r\n"
- );
-
- ok(PARSE_SUCCESS == http_request_parse_cq(cq, req), "POST request with line-wrapping");
-
- chunkqueue_remove_finished_chunks(cq);
-
- http_request_free(req);
-
- /* no request line */
-
- chunkqueue_reset(cq);
- req = http_request_init();
-
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "Location: foobar\r\n"
- "Content-Lenght: 24\r\n"
- "\r\nABC"
- );
-
- ok(PARSE_ERROR == http_request_parse_cq(cq, req), "missing request-line");
-
- http_request_free(req);
-
- /* LF as line-ending */
-
- chunkqueue_reset(cq);
- req = http_request_init();
-
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "GET / HTTP/1.0\n"
- "\nABC"
- );
- ok(PARSE_SUCCESS == http_request_parse_cq(cq, req), "no request key-value pairs");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- /* LF as line-ending */
-
- chunkqueue_reset(cq);
- req = http_request_init();
-
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "GE");
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string_len(b, CONST_STR_LEN("T "));
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string_len(b, CONST_STR_LEN("/foo"));
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string_len(b, CONST_STR_LEN("bar HTTP/1.0\r"));
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string(b, "\n"
- "Locati");
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string(b, "on: foobar\r\n"
- "Content-Lenght: 24\r\n"
- "\r\nABC"
- );
- ok(PARSE_SUCCESS == http_request_parse_cq(cq, req), "POST request with line-wrapping");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- http_request_free(req);
- chunkqueue_free(cq);
- buffer_free(content);
- log_free();
-
- return exit_status();
-}
diff --git a/src/http_resp.c b/src/http_resp.c
deleted file mode 100644
index 23b2e58c..00000000
--- a/src/http_resp.c
+++ /dev/null
@@ -1,303 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "log.h"
-#include "http_resp.h"
-#include "http_resp_parser.h"
-
-typedef struct {
- chunkqueue *cq;
-
- chunk *c; /* current chunk in the chunkqueue */
- size_t offset; /* current offset in current chunk */
-
- chunk *lookup_c;
- size_t lookup_offset;
-
- int is_key;
- int is_statusline;
-} http_resp_tokenizer_t;
-
-http_resp *http_response_init(void) {
- http_resp *resp = calloc(1, sizeof(*resp));
-
- resp->reason = buffer_init();
- resp->headers = array_init();
- resp->status = -1;
-
- return resp;
-}
-
-void http_response_reset(http_resp *resp) {
- if (!resp) return;
-
- buffer_reset(resp->reason);
- array_reset(resp->headers);
- resp->status = -1;
-
-}
-
-void http_response_free(http_resp *resp) {
- if (!resp) return;
-
- buffer_free(resp->reason);
- array_free(resp->headers);
-
- free(resp);
-}
-
-static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
- if (t->offset == t->c->mem->used - 1) {
- /* end of chunk, open next chunk */
-
- if (!t->c->next) return -1;
-
- t->c = t->c->next;
- t->offset = 0;
- }
-
- *c = t->c->mem->ptr[t->offset++];
-
- t->lookup_offset = t->offset;
- t->lookup_c = t->c;
-
-#if 0
- fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
-#endif
-
- return 0;
-}
-
-static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
- if (t->lookup_offset == t->lookup_c->mem->used - 1) {
- /* end of chunk, open next chunk */
-
- if (!t->lookup_c->next) return -1;
-
- t->lookup_c = t->lookup_c->next;
- t->lookup_offset = 0;
- }
-
- *c = t->lookup_c->mem->ptr[t->lookup_offset++];
-#if 0
- fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
-#endif
-
- return 0;
-}
-
-typedef enum {
- PARSER_UNSET,
- PARSER_OK,
- PARSER_ERROR,
- PARSER_EOF
-} http_resp_parser_t;
-
-static http_resp_parser_t http_resp_tokenizer(
- http_resp_tokenizer_t *t,
- int *token_id,
- buffer *token
-) {
- unsigned char c;
- int tid = 0;
-
- /* push the token to the parser */
-
- while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
- switch (c) {
- case ':':
- tid = TK_COLON;
-
- t->is_key = 0;
-
- break;
- case ' ':
- case '\t':
- /* ignore WS */
-
- break;
- case '\r':
- if (0 != http_resp_lookup_next_char(t, &c)) return -1;
-
- if (c == '\n') {
- tid = TK_CRLF;
-
- t->c = t->lookup_c;
- t->offset = t->lookup_offset;
-
- t->is_statusline = 0;
- t->is_key = 1;
- } else {
- ERROR("CR with out LF at pos: %zu", t->offset);
- return PARSER_ERROR;
- }
- break;
- case '\n':
- tid = TK_CRLF;
-
- t->is_statusline = 0;
- t->is_key = 1;
-
- break;
- default:
- while (c >= 32 && c != 127 && c != 255) {
- if (t->is_statusline) {
- if (t->is_key && c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
- if (c == 32) { t->is_key = 0; break; } /* the space is a splitter in the statusline */
- } else {
- if (t->is_key) {
- if (c == ':') break; /* the : is the splitter between key and value */
- }
- }
- if (0 != http_resp_lookup_next_char(t, &c)) return PARSER_EOF;
- }
-
- if (t->c == t->lookup_c &&
- t->offset == t->lookup_offset + 1) {
-
- ERROR("invalid char (%d) at pos: %zu", c, t->offset);
- return PARSER_ERROR;
- }
-
- tid = TK_STRING;
-
- /* the lookup points to the first invalid char */
- t->lookup_offset--;
-
- /* no overlapping string */
- if (t->c == t->lookup_c) {
- buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
- } else {
- /* first chunk */
- buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
-
- /* chunks in the middle */
- for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
- buffer_append_string_buffer(token, t->c->mem);
- t->offset = t->c->mem->used - 1;
- }
-
- /* last chunk */
- buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
- }
-
- t->offset = t->lookup_offset;
-
- break;
- }
- }
-
- if (tid) {
- *token_id = tid;
-
- return PARSER_OK;
- }
-
- return PARSER_EOF;
-}
-
-parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
- http_resp_tokenizer_t t;
- void *pParser = NULL;
- int token_id = 0;
- buffer *token = NULL;
- http_resp_ctx_t context;
- parse_status_t ret = PARSE_UNSET;
- http_resp_parser_t parser_ret;
- int last_token_id = 0;
-
- if(!cq->first) return PARSE_NEED_MORE;
- t.cq = cq;
- t.c = cq->first;
- t.offset = t.c->offset;
- t.is_key = 1;
- t.is_statusline = 1;
-
- context.ok = 1;
- context.errmsg = buffer_init();
- context.resp = resp;
- context.unused_buffers = buffer_pool_init();
-
- array_reset(resp->headers);
- resp->status = 0;
-
- pParser = http_resp_parserAlloc( malloc );
- token = buffer_pool_get(context.unused_buffers);
-#if 0
- http_resp_parserTrace(stderr, "http-response: ");
-#endif
-
- while((PARSER_OK == (parser_ret = http_resp_tokenizer(&t, &token_id, token))) && context.ok) {
- http_resp_parser(pParser, token_id, token, &context);
-
- token = buffer_pool_get(context.unused_buffers);
-
- /* CRLF CRLF ... the header end sequence */
- if (last_token_id == TK_CRLF &&
- token_id == TK_CRLF) break;
-
- last_token_id = token_id;
- }
-
- // Tokenizer failed
- if (parser_ret == PARSER_ERROR) {
- ret = PARSE_ERROR;
- }
-
- /* oops, the parser failed */
- if (context.ok == 0) {
- ret = PARSE_ERROR;
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- } else {
- TRACE("%s", "parsing failed ...");
- }
- }
-
- http_resp_parser(pParser, 0, token, &context);
- http_resp_parserFree(pParser, free);
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- }
- if (context.ok == 0) {
- /* we are missing the some tokens */
-
- if (!buffer_is_empty(context.errmsg)) {
- TRACE("parsing failed: %s", SAFE_BUF_STR(context.errmsg));
- }
-
- if (ret == PARSE_UNSET) {
- ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
- }
- } else if (parser_ret == PARSER_EOF) { // didn't see CRLF CRLF, no other error till now
- ret = PARSE_NEED_MORE;
- } else {
- chunk *c;
-
- for (c = cq->first; c != t.c; c = c->next) {
- c->offset = c->mem->used - 1;
- cq->bytes_out += c->mem->used - 1;
- }
-
- c->offset = t.offset;
- cq->bytes_out += t.offset;
-
- ret = PARSE_SUCCESS;
- }
-
- buffer_pool_append(context.unused_buffers, token);
- buffer_pool_free(context.unused_buffers);
- buffer_free(context.errmsg);
-
- if (resp->status && (resp->status < 100 || resp->status > 999)) {
- ERROR("invalid status code %i", resp->status);
- return PARSE_ERROR;
- }
-
- return ret;
-}
-
diff --git a/src/http_resp.h b/src/http_resp.h
deleted file mode 100644
index ccc67f94..00000000
--- a/src/http_resp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _HTTP_RESP_H_
-#define _HTTP_RESP_H_
-
-#include <stdio.h>
-
-#include "buffer.h"
-#include "array.h"
-#include "array-static.h"
-#include "chunk.h"
-#include "http_parser.h"
-
-typedef struct {
- int protocol; /* http/1.0, http/1.1 */
- int status; /* e.g. 200 */
- buffer *reason; /* e.g. Ok */
- array *headers;
-} http_resp;
-
-typedef struct {
- int ok;
- buffer *errmsg;
-
- http_resp *resp;
-
- buffer_pool *unused_buffers;
-} http_resp_ctx_t;
-
-LI_API http_resp * http_response_init(void);
-LI_API void http_response_free(http_resp *resp);
-LI_API void http_response_reset(http_resp *resp);
-
-LI_API parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
-
-/* declare prototypes for the parser */
-void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
-void http_resp_parserFree(void *p, void (*freeProc)(void*));
-void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
-void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
-
-#endif
diff --git a/src/http_resp_parser.y b/src/http_resp_parser.y
deleted file mode 100644
index 7305f682..00000000
--- a/src/http_resp_parser.y
+++ /dev/null
@@ -1,143 +0,0 @@
-%token_prefix TK_
-%token_type {buffer *}
-%extra_argument {http_resp_ctx_t *ctx}
-%name http_resp_parser
-
-%include {
-#include <assert.h>
-#include <string.h>
-#include "http_resp.h"
-#include "keyvalue.h"
-#include "array.h"
-#include "log.h"
-}
-
-%parse_failure {
- ctx->ok = 0;
-}
-
-%type protocol { int }
-%type response_hdr { http_resp * }
-%type number { int }
-%type headers { array * }
-%type header { data_string * }
-%destructor reason { buffer_free($$); }
-%token_destructor { buffer_free($$); }
-
-/* just headers + Status: ... */
-response_hdr ::= header headers CRLF . {
- http_resp *resp = ctx->resp;
- data_string *ds;
-
- resp->protocol = HTTP_VERSION_UNSET;
-
- buffer_copy_string(resp->reason, ""); /* no reason */
-
- if (NULL == (ds = (data_string *)array_get_element(resp->headers, CONST_STR_LEN("Status")))) {
- resp->status = 0;
- } else {
- char *err;
- resp->status = strtol(ds->value->ptr, &err, 10);
-
- if (*err != '\0' && *err != ' ' && *err != '\r') {
- buffer_copy_string(ctx->errmsg, "expected a number: ");
- buffer_append_string_buffer(ctx->errmsg, ds->value);
- buffer_append_string(ctx->errmsg, err);
-
- ctx->ok = 0;
- }
- }
-}
-
-/* HTTP-Version SP Status-Code SP Reason-Phrase CRLF ... */
-response_hdr ::= protocol(B) number(C) reason(D) CRLF headers CRLF . {
- http_resp *resp = ctx->resp;
-
- resp->status = C;
- resp->protocol = B;
- buffer_copy_string_buffer(resp->reason, D);
- buffer_pool_append(ctx->unused_buffers, D);
-}
-
-/* HTTP-Version SP Status-Code CRLF ... */
-response_hdr ::= protocol(B) number(C) CRLF headers CRLF . {
- http_resp *resp = ctx->resp;
-
- resp->status = C;
- resp->protocol = B;
- buffer_reset(resp->reason);
-}
-
-protocol(A) ::= STRING(B). {
- if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
- A = HTTP_VERSION_1_0;
- } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
- A = HTTP_VERSION_1_1;
- } else {
- buffer_copy_string(ctx->errmsg, "unknown protocol: ");
- buffer_append_string_buffer(ctx->errmsg, B);
-
- ctx->ok = 0;
- }
- buffer_pool_append(ctx->unused_buffers, B);
-}
-
-number(A) ::= STRING(B). {
- char *err;
- A = strtol(B->ptr, &err, 10);
-
- if (*err != '\0') {
- buffer_copy_string(ctx->errmsg, "expected a number, got: ");
- buffer_append_string_buffer(ctx->errmsg, B);
-
- ctx->ok = 0;
- }
- buffer_pool_append(ctx->unused_buffers, B);
-}
-
-reason(A) ::= STRING(B). {
- A = B;
-}
-
-reason(A) ::= reason(C) STRING(B). {
- A = C;
-
- buffer_append_string(A, " ");
- buffer_append_string_buffer(A, B);
-
- buffer_pool_append(ctx->unused_buffers, B);
-}
-
-headers ::= headers header.
-headers ::= .
-
-header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
- http_resp *resp = ctx->resp;
-
- if (NULL == (HDR = (data_string *)array_get_unused_element(resp->headers, TYPE_STRING))) {
- HDR = data_response_init();
- }
-
- buffer_copy_string_buffer(HDR->key, A);
- buffer_copy_string_buffer(HDR->value, B);
- buffer_pool_append(ctx->unused_buffers, A);
- buffer_pool_append(ctx->unused_buffers, B);
-
- array_insert_unique(resp->headers, (data_unset *)HDR);
-}
-
-/* empty headers */
-header(HDR) ::= STRING(A) COLON CRLF. {
- http_resp *resp = ctx->resp;
-
- if (NULL == (HDR = (data_string *)array_get_unused_element(resp->headers, TYPE_STRING))) {
- HDR = data_response_init();
- }
-
- buffer_copy_string_buffer(HDR->key, A);
- buffer_copy_string(HDR->value, "");
- buffer_pool_append(ctx->unused_buffers, A);
-
- array_insert_unique(resp->headers, (data_unset *)HDR);
-}
-
diff --git a/src/http_resp_test.c b/src/http_resp_test.c
deleted file mode 100644
index 2d91034d..00000000
--- a/src/http_resp_test.c
+++ /dev/null
@@ -1,141 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <tap.h>
-
-#include "http_resp.h"
-#include "log.h"
-
-const char* chunkqueue_to_buffer(chunkqueue *cq, buffer *b) {
- chunk *c;
-
- buffer_reset(b);
-
- for (c = cq->first; c; c = c->next) {
- buffer_append_string(b, c->mem->ptr + c->offset);
- }
-
- return b->ptr;
-}
-
-int main(void) {
- http_resp *resp = http_response_init();
- chunkqueue *cq = chunkqueue_init();
- buffer *b, *content = buffer_init();
- const char *body;
-
- log_init();
- plan_tests(9);
-
- /* basic response header + CRLF */
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "HTTP/1.0 304 Not Modified\r\n"
- "Location: foobar\r\n"
- "Content-Lenght: 24\r\n"
- "\r\nABC"
- );
-
- ok(PARSE_SUCCESS == http_response_parse_cq(cq, resp), "good 304 response with CRLF");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- http_response_free(resp);
-
- /* line-wrapping */
-
- chunkqueue_reset(cq);
- resp = http_response_init();
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string(b,
- "HTTP/1.0 304 Not Modified\n"
- "Location: foobar\n"
- "Content-Lenght: 24\n"
- "\nABC"
- );
-
- ok(PARSE_SUCCESS == http_response_parse_cq(cq, resp), "good response with LF");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- http_response_free(resp);
-
- /* no request line */
-
- chunkqueue_reset(cq);
- resp = http_response_init();
-
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "Status: 200 Foobar\r\n"
- "Location: foobar\r\n"
- "Content-Lenght: 24\r\n"
- "\r\nABC"
- );
-
- ok(PARSE_SUCCESS == http_response_parse_cq(cq, resp), "Status: 200 ...");
-
- http_response_free(resp);
-
- /* LF as line-ending */
-
- chunkqueue_reset(cq);
- resp = http_response_init();
-
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "Location: foobar\n"
- "\nABC"
- );
- ok(PARSE_SUCCESS == http_response_parse_cq(cq, resp), "no Status at all");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- /* LF as line-ending */
-
- chunkqueue_reset(cq);
- resp = http_response_init();
-
- b = chunkqueue_get_append_buffer(cq);
-
- buffer_copy_string(b,
- "HTTP");
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string_len(b, CONST_STR_LEN("/1.0 "));
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string_len(b, CONST_STR_LEN("30"));
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string_len(b, CONST_STR_LEN("4 Not Modified\r"));
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string(b, "\n"
- "Locati");
-
- b = chunkqueue_get_append_buffer(cq);
- buffer_copy_string(b, "on: foobar\r\n"
- "Content-Lenght: 24\r\n"
- "\r\nABC"
- );
- ok(PARSE_SUCCESS == http_response_parse_cq(cq, resp), "chunked response");
-
- chunkqueue_remove_finished_chunks(cq);
- body = chunkqueue_to_buffer(cq, content);
- ok(0 == strcmp("ABC", body), "content is ABC, got %s", body);
-
- http_response_free(resp);
- chunkqueue_free(cq);
- buffer_free(content);
- log_free();
-
- return exit_status();
-}
diff --git a/src/inet_ntop_cache.c b/src/inet_ntop_cache.c
deleted file mode 100644
index 51755df3..00000000
--- a/src/inet_ntop_cache.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <sys/types.h>
-
-#include <string.h>
-
-
-#include "base.h"
-#include "inet_ntop_cache.h"
-#include "sys-socket.h"
-
-const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
-#ifdef HAVE_IPV6
- size_t ndx = 0, i;
- for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
- if (srv->inet_ntop_cache[i].ts != 0 && srv->inet_ntop_cache[i].family == addr->plain.sa_family) {
- if (srv->inet_ntop_cache[i].family == AF_INET6 &&
- 0 == memcmp(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16)) {
- /* IPv6 found in cache */
- break;
- } else if (srv->inet_ntop_cache[i].family == AF_INET &&
- srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
- /* IPv4 found in cache */
- break;
-
- }
- }
- }
-
- if (i == INET_NTOP_CACHE_MAX) {
- /* not found in cache */
-
- i = ndx;
- inet_ntop(addr->plain.sa_family,
- addr->plain.sa_family == AF_INET6 ?
- (const void *) &(addr->ipv6.sin6_addr) :
- (const void *) &(addr->ipv4.sin_addr),
- srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
-
- srv->inet_ntop_cache[i].ts = srv->cur_ts;
- srv->inet_ntop_cache[i].family = addr->plain.sa_family;
-
- if (srv->inet_ntop_cache[i].family == AF_INET) {
- srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
- } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
- memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
- }
- }
-
- return srv->inet_ntop_cache[i].b2;
-#else
- UNUSED(srv);
- return inet_ntoa(addr->ipv4.sin_addr);
-#endif
-}
diff --git a/src/inet_ntop_cache.h b/src/inet_ntop_cache.h
deleted file mode 100644
index b2a769f2..00000000
--- a/src/inet_ntop_cache.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _INET_NTOP_CACHE_H_
-#define _INET_NTOP_CACHE_H_
-
-#include "base.h"
-LI_API const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr);
-
-#endif
diff --git a/src/iosocket.c b/src/iosocket.c
deleted file mode 100644
index 25d477ff..00000000
--- a/src/iosocket.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <stdlib.h>
-
-#include "iosocket.h"
-#include "sys-socket.h"
-#include "sys-files.h"
-#include "array-static.h"
-
-iosocket *iosocket_init(void) {
- STRUCT_INIT(iosocket, sock);
-
- sock->fde_ndx = -1;
- sock->fd = -1;
-
- sock->type = IOSOCKET_TYPE_SOCKET;
-
-#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
- sock->tlsext_server_name = buffer_init();
-#endif
-
- return sock;
-}
-
-void iosocket_free(iosocket *sock) {
- if (!sock) return;
-
- if (sock->fd != -1) {
- switch (sock->type) {
- case IOSOCKET_TYPE_SOCKET:
- closesocket(sock->fd);
- break;
- case IOSOCKET_TYPE_PIPE:
- close(sock->fd);
- break;
- default:
- break;
- }
- }
-
-#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
- buffer_free(sock->tlsext_server_name);
-#endif
-
- free(sock);
-}
diff --git a/src/iosocket.h b/src/iosocket.h
deleted file mode 100644
index a11dbfe0..00000000
--- a/src/iosocket.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _IOSOCKET_H_
-#define _IOSOCKET_H_
-
-/**
- * make sure we know about OPENSSL all the time
- *
- * if we don't include config.h here we run into different sizes
- * for the iosocket-struct depending on config.h include before
- * iosocket.h or not
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
-# define USE_OPENSSL
-# include <openssl/ssl.h>
-#endif
-
-#include "settings.h"
-#include "buffer.h"
-
-typedef enum {
- IOSOCKET_TYPE_UNSET,
- IOSOCKET_TYPE_SOCKET,
- IOSOCKET_TYPE_PIPE
-} iosocket_t;
-
-/**
- * a non-blocking fd
- */
-typedef struct {
- int fd;
- int fde_ndx;
-
-#ifdef USE_OPENSSL
- SSL *ssl;
-#ifndef OPENSSL_NO_TLSEXT
- buffer *tlsext_server_name;
-#endif
-#endif
-
- iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
-} iosocket;
-
-LI_API iosocket * iosocket_init(void);
-LI_API void iosocket_free(iosocket *sock);
-
-#endif
diff --git a/src/joblist.c b/src/joblist.c
deleted file mode 100644
index 8f68f496..00000000
--- a/src/joblist.c
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "base.h"
-#include "joblist.h"
-#include "log.h"
-
-void joblist_append(server *srv, connection *con) {
- if (con->in_joblist) return;
- con->in_joblist = 1;
-
- if (srv->joblist->size == 0) {
- srv->joblist->size = 16;
- srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
- } 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);
- }
-
- srv->joblist->ptr[srv->joblist->used++] = con;
-}
-
-void joblist_free(server *srv, connections *joblist) {
- UNUSED(srv);
-
- free(joblist->ptr);
- free(joblist);
-}
-
-#ifdef USE_GTHREAD
-void joblist_async_append(server *srv, connection *con) {
- g_async_queue_push(srv->joblist_queue, con);
-
- server_wakeup(srv);
-}
-
-void server_wakeup(server *srv) {
- if (g_atomic_int_compare_and_exchange(&srv->did_wakeup, 0, 1)) {
- write(srv->wakeup_pipe[1], " ", 1);
- }
-}
-#endif
-
-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);
- } 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);
- }
-
- 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/src/joblist.h b/src/joblist.h
deleted file mode 100644
index 2f6bb236..00000000
--- a/src/joblist.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _JOB_LIST_H_
-#define _JOB_LIST_H_
-
-#include "base.h"
-
-LI_API void joblist_append(server *srv, connection *con);
-LI_API void joblist_free(server *srv, connections *joblist);
-
-#ifdef USE_GTHREAD
-LI_API void joblist_async_append(server *srv, connection *con);
-
-LI_API void server_wakeup(server *srv);
-#endif
-
-LI_API int fdwaitqueue_append(server *srv, connection *con);
-LI_API void fdwaitqueue_free(server *srv, connections *fdwaitqueue);
-LI_API connection* fdwaitqueue_unshift(server *srv, connections *fdwaitqueue);
-
-#endif
diff --git a/src/keyvalue.c b/src/keyvalue.c
deleted file mode 100644
index a615116d..00000000
--- a/src/keyvalue.c
+++ /dev/null
@@ -1,390 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "base.h"
-#include "server.h"
-#include "keyvalue.h"
-
-static keyvalue http_versions[] = {
- { HTTP_VERSION_1_1, "HTTP/1.1" },
- { HTTP_VERSION_1_0, "HTTP/1.0" },
- { HTTP_VERSION_UNSET, NULL }
-};
-
-static keyvalue http_methods[] = {
- { HTTP_METHOD_GET, "GET" },
- { HTTP_METHOD_POST, "POST" },
- { HTTP_METHOD_HEAD, "HEAD" },
- { HTTP_METHOD_PROPFIND, "PROPFIND" },
- { HTTP_METHOD_PROPPATCH, "PROPPATCH" },
- { HTTP_METHOD_REPORT, "REPORT" },
- { HTTP_METHOD_OPTIONS, "OPTIONS" },
- { HTTP_METHOD_MKCOL, "MKCOL" },
- { HTTP_METHOD_PUT, "PUT" },
- { HTTP_METHOD_DELETE, "DELETE" },
- { HTTP_METHOD_COPY, "COPY" },
- { HTTP_METHOD_MOVE, "MOVE" },
- { HTTP_METHOD_LABEL, "LABEL" },
- { HTTP_METHOD_CHECKOUT, "CHECKOUT" },
- { HTTP_METHOD_CHECKIN, "CHECKIN" },
- { HTTP_METHOD_MERGE, "MERGE" },
- { HTTP_METHOD_LOCK, "LOCK" },
- { HTTP_METHOD_UNLOCK, "UNLOCK" },
- { HTTP_METHOD_MKACTIVITY, "MKACTIVITY" },
- { HTTP_METHOD_UNCHECKOUT, "UNCHECKOUT" },
- { HTTP_METHOD_VERSION_CONTROL, "VERSION-CONTROL" },
- { HTTP_METHOD_CONNECT, "CONNECT" },
-
- { HTTP_METHOD_UNSET, NULL }
-};
-
-static keyvalue http_status[] = {
- { 100, "Continue" },
- { 101, "Switching Protocols" },
- { 102, "Processing" }, /* WebDAV */
- { 200, "OK" },
- { 201, "Created" },
- { 202, "Accepted" },
- { 203, "Non-Authoritative Information" },
- { 204, "No Content" },
- { 205, "Reset Content" },
- { 206, "Partial Content" },
- { 207, "Multi-status" }, /* WebDAV */
- { 300, "Multiple Choices" },
- { 301, "Moved Permanently" },
- { 302, "Found" },
- { 303, "See Other" },
- { 304, "Not Modified" },
- { 305, "Use Proxy" },
- { 306, "(Unused)" },
- { 307, "Temporary Redirect" },
- { 400, "Bad Request" },
- { 401, "Unauthorized" },
- { 402, "Payment Required" },
- { 403, "Forbidden" },
- { 404, "Not Found" },
- { 405, "Method Not Allowed" },
- { 406, "Not Acceptable" },
- { 407, "Proxy Authentication Required" },
- { 408, "Request Timeout" },
- { 409, "Conflict" },
- { 410, "Gone" },
- { 411, "Length Required" },
- { 412, "Precondition Failed" },
- { 413, "Request Entity Too Large" },
- { 414, "Request-URI Too Long" },
- { 415, "Unsupported Media Type" },
- { 416, "Requested Range Not Satisfiable" },
- { 417, "Expectation Failed" },
- { 422, "Unprocessable Entity" }, /* WebDAV */
- { 423, "Locked" }, /* WebDAV */
- { 424, "Failed Dependency" }, /* WebDAV */
- { 426, "Upgrade Required" }, /* TLS */
- { 500, "Internal Server Error" },
- { 501, "Not Implemented" },
- { 502, "Bad Gateway" },
- { 503, "Service Not Available" },
- { 504, "Gateway Timeout" },
- { 505, "HTTP Version Not Supported" },
- { 507, "Insufficient Storage" }, /* WebDAV */
- { 509, "Bandwidth Limit exceeded" },
-
- { -1, NULL }
-};
-
-static keyvalue http_status_body[] = {
- { 400, "400.html" },
- { 401, "401.html" },
- { 403, "403.html" },
- { 404, "404.html" },
- { 411, "411.html" },
- { 416, "416.html" },
- { 500, "500.html" },
- { 501, "501.html" },
- { 503, "503.html" },
- { 505, "505.html" },
-
- { -1, NULL }
-};
-
-
-const char *keyvalue_get_value(keyvalue *kv, int k) {
- int i;
- for (i = 0; kv[i].value; i++) {
- if (kv[i].key == k) return kv[i].value;
- }
- return NULL;
-}
-
-int keyvalue_get_key(keyvalue *kv, const char *s) {
- int i;
- for (i = 0; kv[i].value; i++) {
- if (0 == strcmp(kv[i].value, s)) return kv[i].key;
- }
- return -1;
-}
-
-keyvalue_buffer *keyvalue_buffer_init(void) {
- keyvalue_buffer *kvb;
-
- kvb = calloc(1, sizeof(*kvb));
-
- return kvb;
-}
-
-int keyvalue_buffer_append(keyvalue_buffer *kvb, int key, const char *value) {
- size_t i;
- if (kvb->size == 0) {
- kvb->size = 4;
-
- kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
- for(i = 0; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- } else if (kvb->used == kvb->size) {
- kvb->size += 4;
-
- kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
- for(i = kvb->used; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- }
-
- kvb->kv[kvb->used]->key = key;
- kvb->kv[kvb->used]->value = strdup(value);
-
- kvb->used++;
-
- return 0;
-}
-
-void keyvalue_buffer_free(keyvalue_buffer *kvb) {
- size_t i;
-
- for (i = 0; i < kvb->size; i++) {
- if (kvb->kv[i]->value) free(kvb->kv[i]->value);
- free(kvb->kv[i]);
- }
-
- if (kvb->kv) free(kvb->kv);
-
- free(kvb);
-}
-
-
-s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
- s_keyvalue_buffer *kvb;
-
- kvb = calloc(1, sizeof(*kvb));
-
- return kvb;
-}
-
-int s_keyvalue_buffer_append(s_keyvalue_buffer *kvb, const char *key, const char *value) {
- size_t i;
- if (kvb->size == 0) {
- kvb->size = 4;
- kvb->used = 0;
-
- kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
- for(i = 0; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- } else if (kvb->used == kvb->size) {
- kvb->size += 4;
-
- kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
- for(i = kvb->used; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- }
-
- kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
- kvb->kv[kvb->used]->value = strdup(value);
-
- kvb->used++;
-
- return 0;
-}
-
-void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
- size_t i;
-
- for (i = 0; i < kvb->size; i++) {
- if (kvb->kv[i]->key) free(kvb->kv[i]->key);
- if (kvb->kv[i]->value) free(kvb->kv[i]->value);
- free(kvb->kv[i]);
- }
-
- if (kvb->kv) free(kvb->kv);
-
- free(kvb);
-}
-
-
-httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
- httpauth_keyvalue_buffer *kvb;
-
- kvb = calloc(1, sizeof(*kvb));
-
- return kvb;
-}
-
-int httpauth_keyvalue_buffer_append(httpauth_keyvalue_buffer *kvb, const char *key, const char *realm, httpauth_type type) {
- size_t i;
- if (kvb->size == 0) {
- kvb->size = 4;
-
- kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
- for(i = 0; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- } else if (kvb->used == kvb->size) {
- kvb->size += 4;
-
- kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
- for(i = kvb->used; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- }
-
- kvb->kv[kvb->used]->key = strdup(key);
- kvb->kv[kvb->used]->realm = strdup(realm);
- kvb->kv[kvb->used]->type = type;
-
- kvb->used++;
-
- return 0;
-}
-
-void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
- size_t i;
-
- for (i = 0; i < kvb->size; i++) {
- if (kvb->kv[i]->key) free(kvb->kv[i]->key);
- if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
- free(kvb->kv[i]);
- }
-
- if (kvb->kv) free(kvb->kv);
-
- free(kvb);
-}
-
-
-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);
-}
-
-const char *get_http_status_body_name(int i) {
- return keyvalue_get_value(http_status_body, 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);
-}
-
-
-
-
-pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
- pcre_keyvalue_buffer *kvb;
-
- kvb = calloc(1, sizeof(*kvb));
-
- return kvb;
-}
-
-int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, const char *value) {
-#ifdef HAVE_PCRE_H
- size_t i;
- const char *errptr;
- int erroff;
- pcre_keyvalue *kv;
-#endif
-
- if (!key) return -1;
-
-#ifdef HAVE_PCRE_H
- if (kvb->size == 0) {
- kvb->size = 4;
- kvb->used = 0;
-
- kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
- for(i = 0; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- } else if (kvb->used == kvb->size) {
- kvb->size += 4;
-
- kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
- for(i = kvb->used; i < kvb->size; i++) {
- kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
- }
- }
-
- kv = kvb->kv[kvb->used];
- if (NULL == (kv->key = pcre_compile(key,
- 0, &errptr, &erroff, NULL))) {
-
- fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
- return -1;
- }
-
- if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
- errptr != NULL) {
- return -1;
- }
-
- kv->value = buffer_init_string(value);
-
- kvb->used++;
-
- return 0;
-#else
- UNUSED(kvb);
- UNUSED(value);
-
- return -1;
-#endif
-}
-
-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);
-}
diff --git a/src/keyvalue.h b/src/keyvalue.h
deleted file mode 100644
index e3b65c38..00000000
--- a/src/keyvalue.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef _KEY_VALUE_H_
-#define _KEY_VALUE_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_PCRE_H
-# include <pcre.h>
-#endif
-
-typedef enum {
- HTTP_METHOD_UNSET = -1,
- HTTP_METHOD_GET,
- HTTP_METHOD_POST,
- HTTP_METHOD_HEAD,
- HTTP_METHOD_OPTIONS,
- HTTP_METHOD_PROPFIND, /* WebDAV */
- HTTP_METHOD_MKCOL,
- HTTP_METHOD_PUT,
- HTTP_METHOD_DELETE,
- HTTP_METHOD_COPY,
- HTTP_METHOD_MOVE,
- HTTP_METHOD_PROPPATCH,
- HTTP_METHOD_REPORT, /* DeltaV */
- HTTP_METHOD_CHECKOUT,
- HTTP_METHOD_CHECKIN,
- HTTP_METHOD_VERSION_CONTROL,
- HTTP_METHOD_UNCHECKOUT,
- HTTP_METHOD_MKACTIVITY,
- HTTP_METHOD_MERGE,
- HTTP_METHOD_LOCK,
- HTTP_METHOD_UNLOCK,
- HTTP_METHOD_LABEL,
- HTTP_METHOD_CONNECT
-} http_method_t;
-
-typedef enum {
- HTTP_VERSION_UNSET = -1,
- HTTP_VERSION_1_0,
- HTTP_VERSION_1_1
-} http_version_t;
-
-typedef struct {
- int key;
-
- char *value;
-} keyvalue;
-
-typedef struct {
- char *key;
-
- char *value;
-} s_keyvalue;
-
-typedef struct {
-#ifdef HAVE_PCRE_H
- pcre *key;
- pcre_extra *key_extra;
-#endif
-
- buffer *value;
-} pcre_keyvalue;
-
-typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type;
-
-typedef struct {
- char *key;
-
- char *realm;
- httpauth_type type;
-} httpauth_keyvalue;
-
-#define KVB(x) \
-typedef struct {\
- x **kv; \
- size_t used;\
- size_t size;\
-} x ## _buffer
-
-KVB(keyvalue);
-KVB(s_keyvalue);
-KVB(httpauth_keyvalue);
-KVB(pcre_keyvalue);
-
-LI_API const char * get_http_status_name(int i);
-LI_API const char * get_http_version_name(int i);
-LI_API const char * get_http_method_name(http_method_t i);
-LI_API const char * get_http_status_body_name(int i);
-LI_API int get_http_version_key(const char *s);
-LI_API http_method_t get_http_method_key(const char *s);
-
-LI_API const char * keyvalue_get_value(keyvalue *kv, int k);
-LI_API int keyvalue_get_key(keyvalue *kv, const char *s);
-
-LI_API keyvalue_buffer * keyvalue_buffer_init(void);
-LI_API int keyvalue_buffer_append(keyvalue_buffer *kvb, int k, const char *value);
-LI_API void keyvalue_buffer_free(keyvalue_buffer *kvb);
-
-LI_API s_keyvalue_buffer * s_keyvalue_buffer_init(void);
-LI_API int s_keyvalue_buffer_append(s_keyvalue_buffer *kvb, const char *key, const char *value);
-LI_API void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb);
-
-LI_API httpauth_keyvalue_buffer * httpauth_keyvalue_buffer_init(void);
-LI_API int httpauth_keyvalue_buffer_append(httpauth_keyvalue_buffer *kvb, const char *key, const char *realm, httpauth_type type);
-LI_API void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb);
-
-LI_API pcre_keyvalue_buffer * pcre_keyvalue_buffer_init(void);
-LI_API int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, const char *value);
-LI_API void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb);
-
-#endif
diff --git a/src/lemon.c b/src/lemon.c
deleted file mode 100644
index ac37f907..00000000
--- a/src/lemon.c
+++ /dev/null
@@ -1,4400 +0,0 @@
-/*
-** 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 <unistd.h>
-
-extern void qsort();
-extern double strtod();
-extern long strtol();
-extern void free();
-extern int access();
-extern int atoi();
-extern char *getenv();
-
-#ifndef __WIN32__
-# if defined(_WIN32) || defined(WIN32)
-# define __WIN32__
-# endif
-#endif
-
-#define PRIVATE static
-/* #define PRIVATE */
-
-#ifdef TEST
-#define MAXRHS 5 /* Set low to exercise exception code */
-#else
-#define MAXRHS 1000
-#endif
-
-char *msort();
-extern void *malloc();
-
-extern void memory_error();
-
-/******** From the file "action.h" *************************************/
-struct action *Action_new();
-struct action *Action_sort();
-void Action_add();
-
-/********* From the file "assert.h" ************************************/
-void myassert();
-#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;
- char *arg;
- 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(/* */);
-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 = 0;
- struct action *new;
-
- if( freelist==0 ){
- 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,&ap->next,actioncmp);
- return ap;
-}
-
-void Action_add(app,type,sp,arg)
-struct action **app;
-enum e_action type;
-struct symbol *sp;
-char *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 plink *plp;
- int progress;
- int change;
-
- for(i=0; i<lemp->nstate; i++){
- for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){
- cfp->status = INCOMPLETE;
- }
- }
-
- do{
- progress = 0;
- for(i=0; i<lemp->nstate; i++){
- for(cfp=lemp->sorted[i]->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. */
- Action_add(&lemp->sorted[0]->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)
-struct action *apx;
-struct action *apy;
-{
- struct symbol *spx, *spy;
- int errcnt = 0;
- 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,&(current->next),Configcmp);
- currentend = 0;
- return;
-}
-
-/* Sort the basis configuration list */
-void Configlist_sortbasis(){
- basis = (struct config *)msort(current,&(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);
-}
-
-
-/* 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_FLAG,0,0,0}
- };
- int i;
- struct lemon lem;
- char *def_tmpl_name = "lempar.c";
- ( (void) argc ); // 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 */
- lem.nsymbol = Symbol_count();
- Symbol_new("{default}");
- lem.symbols = Symbol_arrayof();
- for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
- qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*),
- (int(*)())Symbolcmpp);
- for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
- for(i=1; isupper(lem.symbols[i]->name[0]); i++);
- 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.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
-char *msort(list,next,cmp)
-char *list;
-char **next;
-int (*cmp)();
-{
- 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, i;
- spcnt = 0;
- 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 thru to next case */
- 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(lemp->filename) + strlen(suffix) + 5 );
- 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,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 */
-PRIVATE 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 *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 = 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",lemp->tmplname);
- lemp->errorcnt++;
- return 0;
- }
- 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 if( lemp->vardest ){
- 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 = *plineno; /* 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 = hash*53 + 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;
-{
- int h = 0;
- while( *x) h = h*13 + *(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;
- }
- /* 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;
- }
- /* 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;
-{
- int h=0;
- while( a ){
- h = h*571 + a->rp->index*37 + 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;
- }
- /* 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 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;
- }
- /* 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/src/lempar.c b/src/lempar.c
deleted file mode 100644
index c98720a6..00000000
--- a/src/lempar.c
+++ /dev/null
@@ -1,693 +0,0 @@
-/* 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 <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 = 0;
-static char *yyTracePrompt = 0;
-#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 = &pParser->yystack[pParser->yyidx];
-
- if( pParser->yyidx<0 ) return 0;
-#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==0 ) 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 && yyruleno>=0
- && (size_t) yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
- fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
- yyRuleName[yyruleno]);
- }
-#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;
- ( (void) yymajor );
- ( (void) 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; /* Accept empty input */
- 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/src/log.c b/src/log.c
deleted file mode 100644
index 401ab50d..00000000
--- a/src/log.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <time.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef _WIN32
-#undef HAVE_SYSLOG_H
-#endif
-
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#include "log.h"
-#include "array.h"
-
-#include "sys-files.h"
-
-#ifdef _WIN32
-#define STDERR_FILENO 2
-#endif
-
-#ifndef O_LARGEFILE
-# define O_LARGEFILE 0
-#endif
-
-/* Close fd and _try_ to get a /dev/null for it instead.
- * close() alone may trigger some bugs when a
- * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO
- * and later tries to just print on stdout/stderr
- *
- * Returns 0 on success and -1 on failure (fd gets closed in all cases)
- */
-int openDevNull(int fd) {
- int tmpfd;
- close(fd);
-#if defined(__WIN32)
- /* Cygwin should work with /dev/null */
- tmpfd = open("nul", O_RDWR);
-#else
- tmpfd = open("/dev/null", O_RDWR);
-#endif
- if (tmpfd != -1 && tmpfd != fd) {
- dup2(tmpfd, fd);
- close(tmpfd);
- }
- return (tmpfd != -1) ? 0 : -1;
-}
-
-/**
- * open the errorlog
- *
- * we have 3 possibilities:
- * - stderr (default)
- * - syslog
- * - logfile
- *
- * if the open failed, report to the user and die
- *
- */
-
-
-typedef struct {
- buffer *file;
- unsigned short use_syslog;
-
- /* the errorlog */
- int fd;
- enum { ERRORLOG_FILE, ERRORLOG_FD, ERRORLOG_SYSLOG } mode;
- buffer *buf;
-
- time_t cached_ts;
- buffer *cached_ts_str;
-} errorlog;
-
-errorlog *myconfig = NULL;
-
-void log_init(void) {
- /* use syslog */
- errorlog *err;
-
- err = calloc(1, sizeof(*err));
-
- err->fd = STDERR_FILENO;
- err->mode = ERRORLOG_FD;
- err->buf = buffer_init();
- err->cached_ts_str = buffer_init();
-
- myconfig = err;
-}
-
-void log_free(void) {
- errorlog *err = myconfig;
-
- if (!err) return;
-
- switch(err->mode) {
- case ERRORLOG_FILE:
- case ERRORLOG_FD:
- if (-1 != err->fd) {
- if (STDERR_FILENO != err->fd)
- close(err->fd);
- err->fd = -1;
- }
- break;
- case ERRORLOG_SYSLOG:
-#ifdef HAVE_SYSLOG_H
- closelog();
-#endif
- break;
- }
-
- buffer_free(err->buf);
- buffer_free(err->cached_ts_str);
-
- free(err);
-
- myconfig = NULL;
-}
-
-int log_error_open(buffer *file, buffer *breakage_file, int use_syslog, int dont_daemonize) {
- errorlog *err = myconfig;
-
-#ifdef HAVE_SYSLOG_H
- /* perhaps someone wants to use syslog() */
- openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
-#endif
- err->mode = ERRORLOG_FD;
- err->fd = STDERR_FILENO;
-
- if (use_syslog) {
- err->mode = ERRORLOG_SYSLOG;
- } else if (!buffer_is_empty(file)) {
- if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
- log_error_write(NULL, __FILE__, __LINE__, "SBSS",
- "opening errorlog '", file,
- "' failed: ", strerror(errno));
-
- return -1;
- }
-#ifdef FD_CLOEXEC
- /* close fd on exec (cgi) */
- fcntl(err->fd, F_SETFD, FD_CLOEXEC);
-#endif
- err->mode = ERRORLOG_FILE;
- err->file = file;
- }
-
- TRACE("%s", "server started");
-
- if (err->mode == ERRORLOG_FD && !dont_daemonize) {
- /* We can only log to stderr in dont-daemonize mode */
- err->fd = -1;
- }
-
- if (!buffer_is_empty(breakage_file)) {
- int breakage_fd;
-
- if (err->mode == ERRORLOG_FD) {
- err->fd = dup(STDERR_FILENO);
-#ifdef FD_CLOEXEC
- fcntl(err->fd, F_SETFD, FD_CLOEXEC);
-#endif
- }
-
- if (-1 == (breakage_fd = open(breakage_file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
- log_error_write(NULL, __FILE__, __LINE__, "SBSS",
- "opening breakagelog '", breakage_file,
- "' failed: ", strerror(errno));
-
- return -1;
- }
-
- if (STDERR_FILENO != breakage_fd) {
- dup2(breakage_fd, STDERR_FILENO);
- close(breakage_fd);
- }
- } else if (!dont_daemonize) {
- /* move stderr to /dev/null */
- openDevNull(STDERR_FILENO);
- }
-
-
- return 0;
-}
-
-/**
- * open the errorlog
- *
- * if the open failed, report to the user and die
- * if no filename is given, use syslog instead
- *
- */
-
-int log_error_cycle(void) {
- /* only cycle if we are not in syslog-mode */
-
- errorlog *err = myconfig;
-
- if (err->mode == ERRORLOG_FILE) {
- buffer *file = err->file;
- /* already check of opening time */
-
- int new_fd;
-
- if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
- /* write to old log */
- log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
- "cycling errorlog '", file,
- "' failed: ", strerror(errno),
- ", falling back to syslog()");
-
- close(err->fd);
- err->fd = -1;
-#ifdef HAVE_SYSLOG_H
- err->mode = ERRORLOG_SYSLOG;
-#endif
- } else {
- /* ok, new log is open, close the old one */
- close(err->fd);
- err->fd = new_fd;
- }
- }
-
- return 0;
-}
-
-int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
- va_list ap;
- time_t t;
-
- errorlog *err = myconfig;
-
- UNUSED(srv);
-
- switch(err->mode) {
- case ERRORLOG_FILE:
- case ERRORLOG_FD:
- if (-1 == err->fd) return 0;
- /* cache the generated timestamp */
- t = time(NULL);
-
- if (t != err->cached_ts) {
- buffer_prepare_copy(err->cached_ts_str, 255);
- strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
- err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
- err->cached_ts = t;
- }
-
- buffer_copy_string_buffer(err->buf, err->cached_ts_str);
- buffer_append_string_len(err->buf, CONST_STR_LEN(" ("));
- break;
- case ERRORLOG_SYSLOG:
- /* syslog is generating its own timestamps */
- buffer_copy_string_len(err->buf, CONST_STR_LEN("("));
- break;
- }
-
- buffer_append_string(err->buf, REMOVE_PATH(filename));
- buffer_append_string_len(err->buf, CONST_STR_LEN(":"));
- buffer_append_long(err->buf, line);
- buffer_append_string_len(err->buf, CONST_STR_LEN(") "));
-
- for(va_start(ap, fmt); *fmt; fmt++) {
- int d;
- char *s;
- buffer *b;
- off_t o;
-
- switch(*fmt) {
- case 's': /* string */
- s = va_arg(ap, char *);
- buffer_append_string(err->buf, s);
- buffer_append_string_len(err->buf, CONST_STR_LEN(" "));
- break;
- case 'b': /* buffer */
- b = va_arg(ap, buffer *);
- buffer_append_string_buffer(err->buf, b);
- buffer_append_string_len(err->buf, CONST_STR_LEN(" "));
- break;
- case 'd': /* int */
- d = va_arg(ap, int);
- buffer_append_long(err->buf, d);
- buffer_append_string_len(err->buf, CONST_STR_LEN(" "));
- break;
- case 'o': /* off_t */
- o = va_arg(ap, off_t);
- buffer_append_off_t(err->buf, o);
- buffer_append_string_len(err->buf, CONST_STR_LEN(" "));
- break;
- case 'x': /* int (hex) */
- d = va_arg(ap, int);
- buffer_append_string_len(err->buf, CONST_STR_LEN("0x"));
- buffer_append_long_hex(err->buf, d);
- buffer_append_string_len(err->buf, CONST_STR_LEN(" "));
- break;
- case 'S': /* string */
- s = va_arg(ap, char *);
- buffer_append_string(err->buf, s);
- break;
- case 'B': /* buffer */
- b = va_arg(ap, buffer *);
- buffer_append_string_buffer(err->buf, b);
- break;
- case 'D': /* int */
- d = va_arg(ap, int);
- buffer_append_long(err->buf, d);
- break;
- case '(':
- case ')':
- case '<':
- case '>':
- case ',':
- case ' ':
- buffer_append_string_len(err->buf, fmt, 1);
- break;
- }
- }
- va_end(ap);
-
- switch(err->mode) {
- case ERRORLOG_FILE:
- case ERRORLOG_FD:
- buffer_append_string_len(err->buf, CONST_STR_LEN("\n"));
- write(err->fd, err->buf->ptr, err->buf->used - 1);
- break;
-#ifdef HAVE_SYSLOG_H
- case ERRORLOG_SYSLOG:
- syslog(LOG_ERR, "%s", err->buf->ptr);
- break;
-#endif
- }
-
- return 0;
-}
-
-int log_trace(const char *fmt, ...) {
- buffer *b;
- int l, tries = 0;
- errorlog *err = myconfig;
- va_list ap;
- time_t t;
- int timestrsize = 0;
-
- b = buffer_init();
- buffer_prepare_copy(b, 4096);
-
- switch(err->mode) {
- case ERRORLOG_FILE:
- case ERRORLOG_FD:
- if (-1 == err->fd) return 0;
- /* cache the generated timestamp */
- t = time(NULL);
-
- if (t != err->cached_ts) {
- buffer_prepare_copy(err->cached_ts_str, 255);
- strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
- err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
- err->cached_ts = t;
- }
-
- buffer_copy_string_buffer(b, err->cached_ts_str);
- buffer_append_string_len(b, CONST_STR_LEN(" "));
- timestrsize = b->used - 1;
- break;
- case ERRORLOG_SYSLOG:
- /* syslog is generating its own timestamps */
- buffer_copy_string_len(b, CONST_STR_LEN(""));
- timestrsize = b->used - 1;
- break;
- }
-
- do {
- errno = 0;
- va_start(ap, fmt);
- l = vsnprintf(b->ptr+timestrsize, b->size-timestrsize, fmt, ap);
- va_end(ap);
-
- /* if 'l' is between -1 and size we are good,
- * otherwise we have to resize to size
- */
-
- if (l > -1 && ((unsigned int) l) < (b->size-timestrsize)) {
- b->used += l;
-
- break;
- }
-
- if (l > -1) {
- /* C99: l is the mem-size we need */
- buffer_prepare_append(b, l + 1); /* allocate a bit more than we need */
- } else if (tries++ >= 3) {
- int e = errno;
- /* glibc 2.0.6 and earlier return -1 if the output was truncated
- * so we try to increase the buffer size 3 times - so you cannot
- * print error messages longer than 8 * 4096 = 32k with glib <= 2.0.6
- */
- buffer_copy_string_len(b, CONST_STR_LEN("log_trace: vsnprintf error: l = "));
- buffer_append_long(b, l);
- if (e) {
- buffer_append_string_len(b, CONST_STR_LEN(", errno = "));
- buffer_append_long(b, errno);
- buffer_append_string_len(b, CONST_STR_LEN(": "));
- buffer_append_string(b, strerror(e));
- }
- break;
- } else {
- buffer_prepare_append(b, 2*b->size);
- }
- } while(1);
-
- /* write b */
- switch(err->mode) {
- case ERRORLOG_FILE:
- case ERRORLOG_FD:
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
- write(err->fd, b->ptr, b->used - 1);
- break;
-#ifdef HAVE_SYSLOG_H
- case ERRORLOG_SYSLOG:
- syslog(LOG_ERR, "%s", b->ptr);
- break;
-#endif
- }
-
- buffer_free(b);
-
- return 0;
-}
-
-#if REMOVE_PATH_FROM_FILE
-const char *remove_path(const char *path) {
- char *p = strrchr(path, DIR_SEPERATOR);
- if (NULL != p && *(p) != '\0') {
- return (p + 1);
- }
- return path;
-}
-#endif
-
diff --git a/src/log.h b/src/log.h
deleted file mode 100644
index 616e6274..00000000
--- a/src/log.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef _LOG_H_
-#define _LOG_H_
-
-#include "valgrind/valgrind.h"
-#include "buffer.h"
-
-/* Close fd and _try_ to get a /dev/null for it instead.
- * Returns 0 on success and -1 on failure (fd gets closed in all cases)
- */
-LI_API int openDevNull(int fd);
-
-LI_API void log_init(void);
-LI_API void log_free(void);
-
-LI_API int log_error_open(buffer* file, buffer* breakage_file, int use_syslog, int dont_daemonize);
-LI_API int log_error_close();
-LI_API int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
-LI_API int log_error_cycle();
-#define REMOVE_PATH_FROM_FILE 1
-#if REMOVE_PATH_FROM_FILE
-LI_API const char *remove_path(const char *path);
-#define REMOVE_PATH(file) remove_path(file)
-#else
-#define REMOVE_PATH(file) file
-#endif
-
-// TODO: perhaps make portable (detect if cc supports)
-#define __ATTRIBUTE_PRINTF_FORMAT(fmt, arg) __attribute__ ((__format__ (__printf__, fmt, arg)))
-
-#define ERROR(fmt, ...) \
- log_trace("(error) (%s:%d) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
-
-#define TRACE(fmt, ...) \
- log_trace("(trace) (%s:%d) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
-
-#define SEGFAULT(fmt, ...) \
- do { \
- log_trace("(crashing) (%s:%d) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \
- VALGRIND_PRINTF_BACKTRACE(fmt, __VA_ARGS__);\
- abort();\
- } while(0)
-LI_API int log_trace(const char *fmt, ...) __ATTRIBUTE_PRINTF_FORMAT(1, 2);
-#endif
diff --git a/src/md5.c b/src/md5.c
deleted file mode 100644
index b365fc41..00000000
--- a/src/md5.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef USE_OPENSSL
-#include <string.h>
-
-#include "md5.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 (context)
-li_MD5_CTX *context; /* 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 (context, input, inputLen)
-li_MD5_CTX *context; /* context */
-const unsigned char *input; /* input block */
-unsigned int inputLen; /* length of input block */
-{
- unsigned int i, ndx, partLen;
-
- /* 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 (digest, context)
-unsigned char digest[16]; /* message digest */
-li_MD5_CTX *context; /* 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 (state, block)
-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 (output, input, len)
-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 (output, input, len)
-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 (output, input, len)
-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 (output, value, len)
-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/src/md5.h b/src/md5.h
deleted file mode 100644
index fbcada0f..00000000
--- a/src/md5.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 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.
- */
-#include <limits.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-
-#ifdef _WIN32
-#define UINT4 unsigned __int32
-#define UINT2 unsigned __int16
-#define POINTER unsigned char *
-#else
-#define UINT4 uint32_t
-#define UINT2 uint16_t
-#define POINTER unsigned char *
-#endif
-
-#include "settings.h"
-
-/* MD5 context. */
-typedef struct {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-} li_MD5_CTX;
-
-LI_API void li_MD5_Init (li_MD5_CTX *);
-LI_API void li_MD5_Update (li_MD5_CTX *, const unsigned char *, unsigned int);
-LI_API void li_MD5_Final (unsigned char [16], li_MD5_CTX *);
-
-
-
diff --git a/src/mod_access.c b/src/mod_access.c
deleted file mode 100644
index 03eee6da..00000000
--- a/src/mod_access.c
+++ /dev/null
@@ -1,230 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "sys-strings.h"
-
-#define PLUGIN_NAME "access"
-
-#define CONFIG_URL_ACCESS_DENY "url.access-deny"
-#define CONFIG_ACCESS_DENY_ALL PLUGIN_NAME ".deny-all"
-
-typedef struct {
- array *access_deny;
-
- unsigned short deny_all;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-INIT_FUNC(mod_access_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-FREE_FUNC(mod_access_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- array_free(s->access_deny);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_access_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { CONFIG_URL_ACCESS_DENY, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_ACCESS_DENY_ALL, NULL, T_CONFIG_BOOLEAN, 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->access_deny = array_init();
- s->deny_all = 0;
-
- cv[0].destination = s->access_deny;
- cv[1].destination = &(s->deny_all);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(access_deny);
- PATCH_OPTION(deny_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(CONFIG_URL_ACCESS_DENY))) {
- PATCH_OPTION(access_deny);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ACCESS_DENY_ALL))) {
- PATCH_OPTION(deny_all);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_access_uri_handler) {
- plugin_data *p = p_d;
- int s_len;
- size_t k;
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_access_patch_connection(srv, con, p);
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "handling file in mod_access");
- }
-
- s_len = con->uri.path->used - 1;
-
- for (k = 0; k < p->conf.access_deny->used; k++) {
- data_string *ds = (data_string *)p->conf.access_deny->data[k];
- int ct_len = ds->value->used - 1;
-
- if (ct_len > s_len) continue;
- if (ds->value->used == 0) continue;
-
- /* if we have a case-insensitive FS we have to lower-case the URI here too */
-
- if (con->conf.force_lowercase_filenames) {
- if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("access denied, sending %d", con->http_status);
- }
-
- return HANDLER_FINISHED;
- }
- } else {
- if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("access denied for %s as %s matched %d chars, sending %d",
- SAFE_BUF_STR(con->uri.path),
- SAFE_BUF_STR(ds->value),
- ct_len,
- con->http_status);
- }
-
- return HANDLER_FINISHED;
- }
- }
- }
-
- if (p->conf.deny_all) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("access.deny-all triggered, sending %d", con->http_status);
- }
-
- return HANDLER_FINISHED;
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-URIHANDLER_FUNC(mod_access_path_handler) {
- plugin_data *p = p_d;
-
- mod_access_patch_connection(srv, con, p);
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "handling file in mod_access");
- }
-
- if (p->conf.deny_all) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("access denied, sending %d", con->http_status);
- }
-
- return HANDLER_FINISHED;
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_access_plugin_init(plugin *p);
-LI_EXPORT int mod_access_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string(PLUGIN_NAME);
-
- p->init = mod_access_init;
- p->set_defaults = mod_access_set_defaults;
- p->handle_uri_clean = mod_access_uri_handler;
- p->handle_start_backend = mod_access_path_handler;
- p->cleanup = mod_access_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
deleted file mode 100644
index 419fc463..00000000
--- a/src/mod_accesslog.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h> /* only the defines on windows */
-#include <errno.h>
-#include <time.h>
-
-#include <stdio.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "inet_ntop_cache.h"
-
-#include "sys-socket.h"
-#include "sys-files.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_MS,
- 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_RESPONSE_HEADER
- } type;
-} format_mapping;
-
-/**
- *
- *
- * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
- *
- */
-
-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_MS },
- { 'e', FORMAT_ENV },
- { 'f', FORMAT_FILENAME },
- { 'H', FORMAT_REQUEST_PROTOCOL },
- { 'm', FORMAT_REQUEST_METHOD },
- { 'n', FORMAT_UNSUPPORTED }, /* we have no notes */
- { '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 }
-};
-
-
-typedef struct {
- enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
-
- buffer *string;
- int field;
-} format_field;
-
-typedef struct {
- format_field **ptr;
-
- size_t used;
- size_t size;
-} format_fields;
-
-typedef struct {
- buffer *access_logfile;
- buffer *format;
- unsigned short use_syslog;
-
-
- int log_access_fd;
- time_t last_generated_accesslog_ts;
- time_t *last_generated_accesslog_ts_ptr;
-
-
- buffer *access_logbuffer;
- buffer *ts_accesslog_str;
-
- format_fields *parsed_format;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
- plugin_config conf;
-} plugin_data;
-
-INIT_FUNC(mod_accesslog_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-static void accesslog_append_escaped(buffer *dest, buffer *str) {
- /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
- /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
- if (str->used == 0) return;
- buffer_prepare_append(dest, str->used - 1);
-
- for (unsigned int i = 0; i < str->used - 1; i++) {
- if (str->ptr[i] >= ' ' && str->ptr[i] <= '~') {
- /* printable chars */
- buffer_append_string_len(dest, &str->ptr[i], 1);
- } else switch (str->ptr[i]) {
- 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 = str->ptr[i] / 16;
- hh[2] = (h > 9) ? (h - 10 + 'A') : (h + '0');
- h = str->ptr[i] % 16;
- hh[3] = (h > 9) ? (h - 10 + 'A') : (h + '0');
- buffer_append_string_len(dest, &hh[0], 4);
- }
- break;
- }
- }
-}
-
-static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
- size_t i, j, k = 0, start = 0;
-
- for (i = 0; i < format->used - 1; i++) {
-
- switch(format->ptr[i]) {
- case '%':
- 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++;
- }
-
-
- /* 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 '<':
- /* only for s */
-
- 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->used++;
-
- break;
- }
-
- if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
- return -1;
- }
-
- start = i + 3;
-
- break;
- case '{':
- /* go forward to } */
-
- for (k = i+2; k < format->used - 1; k++) {
- if (format->ptr[k] == '}') break;
- }
-
- if (k == format->used - 1) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
- return -1;
- }
- if (format->ptr[k+1] == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
- 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();
-
- buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
-
- fields->used++;
-
- break;
- }
-
- if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
- return -1;
- }
-
- start = k + 2;
-
- break;
- default:
- 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->used++;
-
- break;
- }
-
- if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
- return -1;
- }
-
- start = i + 2;
-
- 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 (!s) continue;
-
- if (s->access_logbuffer->used) {
- if (s->use_syslog) {
-# ifdef HAVE_SYSLOG_H
- if (s->access_logbuffer->used > 2) {
- syslog(LOG_INFO, "%*s", (int) s->access_logbuffer->used - 2, s->access_logbuffer->ptr);
- }
-# endif
- } else if (s->log_access_fd != -1) {
- write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
- }
- }
-
- if (s->log_access_fd != -1) close(s->log_access_fd);
-
- buffer_free(s->ts_accesslog_str);
- buffer_free(s->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);
- }
-
- 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 },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->access_logfile = buffer_init();
- s->format = buffer_init();
- s->access_logbuffer = buffer_init();
- s->ts_accesslog_str = buffer_init();
- s->log_access_fd = -1;
- s->last_generated_accesslog_ts = 0;
- s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
-
-
- cv[0].destination = s->access_logfile;
- cv[1].destination = &(s->use_syslog);
- cv[2].destination = s->format;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (i == 0 && buffer_is_empty(s->format)) {
- /* set a default logfile string */
-
- buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));
- }
-
- /* parse */
-
- if (s->format->used) {
- 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;
- }
-#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_is_empty(s->access_logfile)) continue;
-
- if (s->access_logfile->ptr[0] == '|') {
-#ifdef HAVE_FORK
- /* create write pipe and spawn process */
-
- int to_log_fds[2];
- pid_t pid;
-
- if (pipe(to_log_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
- return HANDLER_ERROR;
- }
-
- /* fork, execve */
- switch (pid = fork()) {
- case 0:
- /* child */
-
- close(STDIN_FILENO);
- dup2(to_log_fds[0], STDIN_FILENO);
- close(to_log_fds[0]);
- /* not needed */
- close(to_log_fds[1]);
-
- /* we don't need the client socket */
- for (i = 3; i < 256; i++) {
- close(i);
- }
-
- /* exec the log-process (skip the | )
- *
- */
-
- execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, (char *)NULL);
-
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "spawning log-process failed: ", strerror(errno),
- s->access_logfile->ptr + 1);
-
- exit(-1);
- break;
- case -1:
- /* error */
- log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
- break;
- default:
- close(to_log_fds[0]);
-
- s->log_access_fd = to_log_fds[1];
-
- break;
- }
-#else
- return -1;
-#endif
- } else if (-1 == (s->log_access_fd =
- open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
-
- log_error_write(srv, __FILE__, __LINE__, "ssb",
- "opening access-log failed:",
- strerror(errno), s->access_logfile);
-
- return HANDLER_ERROR;
- }
-#ifndef _WIN32
- fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
-#endif
- }
-
- 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;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (s->access_logbuffer->used) {
- if (s->use_syslog) {
-#ifdef HAVE_SYSLOG_H
- if (s->access_logbuffer->used > 2) {
- /* syslog appends a \n on its own */
- syslog(LOG_INFO, "%*s", (int) s->access_logbuffer->used - 2, s->access_logbuffer->ptr);
- }
-#endif
- } else if (s->log_access_fd != -1) {
- write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
- }
-
- buffer_reset(s->access_logbuffer);
- }
-
- if (s->use_syslog == 0 &&
- !buffer_is_empty(s->access_logfile) &&
- s->access_logfile->ptr[0] != '|') {
-
- close(s->log_access_fd);
-
- if (-1 == (s->log_access_fd =
- open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
-
- log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
-
- return HANDLER_ERROR;
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(access_logfile);
- PATCH_OPTION(format);
- PATCH_OPTION(log_access_fd);
- PATCH_OPTION(last_generated_accesslog_ts_ptr);
- PATCH_OPTION(access_logbuffer);
- PATCH_OPTION(ts_accesslog_str);
- PATCH_OPTION(parsed_format);
- PATCH_OPTION(use_syslog);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
- PATCH_OPTION(access_logfile);
- PATCH_OPTION(log_access_fd);
- PATCH_OPTION(last_generated_accesslog_ts_ptr);
- PATCH_OPTION(access_logbuffer);
- PATCH_OPTION(ts_accesslog_str);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
- PATCH_OPTION(format);
- PATCH_OPTION(parsed_format);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
- PATCH_OPTION(use_syslog);
- }
- }
- }
-
- return 0;
-}
-
-REQUESTDONE_FUNC(log_access_write) {
- plugin_data *p = p_d;
- buffer *b;
- size_t j;
-
- int newts = 0;
- data_string *ds;
-
- mod_accesslog_patch_connection(srv, con, p);
-
- b = p->conf.access_logbuffer;
- if (b->used == 0) {
- buffer_copy_string_len(b, CONST_STR_LEN(""));
- }
-
- for (j = 0; j < p->conf.parsed_format->used; j++) {
- switch(p->conf.parsed_format->ptr[j]->type) {
- case FIELD_STRING:
- buffer_append_string_buffer(b, p->conf.parsed_format->ptr[j]->string);
- break;
- case FIELD_FORMAT:
- switch(p->conf.parsed_format->ptr[j]->field) {
- case FORMAT_TIMESTAMP:
-
- /* cache the generated timestamp */
- if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
- struct tm tm;
-#if defined(HAVE_STRUCT_TM_GMTOFF)
- long scd, hrs, min;
-#endif
-
- buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
-#if defined(HAVE_STRUCT_TM_GMTOFF)
-# ifdef HAVE_LOCALTIME_R
- localtime_r(&(srv->cur_ts), &tm);
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", &tm);
-# else
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime(&(srv->cur_ts)));
-# endif
- p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
-
- buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
-
- scd = abs(tm.tm_gmtoff);
- hrs = scd / 3600;
- min = (scd % 3600) / 60;
-
- /* hours */
- if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
- buffer_append_long(p->conf.ts_accesslog_str, hrs);
-
- if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
- buffer_append_long(p->conf.ts_accesslog_str, min);
- buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));
-#else
-#ifdef HAVE_GMTIME_R
- gmtime_r(&(srv->cur_ts), &tm);
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S +0000]", &tm);
-#else
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S +0000]", gmtime(&(srv->cur_ts)));
-#endif
- p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
-#endif
-
- *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
- newts = 1;
- }
-
- buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
-
- break;
- case FORMAT_REMOTE_HOST:
-
- /* handle inet_ntop cache */
-
- buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
- break;
- case FORMAT_REMOTE_IDENT:
- /* ident */
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- break;
- case FORMAT_REMOTE_USER:
- if (con->authed_user->used > 1) {
- buffer_append_string_buffer(b, con->authed_user);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_REQUEST_LINE:
- buffer_append_string(b, get_http_method_name(con->request.http_method));
- buffer_append_string_len(b, CONST_STR_LEN(" "));
- accesslog_append_escaped(b, con->request.orig_uri);
- buffer_append_string_len(b, CONST_STR_LEN(" "));
- buffer_append_string(b, get_http_version_name(con->request.http_version));
-
- break;
- case FORMAT_STATUS:
- buffer_append_long(b, con->http_status);
- break;
-
- case FORMAT_BYTES_OUT_NO_HEADER:
- if (con->bytes_written > 0) {
- buffer_append_off_t(b,
- 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 != (ds = (data_string *)array_get_element(con->request.headers, CONST_BUF_LEN(p->conf.parsed_format->ptr[j]->string)))) {
- accesslog_append_escaped(b, ds->value);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_RESPONSE_HEADER:
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, CONST_BUF_LEN(p->conf.parsed_format->ptr[j]->string)))) {
- accesslog_append_escaped(b, ds->value);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_ENV:
- if (NULL != (ds = (data_string *)array_get_element(con->environment, CONST_BUF_LEN(p->conf.parsed_format->ptr[j]->string)))) {
- accesslog_append_escaped(b, ds->value);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_FILENAME:
- if (con->physical.path->used > 1) {
- buffer_append_string_buffer(b, con->physical.path);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_BYTES_OUT:
- if (con->bytes_written > 0) {
- buffer_append_off_t(b, con->bytes_written);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_BYTES_IN:
- if (con->bytes_read > 0) {
- buffer_append_off_t(b, con->bytes_read);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_TIME_USED:
- buffer_append_long(b, srv->cur_ts - con->request_start);
- break;
- case FORMAT_SERVER_NAME:
- if (con->server_name->used > 1) {
- buffer_append_string_buffer(b, con->server_name);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_HTTP_HOST:
- if (con->uri.authority->used > 1) {
- accesslog_append_escaped(b, con->uri.authority);
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- }
- break;
- case FORMAT_REQUEST_PROTOCOL:
- buffer_append_string(b,
- con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
- break;
- case FORMAT_REQUEST_METHOD:
- buffer_append_string(b, get_http_method_name(con->request.http_method));
- break;
- case FORMAT_SERVER_PORT:
- buffer_append_long(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:
- switch(con->keep_alive) {
- case 0: buffer_append_string_len(b, CONST_STR_LEN("-")); break;
- default: buffer_append_string_len(b, CONST_STR_LEN("+")); break;
- }
- break;
- default:
- /*
- { 'a', FORMAT_REMOTE_ADDR },
- { 'A', FORMAT_LOCAL_ADDR },
- { 'C', FORMAT_COOKIE },
- { 'D', FORMAT_TIME_USED_MS },
- */
-
- break;
- }
- break;
- default:
- break;
- }
- }
-
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- if (p->conf.use_syslog || /* syslog doesn't cache */
- (p->conf.access_logfile->used && p->conf.access_logfile->ptr[0] != '|') || /* pipes don't cache */
- newts ||
- b->used > BUFFER_MAX_REUSE_SIZE) {
- if (p->conf.use_syslog) {
-#ifdef HAVE_SYSLOG_H
- if (b->used > 2) {
- /* syslog appends a \n on its own */
- syslog(LOG_INFO, "%*s", (int) b->used - 2, b->ptr);
- }
-#endif
- } else if (p->conf.log_access_fd != -1) {
- write(p->conf.log_access_fd, b->ptr, b->used - 1);
- }
- buffer_reset(b);
- }
-
- return HANDLER_GO_ON;
-}
-
-
-LI_EXPORT int mod_accesslog_plugin_init(plugin *p);
-LI_EXPORT 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_response_done = log_access_write;
- p->handle_sighup = log_access_cycle;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_alias.c b/src/mod_alias.c
deleted file mode 100644
index c03fb7cb..00000000
--- a/src/mod_alias.c
+++ /dev/null
@@ -1,204 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-#include "sys-strings.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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
-
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_alias_free) {
- plugin_data *p = p_d;
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->alias);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; 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, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- if (s->alias->used >= 2) {
- const array *a = s->alias;
- size_t j, k;
-
- for (j = 0; j < a->used; j ++) {
- const buffer *prefix = a->data[a->sorted[j]]->key;
- for (k = j + 1; k < a->used; k ++) {
- const buffer *key = a->data[a->sorted[k]]->key;
-
- if (key->used < prefix->used) {
- break;
- }
- if (memcmp(key->ptr, prefix->ptr, prefix->used - 1) != 0) {
- break;
- }
- /* ok, they have same prefix. check position */
- if (a->sorted[j] < a->sorted[k]) {
- fprintf(stderr, "url.alias: `%s' will never match as `%s' matched first\n",
- key->ptr,
- prefix->ptr);
- return HANDLER_ERROR;
- }
- }
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(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_OPTION(alias);
- }
- }
- }
-
- return 0;
-}
-
-PHYSICALPATH_FUNC(mod_alias_physical_handler) {
- plugin_data *p = p_d;
- int uri_len, basedir_len;
- char *uri_ptr;
- size_t k;
-
- if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
- mod_alias_patch_connection(srv, con, p);
-
- /* not to include the tailing slash */
- basedir_len = (con->physical.basedir->used - 1) - 1;
- uri_len = con->physical.path->used - 1 - basedir_len;
- uri_ptr = con->physical.path->ptr + basedir_len;
-
- for (k = 0; k < p->conf.alias->used; k++) {
- data_string *ds = (data_string *)p->conf.alias->data[k];
- int alias_len = ds->key->used - 1;
-
- if (alias_len > uri_len) continue;
- if (ds->key->used == 0) continue;
-
- if (0 == (con->conf.force_lowercase_filenames ?
- strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
- strncmp(uri_ptr, ds->key->ptr, alias_len))) {
- /* matched */
-
- buffer_copy_string_buffer(con->physical.basedir, ds->value);
- buffer_copy_string_buffer(srv->tmp_buf, ds->value);
- buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
- buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
-
- return HANDLER_GO_ON;
- }
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_alias_plugin_init(plugin *p);
-LI_EXPORT int mod_alias_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("alias");
-
- p->init = mod_alias_init;
- p->handle_physical= mod_alias_physical_handler;
- p->set_defaults = mod_alias_set_defaults;
- p->cleanup = mod_alias_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_auth.c b/src/mod_auth.c
deleted file mode 100644
index 5b8307cc..00000000
--- a/src/mod_auth.c
+++ /dev/null
@@ -1,672 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "settings.h"
-#include "plugin.h"
-#include "http_auth.h"
-#include "log.h"
-#include "response.h"
-
-#include "sys-strings.h"
-#include "sys-files.h"
-
-handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
-#ifdef USE_LDAP
-void auth_ldap_cleanup(ldap_plugin_config* p);
-#endif
-
-/**
- * the basic and digest auth framework
- *
- * - config handling
- * - protocol handling
- *
- * http_auth.c
- * http_auth_digest.c
- *
- * do the real work
- */
-
-INIT_FUNC(mod_auth_init) {
- mod_auth_plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- p->auth_user = buffer_init();
-#ifdef USE_LDAP
- p->ldap_filter = buffer_init();
-#endif
-
- return p;
-}
-
-FREE_FUNC(mod_auth_free) {
- mod_auth_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->tmp_buf);
- buffer_free(p->auth_user);
-#ifdef USE_LDAP
- buffer_free(p->ldap_filter);
-#endif
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- mod_auth_plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->auth_require);
- buffer_free(s->auth_plain_groupfile);
- buffer_free(s->auth_plain_userfile);
- buffer_free(s->auth_htdigest_userfile);
- buffer_free(s->auth_htpasswd_userfile);
- buffer_free(s->auth_backend_conf);
-
- buffer_free(s->auth_ldap_url);
- 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_cert);
- buffer_free(s->auth_ldap_key);
-
-#ifdef USE_LDAP
- buffer_free(s->ldap->ldap_filter_pre);
- buffer_free(s->ldap->ldap_filter_post);
-
- auth_ldap_cleanup(s->ldap);
- free(s->ldap);
-#endif
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
- size_t i, j;
- mod_auth_plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(auth_backend);
- PATCH_OPTION(auth_plain_groupfile);
- PATCH_OPTION(auth_plain_userfile);
- PATCH_OPTION(auth_htdigest_userfile);
- PATCH_OPTION(auth_htpasswd_userfile);
- PATCH_OPTION(auth_require);
- PATCH_OPTION(auth_debug);
- PATCH_OPTION(auth_ldap_url);
- PATCH_OPTION(auth_ldap_basedn);
- PATCH_OPTION(auth_ldap_binddn);
- PATCH_OPTION(auth_ldap_bindpw);
- PATCH_OPTION(auth_ldap_filter);
- PATCH_OPTION(auth_ldap_cafile);
- PATCH_OPTION(auth_ldap_cert);
- PATCH_OPTION(auth_ldap_key);
- PATCH_OPTION(auth_ldap_starttls);
- PATCH_OPTION(auth_ldap_allow_empty_pw);
-#ifdef USE_LDAP
- PATCH_OPTION(ldap);
-#endif
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
- PATCH_OPTION(auth_backend);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
- PATCH_OPTION(auth_plain_groupfile);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
- PATCH_OPTION(auth_plain_userfile);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
- PATCH_OPTION(auth_htdigest_userfile);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
- PATCH_OPTION(auth_htpasswd_userfile);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
- PATCH_OPTION(auth_require);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
- PATCH_OPTION(auth_debug);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.url"))) {
- PATCH_OPTION(auth_ldap_url);
-#ifdef USE_LDAP
- PATCH_OPTION(ldap);
-#endif
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
- PATCH_OPTION(auth_ldap_basedn);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-dn"))) {
- PATCH_OPTION(auth_ldap_binddn);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-pw"))) {
- PATCH_OPTION(auth_ldap_bindpw);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
- PATCH_OPTION(auth_ldap_filter);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
- PATCH_OPTION(auth_ldap_cafile);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.cert"))) {
- PATCH_OPTION(auth_ldap_cert);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.key"))) {
- PATCH_OPTION(auth_ldap_key);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
- PATCH_OPTION(auth_ldap_starttls);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) {
- PATCH_OPTION(auth_ldap_allow_empty_pw);
- }
- }
- }
-
- return 0;
-}
-
-static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
- size_t k;
- int auth_required = 0, auth_satisfied = 0;
- char *http_authorization = NULL;
- data_string *ds;
- mod_auth_plugin_data *p = p_d;
- array *req;
-
- /* select the right config */
- mod_auth_patch_connection(srv, con, p);
-
- if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
-
- /*
- * AUTH
- *
- */
-
- /* do we have to ask for auth ? */
-
- auth_required = 0;
- auth_satisfied = 0;
-
- /* search auth-directives for path */
- for (k = 0; k < p->conf.auth_require->used; k++) {
- buffer *auth_path = p->conf.auth_require->data[k]->key;
-
- if (auth_path->used == 0) continue;
- if (con->uri.path->used < auth_path->used) continue;
-
- /* if we have a case-insensitive FS we have to lower-case the URI here too */
-
- if (con->conf.force_lowercase_filenames) {
- if (0 == strncasecmp(con->uri.path->ptr, auth_path->ptr, auth_path->used - 1)) {
- auth_required = 1;
- break;
- }
- } else {
- if (0 == strncmp(con->uri.path->ptr, auth_path->ptr, auth_path->used - 1)) {
- auth_required = 1;
- break;
- }
- }
- }
-
- /* nothing to do for us */
- if (auth_required == 0) return HANDLER_GO_ON;
-
- req = ((data_array *)(p->conf.auth_require->data[k]))->value;
-
- /* try to get Authorization-header */
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Authorization")))) {
- http_authorization = ds->value->ptr;
- }
-
- if (ds && ds->value && ds->value->used) {
- char *auth_realm;
- data_string *method;
-
- method = (data_string *)array_get_element(req, CONST_STR_LEN("method"));
-
- /* parse auth-header */
- if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
- int auth_type_len = auth_realm - http_authorization;
-
- if ((auth_type_len == 5) &&
- (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
-
- if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
- auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
- }
- } else if ((auth_type_len == 6) &&
- (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
- if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
- if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
- con->http_status = 400;
-
- /* a field was missing */
-
- return HANDLER_FINISHED;
- }
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "unknown authentification type:",
- http_authorization);
- }
- }
- }
-
- if (!auth_satisfied) {
- data_string *method, *realm;
- method = (data_string *)array_get_element(req, CONST_STR_LEN("method"));
- realm = (data_string *)array_get_element(req, CONST_STR_LEN("realm"));
-
- con->http_status = 401;
-
- if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Basic realm=\""));
- buffer_append_string_buffer(p->tmp_buf, realm->value);
- buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\""));
-
- response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
- } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
- char hh[33];
- http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
-
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Digest realm=\""));
- buffer_append_string_buffer(p->tmp_buf, realm->value);
- buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", nonce=\""));
- buffer_append_string(p->tmp_buf, hh);
- buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", qop=\"auth\""));
-
- response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
- } else {
- /* evil */
- }
- return HANDLER_FINISHED;
- } else {
- /* the REMOTE_USER header */
-
- buffer_copy_string_buffer(con->authed_user, p->auth_user);
- }
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_auth_set_defaults) {
- mod_auth_plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "auth.backend.ldap.url" , NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { "auth.backend.ldap.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { "auth.backend.ldap.cert", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { "auth.backend.ldap.key", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
- { "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
- { "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
- { "auth.backend.ldap.bind-pw", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
- { "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
- { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
- { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
- { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- mod_auth_plugin_config *s;
- size_t n;
- data_array *da;
- array *ca;
-
- s = calloc(1, sizeof(mod_auth_plugin_config));
- s->auth_plain_groupfile = buffer_init();
- s->auth_plain_userfile = buffer_init();
- s->auth_htdigest_userfile = buffer_init();
- s->auth_htpasswd_userfile = buffer_init();
- s->auth_backend_conf = buffer_init();
-
- s->auth_ldap_url = 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_cert = buffer_init();
- s->auth_ldap_key = buffer_init();
- s->auth_ldap_starttls = 0;
- s->auth_debug = 0;
-
- s->auth_require = array_init();
-
-#ifdef USE_LDAP
- s->ldap = malloc (sizeof(ldap_plugin_config));
- s->ldap->ldap_filter_pre = buffer_init();
- s->ldap->ldap_filter_post = buffer_init();
- s->ldap->ldap = NULL;
-#endif
-
- cv[0].destination = s->auth_backend_conf;
- cv[1].destination = s->auth_plain_groupfile;
- cv[2].destination = s->auth_plain_userfile;
- cv[3].destination = s->auth_require;
- cv[4].destination = s->auth_ldap_url;
- cv[5].destination = s->auth_ldap_basedn;
- cv[6].destination = s->auth_ldap_filter;
- cv[7].destination = s->auth_ldap_cafile;
- cv[8].destination = s->auth_ldap_cert;
- cv[9].destination = s->auth_ldap_key;
- cv[10].destination = &(s->auth_ldap_starttls);
- cv[11].destination = s->auth_ldap_binddn;
- cv[12].destination = s->auth_ldap_bindpw;
- cv[13].destination = &(s->auth_ldap_allow_empty_pw);
- cv[14].destination = s->auth_htdigest_userfile;
- cv[15].destination = s->auth_htpasswd_userfile;
- cv[16].destination = &(s->auth_debug);
-
- p->config_storage[i] = s;
- ca = ((data_config *)srv->config_context->data[i])->value;
-
- if (0 != config_insert_values_global(srv, ca, cv)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_is_empty(s->auth_backend_conf)) {
- if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
- s->auth_backend = AUTH_BACKEND_HTPASSWD;
- } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
- s->auth_backend = AUTH_BACKEND_HTDIGEST;
- } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
- s->auth_backend = AUTH_BACKEND_PLAIN;
- } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
- s->auth_backend = AUTH_BACKEND_LDAP;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
-
- return HANDLER_ERROR;
- }
- }
-
- /* no auth.require for this section */
- if (NULL == (da = (data_array *)array_get_element(ca, CONST_STR_LEN("auth.require")))) continue;
-
- if (da->type != TYPE_ARRAY) continue;
-
- for (n = 0; n < da->value->used; n++) {
- size_t m;
- data_array *da_file = (data_array *)da->value->data[n];
- buffer *method, *realm, *require;
-
- if (da->value->data[n]->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "auth.require should contain an array as in:",
- "auth.require = ( \"...\" => ( ..., ...) )");
-
- return HANDLER_ERROR;
- }
-
- method = realm = require = NULL;
-
- for (m = 0; m < da_file->value->used; m++) {
- data_string *ds_auth_req = (data_string *)da_file->value->data[m];
-
- if (ds_auth_req->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "ssbs",
- "a string was expected for:",
- "auth.require = ( \"...\" => ( ..., -> \"",
- ds_auth_req->key,
- "\" <- => \"...\" ) )");
-
- return HANDLER_ERROR;
- }
-
- if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
- method = ds_auth_req->value;
- } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
- realm = ds_auth_req->value;
- } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
- require = ds_auth_req->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;
-
- }
- }
-
- if (method == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "the require field is missing in:",
- "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
- return HANDLER_ERROR;
- }
- if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
- !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "method has to be either \"basic\" or \"digest\" in",
- "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
- return HANDLER_ERROR;
- }
-
- if (realm == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "the require field is missing in:",
- "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
- return HANDLER_ERROR;
- }
-
- if (require == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "the require field is missing in:",
- "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
- return HANDLER_ERROR;
- }
-
- if (method && realm && require) {
- data_string *ds;
- data_array *a;
-
- a = data_array_init();
- buffer_copy_string_buffer(a->key, da_file->key);
-
- ds = data_string_init();
-
- buffer_copy_string_len(ds->key, CONST_STR_LEN("method"));
- buffer_copy_string_buffer(ds->value, method);
-
- array_insert_unique(a->value, (data_unset *)ds);
-
- ds = data_string_init();
-
- buffer_copy_string_len(ds->key, CONST_STR_LEN("realm"));
- buffer_copy_string_buffer(ds->value, realm);
-
- array_insert_unique(a->value, (data_unset *)ds);
-
- ds = data_string_init();
-
- buffer_copy_string_len(ds->key, CONST_STR_LEN("require"));
- buffer_copy_string_buffer(ds->value, require);
-
- array_insert_unique(a->value, (data_unset *)ds);
-
- array_insert_unique(s->auth_require, (data_unset *)a);
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
-#ifdef USE_LDAP
- int ret;
- struct berval credentials;
- char *binddn_ptr = NULL;
-
- if (s->auth_ldap_filter->used) {
- char *dollar;
-
- /* parse filter */
-
- if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
-
- return HANDLER_ERROR;
- }
-
- buffer_copy_string_len(s->ldap->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
- buffer_copy_string(s->ldap->ldap_filter_post, dollar+1);
- }
-
- if (s->auth_ldap_url->used) {
- if ((ret = ldap_initialize(&s->ldap->ldap, s->auth_ldap_url->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- return HANDLER_ERROR;
- }
-
- {
- const int ldap_version = LDAP_VERSION3;
- ret = ldap_set_option(s->ldap->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
- }
- if (ret != LDAP_OPT_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_memfree(s->ldap->ldap);
- s->ldap->ldap = NULL;
-
- return HANDLER_ERROR;
- }
-
- if (s->auth_ldap_starttls == 1) {
- /* if no CA file is given, it is ok, as we will use encryption
- * if the server requires a CAfile it will tell us */
- if (!buffer_is_empty(s->auth_ldap_cafile)) {
- if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
- s->auth_ldap_cafile->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "Loading CA certificate failed:", ldap_err2string(ret));
-
- ldap_memfree(s->ldap->ldap);
- s->ldap->ldap = NULL;
-
- return HANDLER_ERROR;
- }
- }
-
- if (!buffer_is_empty(s->auth_ldap_cert)) {
- if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE,
- s->auth_ldap_cert->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "Loading TLS certificate failed:", ldap_err2string(ret));
-
- ldap_memfree(s->ldap->ldap);
- s->ldap->ldap = NULL;
-
- return HANDLER_ERROR;
- }
- }
-
- if (!buffer_is_empty(s->auth_ldap_key)) {
- if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE,
- s->auth_ldap_key->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "Loading TLS key certificate failed:", ldap_err2string(ret));
-
- ldap_memfree(s->ldap->ldap);
- s->ldap->ldap = NULL;
-
- return HANDLER_ERROR;
- }
- }
-
- if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap->ldap, NULL, NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
-
- ldap_memfree(s->ldap->ldap);
- s->ldap->ldap = NULL;
-
- return HANDLER_ERROR;
- }
- }
-
-
- /* 1. */
- if (s->auth_ldap_binddn->used) {
- credentials.bv_val = s->auth_ldap_bindpw->ptr;
- credentials.bv_len = s->auth_ldap_bindpw->used;
- binddn_ptr = s->auth_ldap_binddn->ptr;
- } else {
- credentials.bv_val = NULL;
- credentials.bv_len = 0;
- binddn_ptr = NULL;
- }
- ret = ldap_sasl_bind_s(s->ldap->ldap, s->auth_ldap_binddn->ptr, LDAP_SASL_SIMPLE, &credentials, NULL, NULL, NULL);
- if(ret != LDAP_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- ldap_memfree(s->ldap->ldap);
- s->ldap->ldap = NULL;
- return HANDLER_ERROR;
- }
- }
-#else
- UNUSED(s);
- log_error_write(srv, __FILE__, __LINE__, "s", "no ldap support available");
- return HANDLER_ERROR;
-#endif
- return HANDLER_GO_ON;
-}
-
-#ifdef USE_LDAP
-void auth_ldap_cleanup(ldap_plugin_config *p) {
- if (p->ldap != NULL)
- ldap_unbind_ext_s(p->ldap, NULL, NULL);
- p->ldap = NULL;
-}
-#endif
-
-LI_EXPORT int mod_auth_plugin_init(plugin *p);
-LI_EXPORT 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;
-}
diff --git a/src/mod_auth.h b/src/mod_auth.h
deleted file mode 100644
index e69de29b..00000000
--- a/src/mod_auth.h
+++ /dev/null
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
deleted file mode 100644
index 5e02826a..00000000
--- a/src/mod_cgi.c
+++ /dev/null
@@ -1,1312 +0,0 @@
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include <stdio.h>
-#include <fcntl.h>
-
-#include "server.h"
-#include "stat_cache.h"
-#include "keyvalue.h"
-#include "log.h"
-#include "connections.h"
-#include "joblist.h"
-#include "fdevent.h"
-#include "inet_ntop_cache.h"
-
-#include "plugin.h"
-#include "http_resp.h"
-
-#include "sys-files.h"
-#include "sys-mmap.h"
-#include "sys-socket.h"
-#include "sys-strings.h"
-#include "sys-process.h"
-
-#include "network_backends.h"
-
-#ifdef HAVE_SYS_FILIO_H
-# include <sys/filio.h>
-#endif
-
-enum {EOL_UNSET, EOL_N, EOL_RN};
-
-typedef struct {
- char **ptr;
-
- size_t size;
- size_t used;
-} char_array;
-
-#define pid_t int
-typedef struct {
- pid_t *ptr;
- size_t used;
- size_t size;
-} buffer_pid_t;
-
-typedef struct {
- array *cgi;
- unsigned short execute_all;
- unsigned short execute_x_only;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
- buffer_pid_t cgi_pid;
-
- buffer *tmp_buf;
-
- http_resp *resp;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-typedef enum {
- CGI_STATE_UNSET,
- CGI_STATE_CONNECTING,
- CGI_STATE_READ_RESPONSE_HEADER,
- CGI_STATE_READ_RESPONSE_CONTENT
-} cgi_state_t;
-
-typedef struct {
- pid_t pid;
-
- iosocket *sock;
- iosocket *sock_err;
- iosocket *wb_sock;
-
- chunkqueue *rb;
- chunkqueue *rb_err;
- chunkqueue *wb;
-
- cgi_state_t state;
-
- connection *remote_con; /* dumb pointer */
-} cgi_session;
-
-static cgi_session * cgi_session_init() {
- cgi_session *sess = calloc(1, sizeof(*sess));
- assert(sess);
-
- sess->sock = iosocket_init();
- sess->sock_err = iosocket_init();
- sess->wb_sock = iosocket_init();
- sess->wb = chunkqueue_init();
- sess->rb = chunkqueue_init();
- sess->rb_err = chunkqueue_init();
-
- return sess;
-}
-
-static void cgi_session_free(cgi_session *sess) {
- if (!sess) return;
-
- iosocket_free(sess->sock);
- iosocket_free(sess->sock_err);
- iosocket_free(sess->wb_sock);
-
- chunkqueue_free(sess->wb);
- chunkqueue_free(sess->rb);
- chunkqueue_free(sess->rb_err);
-
- free(sess);
-}
-
-INIT_FUNC(mod_cgi_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- assert(p);
-
- p->tmp_buf = buffer_init();
- p->resp = http_response_init();
-
- 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];
-
- array_free(s->cgi);
-
- free(s);
- }
- free(p->config_storage);
- }
-
-
- if (r->ptr) free(r->ptr);
-
- buffer_free(p->tmp_buf);
- http_response_free(p->resp);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-#define PLUGIN_NAME "cgi"
-#define CONFIG_ASSIGN PLUGIN_NAME ".assign"
-#define CONFIG_EXECUTE_ALL PLUGIN_NAME ".execute-all"
-#define CONFIG_EXECUTE_X_ONLY PLUGIN_NAME ".execute-x-only"
-
-SETDEFAULTS_FUNC(mod_cgi_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { CONFIG_ASSIGN, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { CONFIG_EXECUTE_ALL, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { CONFIG_EXECUTE_X_ONLY, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- assert(s);
-
- s->cgi = array_init();
- s->execute_all = 0;
- s->execute_x_only = 0;
-
- cv[0].destination = s->cgi;
- cv[1].destination = &(s->execute_all);
- cv[2].destination = &(s->execute_x_only);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-
-static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {
- int m = -1;
- size_t i;
- buffer_pid_t *r = &(p->cgi_pid);
-
- UNUSED(srv);
-
- for (i = 0; i < r->used; i++) {
- if (r->ptr[i] > m) m = r->ptr[i];
- }
-
- if (r->size == 0) {
- r->size = 16;
- r->ptr = malloc(sizeof(*r->ptr) * r->size);
- } else if (r->used == r->size) {
- r->size += 16;
- r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
- }
-
- r->ptr[r->used++] = pid;
-
- return m;
-}
-
-static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
- size_t i;
- buffer_pid_t *r = &(p->cgi_pid);
-
- UNUSED(srv);
-
- for (i = 0; i < r->used; i++) {
- if (r->ptr[i] == pid) break;
- }
-
- if (i != r->used) {
- /* found */
-
- if (i != r->used - 1) {
- r->ptr[i] = r->ptr[r->used - 1];
- }
- r->used--;
- }
-
- return 0;
-}
-
-/**
- * Copy decoded response content to client connection.
- */
-static int cgi_copy_response(server *srv, connection *con, cgi_session *sess) {
- chunk *c;
- int we_have = 0;
-
- UNUSED(srv);
-
- chunkqueue_remove_finished_chunks(sess->rb);
- /* copy the content to the next cq */
- for (c = sess->rb->first; c; c = c->next) {
- if (c->mem->used == 0) continue;
-
- we_have = chunkqueue_steal_chunk(con->send, c);
- sess->rb->bytes_out += we_have;
- con->send->bytes_in += we_have;
- }
- chunkqueue_remove_finished_chunks(sess->rb);
-
- if(sess->rb->is_closed) {
- con->send->is_closed = 1;
- }
- return 0;
-}
-
-
-static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
- cgi_session *sess = con->plugin_ctx[p->id];
-
- switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
- case NETWORK_STATUS_CONNECTION_CLOSE:
- fdevent_event_del(srv->ev, sess->sock);
-
- /* connection closed. close the read chunkqueue. */
- sess->rb->is_closed = 1;
- case NETWORK_STATUS_SUCCESS:
- /* we got content */
- break;
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- return 0;
- default:
- /* oops */
- ERROR("%s", "oops, read-pipe-read failed and I don't know why");
- return -1;
- }
-
- /* looks like we got some content
- *
- * split off the header from the incoming stream
- */
-
- if (con->file_started == 0) {
- size_t i;
- int have_content_length = 0;
-
- http_response_reset(p->resp);
-
- /* the response header is not fully received yet,
- *
- * extract the http-response header from the rb-cq
- */
- switch (http_response_parse_cq(sess->rb, p->resp)) {
- case PARSE_UNSET:
- case PARSE_ERROR:
- /* parsing failed */
-
- TRACE("%s", "response parser failed");
-
- con->http_status = 502; /* Bad Gateway */
- return -1;
- case PARSE_NEED_MORE:
- if (sess->rb->is_closed) {
- /* backend died before sending a header */
- con->http_status = 502; /* Bad Gateway */
- return -1;
- }
- return 0;
- case PARSE_SUCCESS:
- con->http_status = p->resp->status;
-
- chunkqueue_remove_finished_chunks(sess->rb);
-
- /* copy the http-headers */
- for (i = 0; i < p->resp->headers->used; i++) {
- const char *ign[] = { "Status", "Connection", NULL };
- size_t j;
- data_string *ds;
-
- data_string *header = (data_string *)p->resp->headers->data[i];
-
- /* some headers are ignored by default */
- for (j = 0; ign[j]; j++) {
- if (0 == strcasecmp(ign[j], header->key->ptr)) break;
- }
- if (ign[j]) continue;
-
- if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
- /* CGI/1.1 rev 03 - 7.2.1.2 */
- if (con->http_status == 0) con->http_status = 302;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
- have_content_length = 1;
- }
-
- if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
- ds = data_response_init();
- }
- buffer_copy_string_buffer(ds->key, header->key);
- buffer_copy_string_buffer(ds->value, header->value);
-
- array_insert_unique(con->response.headers, (data_unset *)ds);
- }
-
- con->file_started = 1;
- /* if Status: ... is not set, 200 is our default status-code */
- if (con->http_status == 0) con->http_status = 200;
- sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
-
- if (con->request.http_version == HTTP_VERSION_1_1 &&
- !have_content_length) {
- con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
- }
-
- break;
- }
- }
-
- /* FIXME: pass the response-header to the other plugins to
- * setup the filter-queue
- *
- * - use next-queue instead of con->write_queue
- */
-
- /* copy the resopnse content */
- cgi_copy_response(srv, con, sess);
-
- joblist_append(srv, con);
-
- return 0;
-}
-
-static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
- cgi_session *sess = con->plugin_ctx[p->id];
- int status;
- pid_t pid;
-
- if (NULL == sess) return HANDLER_GO_ON;
- if (con->mode != p->id) return HANDLER_GO_ON;
-
-#ifndef _WIN32
-
- /* the connection to the browser went away, but we still have a connection
- * to the CGI script
- *
- * close cgi-connection
- */
-
- if (sess->sock->fd != -1) {
- /* close connection to the cgi-script */
- fdevent_event_del(srv->ev, sess->sock);
- fdevent_unregister(srv->ev, sess->sock);
- }
-
- if (sess->sock_err->fd != -1) {
- /* close connection to the cgi-script */
- fdevent_event_del(srv->ev, sess->sock_err);
- fdevent_unregister(srv->ev, sess->sock_err);
- }
-
- if (sess->wb_sock->fd != -1) {
- close(sess->wb_sock->fd);
- sess->wb_sock->fd = -1;
- }
-
- pid = sess->pid;
-
- con->plugin_ctx[p->id] = NULL;
-
- /* is this a good idea ? */
- cgi_session_free(sess);
- sess = NULL;
-
- /* if waitpid hasn't been called by response.c yet, do it here */
- if (pid) {
- /* check if the CGI-script is already gone */
-#ifndef _WIN32
- switch(waitpid(pid, &status, WNOHANG)) {
- case 0:
- /* not finished yet */
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", pid);
-#endif
- break;
- case -1:
- /* */
- if (errno == EINTR) break;
-
- /*
- * errno == ECHILD happens if _subrequest catches the process-status before
- * we have read the response of the cgi process
- *
- * -> catch status
- * -> WAIT_FOR_EVENT
- * -> read response
- * -> we get here with waitpid == ECHILD
- *
- */
- if (errno == ECHILD) return HANDLER_GO_ON;
-
- log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
- return HANDLER_ERROR;
- default:
- /* Send an error if we haven't sent any data yet */
- if (0 == con->file_started) {
- if (con->http_status == 0) con->http_status = 500;
- con->mode = DIRECT;
- }
-
- if (WIFEXITED(status)) {
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
-#endif
- pid = 0;
-
- return HANDLER_GO_ON;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
- pid = 0;
- return HANDLER_GO_ON;
- }
- }
-
-
- kill(pid, SIGTERM);
-#endif
- /* cgi-script is still alive, queue the PID for removal */
- cgi_pid_add(srv, p, pid);
- }
-#endif
- return HANDLER_GO_ON;
-}
-
-static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
-
- return cgi_connection_close(srv, con, p);
-}
-
-static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
- cgi_session *sess = ctx;
- connection *con = sess->remote_con;
-
- if (revents & FDEVENT_IN) {
- switch (sess->state) {
- case CGI_STATE_READ_RESPONSE_HEADER:
- /* parse the header and set file-started, the demuxer will care about it */
- joblist_append(srv, con);
-
- break;
- case CGI_STATE_READ_RESPONSE_CONTENT:
- /* just forward the content to the out-going queue */
-
- chunkqueue_remove_finished_chunks(sess->rb);
-
- switch (srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
- case NETWORK_STATUS_CONNECTION_CLOSE:
- fdevent_event_del(srv->ev, sess->sock);
-
- /* connection closed. close the read chunkqueue. */
- sess->rb->is_closed = 1;
- case NETWORK_STATUS_SUCCESS:
- /* read even more, do we have all the content */
-
- /* how much do we want to read ? */
-
- /* copy the resopnse content */
- cgi_copy_response(srv, con, sess);
-
- break;
- default:
- ERROR("%s", "oops, we failed to read");
- break;
- }
-
- joblist_append(srv, con);
- break;
- default:
- TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
- break;
- }
- }
-
- if (revents & FDEVENT_OUT) {
- /* nothing to do */
- }
-
- /* perhaps this issue is already handled */
- if (revents & FDEVENT_HUP) {
- con->send->is_closed = 1;
-
- fdevent_event_del(srv->ev, sess->sock);
-
- joblist_append(srv, con);
- } else if (revents & FDEVENT_ERR) {
- con->send->is_closed = 1;
-
- /* kill all connections to the cgi process */
- fdevent_event_del(srv->ev, sess->sock);
- joblist_append(srv, con);
- }
-
- return HANDLER_FINISHED;
-}
-
-/* so all cgi errors have the same source line as origin */
-static void cgi_log_err(const char *msg) {
- ERROR("error from cgi: %s", msg);
-}
-
-static void cgi_copy_err(chunkqueue *cq) {
- buffer *line = buffer_init();
- chunk *c;
-
- for (c = cq->first; c; c = c->next) {
- off_t we_have;
- char *str, *nl;
-
- if (c->type != MEM_CHUNK) {
- ERROR("%s", "wrong chunk type");
- chunk_set_done(c);
- continue;
- }
-
- we_have = c->mem->used - 1 - c->offset;
- str = c->mem->ptr + c->offset;
- if (we_have <= 0) continue;
-
- for ( ; NULL != (nl = strchr(str, '\n')); str = nl+1) {
- *nl = '\0';
- if (!buffer_is_empty(line)) {
- buffer_append_string(line, str);
- cgi_log_err(SAFE_BUF_STR(line));
- buffer_reset(line);
- } else {
- cgi_log_err(str);
- }
- }
- if (*str) {
- buffer_append_string(line, str);
- }
- chunk_set_done(c);
- }
-
- if (!buffer_is_empty(line)) {
- cgi_log_err(SAFE_BUF_STR(line));
- }
- chunkqueue_remove_finished_chunks(cq);
-}
-
-static handler_t cgi_handle_err_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
- cgi_session *sess = ctx;
- connection *con = sess->remote_con;
-
- if (revents & (FDEVENT_IN | FDEVENT_HUP)) {
- switch (srv->network_backend_read(srv, con, sess->sock_err, sess->rb_err)) {
- case NETWORK_STATUS_CONNECTION_CLOSE:
- fdevent_event_del(srv->ev, sess->sock_err);
-
- /* connection closed. close the read chunkqueue. */
- sess->rb_err->is_closed = 1;
- break;
- case NETWORK_STATUS_SUCCESS:
- break;
- default:
- ERROR("%s", "oops, we failed to read");
- break;
- }
-
- cgi_copy_err(sess->rb_err);
- }
-
- if (revents & FDEVENT_ERR) {
- fdevent_event_del(srv->ev, sess->sock_err);
- }
-
- return HANDLER_FINISHED;
-}
-
-
-static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
- char *dst;
-
- if (!key || !val) return -1;
-
- dst = malloc(key_len + val_len + 3);
- 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->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));
- }
-
- env->ptr[env->used++] = dst;
-
- return 0;
-}
-
-static const char *sock_addr_to_p(server *srv, sock_addr *addr) {
- switch (addr->plain.sa_family) {
- case AF_INET:
- return inet_ntoa(addr->ipv4.sin_addr);
-#ifdef HAVE_IPV6
- case AF_INET6:
- return inet_ntop_cache_get_ip(srv, addr);
-#endif
-#ifdef HAVE_SYS_UN_H
- case AF_UNIX:
- return addr->un.sun_path;
-#endif
- }
- return "";
-}
-
-static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
- pid_t pid;
-
- int to_cgi_fds[2];
- int from_cgi_fds[2];
- int from_cgi_err_fds[2];
- struct stat st;
-
-#ifndef _WIN32
-
- if (cgi_handler && cgi_handler->used > 1) {
- /* stat the exec file */
- if (-1 == (stat(cgi_handler->ptr, &st))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "stat for cgi-handler", cgi_handler,
- "failed:", strerror(errno));
- return -1;
- }
- }
-
- if (pipe(to_cgi_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
- return -1;
- }
-
- if (pipe(from_cgi_fds)) {
- close(to_cgi_fds[0]); close(to_cgi_fds[1]);
- log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
- return -1;
- }
-
- if (pipe(from_cgi_err_fds)) {
- close(to_cgi_fds[0]); close(to_cgi_fds[1]);
- close(from_cgi_fds[0]); close(from_cgi_fds[1]);
- log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
- return -1;
- }
-
- /* fork, execve */
- switch (pid = fork()) {
- case 0: {
- /* child */
- char **args;
- int argc;
- int i = 0;
- char buf[32];
- size_t n;
- char_array env;
- char *c;
- const char *s;
- server_socket *srv_sock = con->srv_socket;
-
- /* move stdout to from_cgi_fd[1] */
- close(STDOUT_FILENO);
- dup2(from_cgi_fds[1], STDOUT_FILENO);
- close(from_cgi_fds[1]);
- /* not needed */
- close(from_cgi_fds[0]);
-
- /* move stderr to from_cgi_err_fd[1] */
- close(STDERR_FILENO);
- dup2(from_cgi_err_fds[1], STDERR_FILENO);
- close(from_cgi_err_fds[1]);
- /* not needed */
- close(from_cgi_err_fds[0]);
-
- /* move the stdin to to_cgi_fd[0] */
- close(STDIN_FILENO);
- dup2(to_cgi_fds[0], STDIN_FILENO);
- close(to_cgi_fds[0]);
- /* not needed */
- close(to_cgi_fds[1]);
-
- /* create environment */
- env.ptr = NULL;
- env.size = 0;
- env.used = 0;
-
- cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
-
- s = sock_addr_to_p(srv, &srv_sock->addr);
- cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
- /* !!! careful: s maybe reused for SERVER_NAME !!! */
-
- if (!buffer_is_empty(con->server_name)) {
- size_t len = con->server_name->used - 1;
- char *colon = strchr(con->server_name->ptr, ':');
- if (colon) len = colon - con->server_name->ptr;
-
- cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
- } else {
- /* use SERVER_ADDR */
- cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
- }
- cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
-
- s = get_http_version_name(con->request.http_version);
-
- cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
-
- LI_ltostr(buf, sock_addr_get_port(&srv_sock->addr));
- cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
-
- s = get_http_method_name(con->request.http_method);
- cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
-
- if (!buffer_is_empty(con->request.pathinfo)) {
- cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
- }
- cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
- if (!buffer_is_empty(con->uri.query)) {
- cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
- } else {
- /* set a empty QUERY_STRING */
- cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
- }
- if (!buffer_is_empty(con->request.orig_uri)) {
- cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
- }
-
- s = sock_addr_to_p(srv, &con->dst_addr);
- cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
-
- LI_ltostr(buf, sock_addr_get_port(&con->dst_addr));
- cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
-
- if (!buffer_is_empty(con->authed_user)) {
- cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
- CONST_BUF_LEN(con->authed_user));
- }
-
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
- }
-#endif
-
- /* request.content_length < SSIZE_MAX, see request.c */
- if (con->request.content_length > 0) {
- LI_ltostr(buf, con->request.content_length);
- cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
- }
- cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
- cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
- cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
-
- /* for valgrind */
- if (NULL != (s = getenv("LD_PRELOAD"))) {
- cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
- }
-
- if (NULL != (s = getenv("LD_LIBRARY_PATH"))) {
- cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), s, strlen(s));
- }
-#ifdef __CYGWIN__
- /* CYGWIN needs SYSTEMROOT */
- if (NULL != (s = getenv("SYSTEMROOT"))) {
- cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
- }
-#endif
-
- for (n = 0; n < con->request.headers->used; n++) {
- data_string *ds;
-
- ds = (data_string *)con->request.headers->data[n];
-
- if (ds->value->used && ds->key->used) {
- size_t j;
-
- buffer_reset(p->tmp_buf);
-
- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_"));
- p->tmp_buf->used--; /* strip \0 after HTTP_ */
- }
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
-
- for (j = 0; j < ds->key->used - 1; j++) {
- char cr = '_';
- if (light_isalpha(ds->key->ptr[j])) {
- /* upper-case */
- cr = ds->key->ptr[j] & ~32;
- } else if (light_isdigit(ds->key->ptr[j])) {
- /* copy */
- cr = ds->key->ptr[j];
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
- }
-
- for (n = 0; n < con->environment->used; n++) {
- data_string *ds;
-
- ds = (data_string *)con->environment->data[n];
-
- if (ds->value->used && ds->key->used) {
- size_t j;
-
- buffer_reset(p->tmp_buf);
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
-
- for (j = 0; j < ds->key->used - 1; j++) {
- char cr = '_';
- if (light_isalpha(ds->key->ptr[j])) {
- /* upper-case */
- cr = ds->key->ptr[j] & ~32;
- } else if (light_isdigit(ds->key->ptr[j])) {
- /* copy */
- cr = ds->key->ptr[j];
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
- }
-
- if (env.size == env.used) {
- env.size += 16;
- env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
- }
-
- env.ptr[env.used] = NULL;
-
- /* set up args */
- argc = 3;
- args = malloc(sizeof(*args) * argc);
- i = 0;
-
- if (cgi_handler && cgi_handler->used > 1) {
- args[i++] = cgi_handler->ptr;
- }
- args[i++] = con->physical.path->ptr;
- args[i++] = NULL;
-
- /* search for the last / */
- if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
- *c = '\0';
-
- /* change to the physical directory */
- if (-1 == chdir(con->physical.path->ptr)) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
- }
- *c = '/';
- }
-
- /* we don't need the client socket */
- for (i = 3; i < 256; i++) {
- close(i);
- }
-
- /* exec the cgi */
- execve(args[0], args, env.ptr);
-
- /* */
- SEGFAULT("execve(%s) failed: %s", args[0], strerror(errno));
- break;
- }
- case -1:
- /* error */
- ERROR("fork() failed: %s", strerror(errno));
- close(to_cgi_fds[0]); close(to_cgi_fds[1]);
- close(from_cgi_fds[0]); close(from_cgi_fds[1]);
- close(from_cgi_err_fds[0]); close(from_cgi_err_fds[1]);
- return -1;
- break;
- default: {
- cgi_session *sess;
- /* father */
-
- close(from_cgi_fds[1]);
- close(from_cgi_err_fds[1]);
- close(to_cgi_fds[0]);
-
- /* register PID and wait for them asyncronously */
- con->mode = p->id;
- buffer_reset(con->physical.path);
-
- sess = cgi_session_init();
-
- sess->remote_con = con;
- sess->pid = pid;
-
- assert(sess->sock);
-
- sess->sock->fd = from_cgi_fds[0];
- sess->sock->type = IOSOCKET_TYPE_PIPE;
- sess->sock_err->fd = from_cgi_err_fds[0];
- sess->sock_err->type = IOSOCKET_TYPE_PIPE;
- sess->wb_sock->fd = to_cgi_fds[1];
- sess->wb_sock->type = IOSOCKET_TYPE_PIPE;
-
- if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
-
- cgi_session_free(sess);
-
- return -1;
- }
-
- if (-1 == fdevent_fcntl_set(srv->ev, sess->sock_err)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
-
- cgi_session_free(sess);
-
- return -1;
- }
-
- con->plugin_ctx[p->id] = sess;
-
- fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
- fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
-
- fdevent_register(srv->ev, sess->sock_err, cgi_handle_err_fdevent, sess);
- fdevent_event_add(srv->ev, sess->sock_err, FDEVENT_IN);
-
- sess->state = CGI_STATE_READ_RESPONSE_HEADER;
-
- break;
- }
- }
-
- return 0;
-#else
- return -1;
-#endif
-}
-
-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_OPTION(cgi);
- PATCH_OPTION(execute_all);
- PATCH_OPTION(execute_x_only);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ASSIGN))) {
- PATCH_OPTION(cgi);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXECUTE_ALL))) {
- PATCH_OPTION(execute_all);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXECUTE_X_ONLY))) {
- PATCH_OPTION(execute_x_only);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_cgi_start_backend) {
- size_t k, s_len;
- plugin_data *p = p_d;
- buffer *fn = con->physical.path;
- stat_cache_entry *sce = NULL;
-
- if (fn->used == 0) return HANDLER_GO_ON;
-
- mod_cgi_patch_connection(srv, con, p);
-
- if (p->conf.cgi->used == 0 && p->conf.execute_all == 0) {
- return HANDLER_GO_ON;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- checking request in mod_%s", "cgi");
- }
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) return HANDLER_GO_ON;
- if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
- if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
-
- s_len = fn->used - 1;
-
- for (k = 0; k < p->conf.cgi->used; k++) {
- data_string *ds = (data_string *)p->conf.cgi->data[k];
- size_t ct_len = ds->key->used - 1;
-
- if (ds->key->used == 0) continue;
- if (s_len < ct_len) continue;
-
- if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
- if (cgi_create_env(srv, con, p, ds->value)) {
- con->http_status = 500;
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- }
- return HANDLER_FINISHED;
- }
- }
-
- if (p->conf.execute_all) {
- if (cgi_create_env(srv, con, p, NULL)) {
- con->http_status = 500;
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- }
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-TRIGGER_FUNC(cgi_trigger) {
- plugin_data *p = p_d;
- size_t ndx;
- /* the trigger handle only cares about lonely PID which we have to wait for */
-#ifndef _WIN32
-
- for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
- int status;
-
- switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
- case 0:
- /* not finished yet */
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", p->cgi_pid.ptr[ndx]);
-#endif
- break;
- case -1:
- log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
-
- return HANDLER_ERROR;
- default:
-
- if (WIFEXITED(status)) {
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]);
-#endif
- } else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sdsd", "cgi signaled, pid:", p->cgi_pid.ptr[ndx], ", signal", WTERMSIG(status));
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sdsd", "cgi died, pid:", p->cgi_pid.ptr[ndx], ", status", status);
- }
-
- cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
- /* del modified the buffer structure
- * and copies the last entry to the current one
- * -> recheck the current index
- */
- ndx--;
- }
- }
-#endif
- return HANDLER_GO_ON;
-}
-
-SUBREQUEST_FUNC(mod_cgi_read_response_content) {
- int status;
- plugin_data *p = p_d;
- cgi_session *sess = con->plugin_ctx[p->id];
-
- if (con->mode != p->id) return HANDLER_GO_ON;
- if (NULL == sess) return HANDLER_GO_ON;
-
- switch (cgi_demux_response(srv, con, p)) {
- case 0:
- break;
- case 1:
- cgi_connection_close(srv, con, p);
-
- /* if we get a IN|HUP and have read everything don't exec the close twice */
- return HANDLER_FINISHED;
- case -1:
- cgi_connection_close(srv, con, p);
-
- if (0 == con->http_status) con->http_status = 500;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
-#endif
- if (sess->pid == 0) return HANDLER_FINISHED;
-#ifndef _WIN32
- switch(waitpid(sess->pid, &status, WNOHANG)) {
- case 0:
- /* we only have for events here if we don't have the header yet,
- * otherwise the event-handler will send us the incoming data */
-
- if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
- if (con->send->is_closed) return HANDLER_FINISHED;
-
- return HANDLER_GO_ON;
- case -1:
- if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
-
- if (errno == ECHILD && con->file_started == 0) {
- /*
- * second round but still not response
- */
- return HANDLER_WAIT_FOR_EVENT;
- }
-
- log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
- con->mode = DIRECT;
- con->http_status = 500;
-
- sess->pid = 0;
-
- fdevent_event_del(srv->ev, sess->sock);
- fdevent_unregister(srv->ev, sess->sock);
-
- fdevent_event_del(srv->ev, sess->sock_err);
- fdevent_unregister(srv->ev, sess->sock_err);
-
- cgi_session_free(sess);
- sess = NULL;
-
- con->plugin_ctx[p->id] = NULL;
-
- return HANDLER_FINISHED;
- default:
- con->send->is_closed = 1;
-
- if (WIFEXITED(status)) {
- /* nothing */
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
-
- con->mode = DIRECT;
- con->http_status = 500;
-
- }
-
- sess->pid = 0;
-
- fdevent_event_del(srv->ev, sess->sock);
- fdevent_unregister(srv->ev, sess->sock);
-
- fdevent_event_del(srv->ev, sess->sock_err);
- fdevent_unregister(srv->ev, sess->sock_err);
-
- cgi_session_free(sess);
- sess = NULL;
-
- con->plugin_ctx[p->id] = NULL;
- return HANDLER_FINISHED;
- }
-#else
- return HANDLER_ERROR;
-#endif
-}
-
-URIHANDLER_FUNC(mod_cgi_send_request_content) {
- plugin_data *p = p_d;
- cgi_session *sess = con->plugin_ctx[p->id];
-
- if (p->id != con->mode) return HANDLER_GO_ON;
-
- if (con->request.content_length > 0 && con->recv->bytes_in > con->recv->bytes_out) {
- /* write request content. */
- switch (network_write_chunkqueue_write(srv, con, sess->wb_sock, con->recv)) {
- case NETWORK_STATUS_SUCCESS:
- /** fall through, still have data to write. */
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- /** fall through */
- case NETWORK_STATUS_WAIT_FOR_AIO_EVENT:
- break;
- case NETWORK_STATUS_CONNECTION_CLOSE:
- /* the script might have written a response already. */
- break;
- default:
- TRACE("%s", "(error)");
- return HANDLER_ERROR;
- }
- chunkqueue_remove_finished_chunks(con->recv);
- }
- /* we have to close the pipe to finish the request. */
- if ((con->recv->is_closed && con->recv->bytes_in == con->recv->bytes_out) ||
- con->request.content_length <= 0) {
- close(sess->wb_sock->fd);
- sess->wb_sock->fd = -1;
- } else {
- /* there is more data to write. */
- return HANDLER_GO_ON;
- }
-
- return mod_cgi_read_response_content(srv, con, p_d);
-}
-
-
-LI_EXPORT int mod_cgi_plugin_init(plugin *p);
-LI_EXPORT 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_start_backend = mod_cgi_start_backend;
- p->handle_send_request_content = mod_cgi_send_request_content;
- p->handle_read_response_content = mod_cgi_read_response_content;
-
- p->handle_trigger = cgi_trigger;
- p->init = mod_cgi_init;
- p->cleanup = mod_cgi_free;
- p->set_defaults = mod_cgi_set_defaults;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_chunked.c b/src/mod_chunked.c
deleted file mode 100644
index 567a3bdb..00000000
--- a/src/mod_chunked.c
+++ /dev/null
@@ -1,381 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-#include "filter.h"
-
-#include "plugin.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define CONFIG_CHUNKED_ENCODING "chunked.encoding"
-#define CONFIG_CHUNKED_DEBUG "chunked.debug"
-
-/**
- * This plugin adds HTTP/1.1 chunked encoding support
- * as a filter module.
- *
- */
-
-/* plugin config for all request/connections */
-
-typedef struct {
- unsigned short encoding;
- unsigned short debug;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-typedef struct {
- unsigned short debug;
- filter *fl;
-} handler_ctx;
-
-static handler_ctx * handler_ctx_init() {
- handler_ctx * hctx;
-
- hctx = calloc(1, sizeof(*hctx));
- hctx->debug = 0;
- hctx->fl = NULL;
-
- return hctx;
-}
-
-static void handler_ctx_free(handler_ctx *hctx) {
-
- free(hctx);
-}
-
-/* init the plugin data */
-INIT_FUNC(mod_chunked_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-/* destroy the plugin data */
-FREE_FUNC(mod_chunked_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;
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_chunked_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { CONFIG_CHUNKED_ENCODING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { CONFIG_CHUNKED_DEBUG, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->encoding = 1;
- s->debug = 0;
-
- cv[0].destination = &(s->encoding);
- cv[1].destination = &(s->debug);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-REQUESTDONE_FUNC(mod_chunked_reset) {
- plugin_data *p = p_d;
- handler_ctx *hctx = con->plugin_ctx[p->id];
-
- UNUSED(srv);
-
- if (NULL == hctx) return HANDLER_GO_ON;
-
- handler_ctx_free(hctx);
- con->plugin_ctx[p->id] = NULL;
-
- return HANDLER_GO_ON;
-}
-
-static int mod_chunked_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(encoding);
- PATCH_OPTION(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(CONFIG_CHUNKED_ENCODING))) {
- PATCH_OPTION(encoding);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_CHUNKED_DEBUG))) {
- PATCH_OPTION(debug);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_chunked_response_header) {
- plugin_data *p = p_d;
- handler_ctx *hctx;
- filter *fl;
- chunkqueue *in;
- int use_chunked = 0;
-
- mod_chunked_patch_connection(srv, con, p);
-
- /* get filter. */
- fl = filter_chain_get_filter(con->send_filters, p->id);
- if (!fl) {
- if (p->conf.debug > 0) TRACE("%s", "add chunked filter to filter chain");
- fl = filter_chain_create_filter(con->send_filters, p->id);
- }
- /* get our input and output chunkqueues. */
- if (!fl || !fl->prev) {
- filter_chain_remove_filter(con->send_filters, fl);
- return HANDLER_GO_ON;
- }
- in = fl->prev->cq;
-
- if (in->is_closed && (con->response.content_length < 0 || con->request.http_method != HTTP_METHOD_HEAD)) {
- con->response.content_length = chunkqueue_length(in);
- }
- /* check if response needs chunked encoding. */
- if (con->request.http_method != HTTP_METHOD_HEAD) {
- if(con->response.content_length >= 0) {
- if (p->conf.debug > 0) TRACE("response content length known, disabling chunked encoding. len=%jd", (intmax_t) con->response.content_length);
- use_chunked = 0;
- } else {
- /* a HEAD request never gets a chunk-encoding, but might stay with keep-alive
- * in case the queue was closed already (above) we still have the content-length */
-
- /* we don't know the size of the content yet
- * - either enable chunking
- * - or disable keep-alive */
-
- if (con->request.http_version == HTTP_VERSION_1_1 && p->conf.encoding) {
- use_chunked = 1;
- } else {
- if (p->conf.debug > 0)
- TRACE("%s", "content length unknown and can't use chunked encoding. disable keep-alive");
- con->keep_alive = 0;
- use_chunked = 0;
- }
- }
- }
-
- if (!use_chunked) {
- /* chunked encoding disabled. remove filter */
- con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
- filter_chain_remove_filter(con->send_filters, fl);
- return HANDLER_GO_ON;
- }
-
- /* enable chunked encoding */
- con->response.transfer_encoding |= HTTP_TRANSFER_ENCODING_CHUNKED;
- hctx = handler_ctx_init();
- hctx->debug = p->conf.debug;
- con->plugin_ctx[p->id] = hctx;
- hctx->fl = fl;
-
- if (hctx->debug > 0)
- TRACE("%s", "chunked encoding enabled");
-
- return HANDLER_GO_ON;
-}
-
-static int http_chunk_append_len(chunkqueue *cq, size_t len) {
- size_t i, olen = len, j;
- buffer *b;
-
- b = buffer_init();
-
- if (len == 0) {
- buffer_copy_string_len(b, CONST_STR_LEN("0"));
- } else {
- for (i = 0; i < 8 && len; i++) {
- len >>= 4;
- }
-
- /* i is the number of hex digits we have */
- buffer_prepare_copy(b, i + 1);
-
- for (j = i-1, len = olen; j+1 > 0; j--) {
- b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
- len >>= 4;
- }
- b->used = i;
- b->ptr[b->used++] = '\0';
- }
-
- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
- chunkqueue_append_buffer(cq, b);
- len = b->used - 1;
-
- buffer_free(b);
-
- return len;
-}
-
-/**
- * apply HTTP/1.1 chunked encoding if necessary
- */
-URIHANDLER_FUNC(mod_chunked_encode_response_content) {
- plugin_data *p = p_d;
- handler_ctx *hctx = con->plugin_ctx[p->id];
- chunkqueue *in;
- chunkqueue *out;
- int we_have = 0;
- chunk *c;
-
- UNUSED(srv);
-
- /* check if chunk-encoding is enabled. */
- if (!hctx) return HANDLER_GO_ON;
-
- /* get our input and output chunkqueues. */
- if (!hctx->fl || !hctx->fl->prev) return HANDLER_GO_ON;
- in = hctx->fl->prev->cq;
- out = hctx->fl->cq;
-
- /* we are all done already (see the end of the function) */
- if (out->is_closed) return HANDLER_GO_ON;
-
- /* move all chunks to the out queue
- * and append a HTTP/1.1 chunked header to each chunk
- */
- for (c = in->first; c; c = c->next) {
- switch (c->type) {
- case MEM_CHUNK:
- if (c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- in->bytes_out += we_have;
- if(we_have == 0) continue;
- we_have += http_chunk_append_len(out, we_have);
- chunkqueue_append_buffer(out, c->mem);
-
- chunk_set_done(c);
-
- break;
- case FILE_CHUNK:
- if (c->file.length == 0) continue;
-
- we_have = c->file.length;
- in->bytes_out += we_have;
- we_have += http_chunk_append_len(out, c->file.length);
-
- if(c->file.is_temp) {
- chunkqueue_steal_tempfile(out, c);
- } else {
- chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);
- }
-
- chunk_set_done(c);
-
- break;
- case UNUSED_CHUNK:
- break;
- }
- chunkqueue_append_mem(out, CONST_STR_LEN("\r\n"));
- we_have += 2;
- out->bytes_in += we_have;
- }
-
- /* terminate the last chunk */
- if (in->is_closed) {
- chunkqueue_append_mem(out, CONST_STR_LEN("0\r\n\r\n"));
- out->bytes_in += 5;
- }
-
- if (hctx->debug > 1) TRACE("chunk encoded: in=%jd, out=%jd", (intmax_t) in->bytes_out, (intmax_t) out->bytes_in);
-
- chunkqueue_remove_finished_chunks(in);
-
- /* the in side is closed, close out too */
- if (in->is_closed) {
- /* mark the output queue as finished. */
- out->is_closed = 1;
- }
-
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_chunked_plugin_init(plugin *p);
-LI_EXPORT int mod_chunked_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("chunked");
-
- p->init = mod_chunked_init;
- p->set_defaults = mod_chunked_set_defaults;
- p->handle_response_header = mod_chunked_response_header;
- p->handle_filter_response_content = mod_chunked_encode_response_content;
- p->connection_reset = mod_chunked_reset;
- p->cleanup = mod_chunked_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_compress.c b/src/mod_compress.c
deleted file mode 100644
index 7e72fb4a..00000000
--- a/src/mod_compress.c
+++ /dev/null
@@ -1,848 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-#include "stat_cache.h"
-
-#include "plugin.h"
-
-#include "crc32.h"
-#include "etag.h"
-
-#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
-
-#include "sys-mmap.h"
-#include "sys-files.h"
-
-/* 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)
-
-#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;
-} 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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->ofn = buffer_init();
- p->b = buffer_init();
-
- return p;
-}
-
-FREE_FUNC(mod_compress_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->ofn);
- buffer_free(p->b);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->compress);
- buffer_free(s->compress_cache_dir);
-
- free(s);
- }
- free(p->config_storage);
- }
-
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 0 on success, -1 for error */
-static int mkdir_recursive(char *dir) {
- char *p = dir;
-
- if (!dir || !dir[0])
- return 0;
-
- while ((p = strchr(p + 1, '/')) != NULL) {
-
- *p = '\0';
- if ((mkdir(dir, 0700) != 0) && (errno != EEXIST)) {
- *p = '/';
- return -1;
- }
-
- *p++ = '/';
- if (!*p) return 0; /* Ignore trailing slash */
- }
-
- return (mkdir(dir, 0700) != 0) && (errno != EEXIST) ? -1 : 0;
-}
-
-/* 0 on success, -1 for error */
-static int mkdir_for_file(char *filename) {
- char *p = filename;
-
- if (!filename || !filename[0])
- return -1;
-
- while ((p = strchr(p + 1, '/')) != NULL) {
-
- *p = '\0';
- if ((mkdir(filename, 0700) != 0) && (errno != EEXIST)) {
- ERROR("creating cache-directory \"%s\" failed: %s", filename, strerror(errno));
- *p = '/';
- return -1;
- }
-
- *p++ = '/';
- if (!*p) {
- ERROR("unexpected trailing slash for filename \"%s\"", filename);
- return -1;
- }
- }
-
- 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 },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- array *encodings_arr = array_init();
-
- s = calloc(1, sizeof(plugin_config));
- s->compress_cache_dir = buffer_init();
- s->compress = array_init();
- s->compress_max_filesize = 0;
- s->allowed_encodings = 0;
-
- cv[0].destination = s->compress_cache_dir;
- cv[1].destination = s->compress;
- cv[2].destination = &(s->compress_max_filesize);
- cv[3].destination = encodings_arr; /* temp array for allowed encodings list */
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (encodings_arr->used) {
- size_t j = 0;
- for (j = 0; j < encodings_arr->used; j++) {
- data_string *ds = (data_string *)encodings_arr->data[j];
-#ifdef USE_ZLIB
- if (NULL != strstr(ds->value->ptr, "gzip"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
- 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;
-#endif
- }
- } else {
- /* default encodings */
- s->allowed_encodings = 0
-#ifdef USE_ZLIB
- | HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_DEFLATE
-#endif
-#ifdef USE_BZ2LIB
- | HTTP_ACCEPT_ENCODING_BZIP2
-#endif
- ;
- }
-
- array_free(encodings_arr);
-
- if (!buffer_is_empty(s->compress_cache_dir)) {
- struct stat st;
- if (0 != stat(s->compress_cache_dir->ptr, &st)) {
-
- ERROR("can't stat compress.cache-dir (%s), attempting to create '%s'", strerror(errno),SAFE_BUF_STR(s->compress_cache_dir));
- mkdir_recursive(s->compress_cache_dir->ptr);
-
- if (0 != stat(s->compress_cache_dir->ptr, &st)) {
- ERROR("can't stat compress.cache-dir (%s), failed to create '%s'", strerror(errno),SAFE_BUF_STR(s->compress_cache_dir));
- 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;
-
- 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_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 */
-
- p->b->used = 10;
- z.next_out = (unsigned char *)p->b->ptr + p->b->used;
- z.avail_out = p->b->size - p->b->used - 8;
- z.total_out = 0;
-
- if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
- deflateEnd(&z);
- return -1;
- }
-
- /* trailer */
- p->b->used += z.total_out;
-
- crc = generate_crc32c(start, st_size);
-
- c = (unsigned char *)p->b->ptr + p->b->used;
-
- c[0] = (crc >> 0) & 0xff;
- c[1] = (crc >> 8) & 0xff;
- c[2] = (crc >> 16) & 0xff;
- 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;
- p->b->used += 8;
-
- 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_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
-
- z.next_out = (unsigned char *)p->b->ptr;
- z.avail_out = p->b->size;
- z.total_out = 0;
-
- if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
- deflateEnd(&z);
- return -1;
- }
-
- /* trailer */
- p->b->used += z.total_out;
-
- if (Z_OK != deflateEnd(&z)) {
- return -1;
- }
-
- return 0;
-}
-
-#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_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
-
- bz.next_out = p->b->ptr;
- bz.avail_out = p->b->size;
- bz.total_out_lo32 = 0;
- bz.total_out_hi32 = 0;
-
- if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
- BZ2_bzCompressEnd(&bz);
- return -1;
- }
-
- /* file is too large for now */
- if (bz.total_out_hi32) return -1;
-
- /* trailer */
- p->b->used = bz.total_out_lo32;
-
- if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
- return -1;
- }
-
- return 0;
-}
-#endif
-
-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 = -1;
- void *start;
- const char *filename = fn->ptr;
- ssize_t r;
- stat_cache_entry *compressed_sce = NULL;
-
- if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
-
- /* 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_string_buffer(p->ofn, p->conf.compress_cache_dir);
- PATHNAME_APPEND_SLASH(p->ofn);
-
- if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
- buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
- buffer_copy_string_buffer(p->b, p->ofn);
- } else {
- buffer_append_string_buffer(p->ofn, con->uri.path);
- }
-
- switch(type) {
- case HTTP_ACCEPT_ENCODING_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:
- buffer_append_string_len(p->ofn, CONST_STR_LEN("-bzip2-"));
- break;
- default:
- ERROR("unknown compression type %d", type);
- return -1;
- }
-
- buffer_append_string_buffer(p->ofn, sce->etag);
-
-
- if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
- /* file exists */
- if (con->conf.log_request_handling) TRACE("file exists in the cache (%s), sending it", SAFE_BUF_STR(p->ofn));
-
- chunkqueue_reset(con->send);
- chunkqueue_append_file(con->send, p->ofn, 0, compressed_sce->st.st_size);
- con->send->is_closed = 1;
-
- return 0;
- }
-
- if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
- if (-1 == mkdir_for_file(p->ofn->ptr)) {
- return -1; // error message in mkdir_for_file
- } else if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
- ERROR("creating cachefile '%s' failed: %s", SAFE_BUF_STR(p->ofn), strerror(errno));
- return -1;
- }
- }
-
- if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
- ERROR("opening plain-file '%s' failed: %s", SAFE_BUF_STR(fn), strerror(errno));
- close(ofd);
- return -1;
- }
-
-
- if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
- ERROR("mmaping '%s' failed: %s", SAFE_BUF_STR(fn), strerror(errno));
- close(ofd);
- close(ifd);
- return -1;
- }
-
- switch(type) {
-#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_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:
- ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
- break;
-#endif
- default:
- ret = -1;
- break;
- }
-
- if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
- munmap(start, sce->st.st_size);
- close(ofd);
- close(ifd);
- return -1;
- }
-
- if ((size_t)r != p->b->used) {
-
- }
-
- munmap(start, sce->st.st_size);
- close(ofd);
- close(ifd);
-
- if (ret != 0) return -1;
-
- chunkqueue_reset(con->send);
- chunkqueue_append_file(con->send, p->ofn, 0, r);
- con->send->is_closed = 1;
-
- 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;
- void *start;
- buffer *b;
-
- /* overflow */
- if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
-
- /* don't mmap files > 128M
- *
- * we could use a sliding window, but currently there is no need for it
- */
-
- if (sce->st.st_size > 128 * 1024 * 1024) return -1;
-
- if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
- ERROR("opening plain-file '%s' failed: %s", SAFE_BUF_STR(fn), strerror(errno));
-
- return -1;
- }
-
- start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
-
- close(ifd);
-
- if (MAP_FAILED == start) {
- ERROR("mmaping '%s' failed: %s", SAFE_BUF_STR(fn), strerror(errno));
-
- return -1;
- }
-
- switch(type) {
-#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_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:
- ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
- break;
-#endif
- default:
- ret = -1;
- break;
- }
-
- munmap(start, sce->st.st_size);
-
- if (ret != 0) return -1;
-
- chunkqueue_reset(con->send);
- b = chunkqueue_get_append_buffer(con->send);
- buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
- con->send->bytes_in += b->used-1;
-
- buffer_reset(con->physical.path);
-
- con->send->is_closed = 1;
- con->file_started = 1;
-
- return 0;
-}
-
-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_OPTION(compress_cache_dir);
- PATCH_OPTION(compress);
- PATCH_OPTION(compress_max_filesize);
- PATCH_OPTION(allowed_encodings);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
- PATCH_OPTION(compress_cache_dir);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
- PATCH_OPTION(compress);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
- PATCH_OPTION(compress_max_filesize);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.allowed-encodings"))) {
- PATCH_OPTION(allowed_encodings);
- }
- }
- }
-
- return 0;
-}
-
-PHYSICALPATH_FUNC(mod_compress_physical) {
- plugin_data *p = p_d;
- size_t m;
- off_t max_fsize;
- stat_cache_entry *sce = NULL;
- data_string *ds;
- int accept_encoding = 0;
- char *value;
- int matched_encodings = 0;
- const char *dflt_gzip = "gzip";
- const char *dflt_deflate = "deflate";
- const char *dflt_bzip2 = "bzip2";
-
- const char *compression_name = NULL;
- int compression_type = 0;
- buffer *mtime, *content_type;
-
- if (con->mode != DIRECT) return HANDLER_GO_ON;
-
- if (con->conf.log_request_handling) TRACE("-- %s", "handling in mod_compress");
-
- /* 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_is_empty(con->physical.path)) {
- return HANDLER_GO_ON;
- }
-
- mod_compress_patch_connection(srv, con, p);
-
- max_fsize = p->conf.compress_max_filesize;
-
- if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- if (con->conf.log_request_handling) TRACE("file '%s' not found", SAFE_BUF_STR(con->physical.path));
- 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) {
- if (con->conf.log_request_handling) TRACE("file '%s' is too large: %jd",
- SAFE_BUF_STR(con->physical.path),
- (intmax_t) sce->st.st_size);
-
- return HANDLER_GO_ON;
- }
-
- /* compressing the file might lead to larger files instead */
- if (sce->st.st_size < 128) {
- if (con->conf.log_request_handling) TRACE("file '%s' is too small: %jd",
- SAFE_BUF_STR(con->physical.path),
- (intmax_t) sce->st.st_size);
-
- return HANDLER_GO_ON;
- }
-
- /* check if mimetype is in compress-config */
- content_type = 0;
- if (sce->content_type->ptr) {
- char *c;
- if ( (c = strchr(BUF_STR(sce->content_type), ';')) != 0) {
- content_type = buffer_init();
- buffer_copy_string_len(content_type, BUF_STR(sce->content_type), c - BUF_STR(sce->content_type));
- }
- }
- for (m = 0; m < p->conf.compress->used; m++) {
- data_string *compress_ds = (data_string *)p->conf.compress->data[m];
-
- if (!compress_ds) {
- ERROR("evil: %s .. %s", SAFE_BUF_STR(con->physical.path), SAFE_BUF_STR(con->uri.path));
-
- return HANDLER_GO_ON;
- }
-
- if (buffer_is_equal(compress_ds->value, sce->content_type)
- || (content_type && buffer_is_equal(compress_ds->value, content_type))) {
- break;
- }
- }
- buffer_free(content_type);
-
- if (m == p->conf.compress->used) {
- return HANDLER_GO_ON;
- }
- /* mimetype found */
-
-
- if (con->send->is_closed == 0) {
- if (con->conf.log_request_handling) TRACE("we can't compress streams: is_closed = %d", con->send->is_closed);
- return HANDLER_GO_ON;
- }
-
- if (con->send->first == NULL) {
- if (con->conf.log_request_handling) TRACE("we can't compress streams: ->first = %p", NULL);
- return HANDLER_GO_ON;
- }
-
- if (con->send->first->next != NULL) {
- if (con->conf.log_request_handling) TRACE("we can't compress streams: ->first->next = %p", NULL);
- return HANDLER_GO_ON;
- }
-
- if (con->send->first->type != FILE_CHUNK) {
- if (con->conf.log_request_handling) TRACE("we can compress file-chunks: ->type = %d", con->send->first->type);
- return HANDLER_GO_ON;
- }
-
- /* the response might change according to Accept-Encoding */
- response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
-
- if (NULL == (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Accept-Encoding")))) {
- if (con->conf.log_request_handling) TRACE("couldn't find a Accept-Encoding header: %s", "");
- return HANDLER_GO_ON;
- }
-
- value = ds->value->ptr;
-
- /* get client side support encodings */
-#ifdef USE_ZLIB
- if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
- if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
- if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
-#endif
-#ifdef USE_BZ2LIB
- if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
-#endif
- if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
-
- /* find matching entries */
- matched_encodings = accept_encoding & p->conf.allowed_encodings;
- if (0 == matched_encodings) {
- if (con->conf.log_request_handling) TRACE("we don't support the requested encoding: %s", value);
- return HANDLER_GO_ON;
- }
-
- mtime = strftime_cache_get(srv, sce->st.st_mtime);
- etag_mutate(con->physical.etag, sce->etag);
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
- response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
-
- /* perhaps we don't even have to compress the file as the browser still has the
- * current version */
- if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
- if (con->conf.log_request_handling) TRACE("%s is still the same, caching", SAFE_BUF_STR(con->physical.path));
- 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_GZIP) {
- compression_type = HTTP_ACCEPT_ENCODING_GZIP;
- compression_name = dflt_gzip;
- } else if (matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE) {
- compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
- compression_name = dflt_deflate;
- }
-
- if (con->conf.log_request_handling) TRACE("we are fine, let's compress: %s", "");
-
- /* deflate it to file (cached) or to memory */
- if (0 == deflate_file_to_file(srv, con, p,
- con->physical.path, sce, compression_type) ||
- 0 == deflate_file_to_buffer(srv, con, p,
- con->physical.path, sce, compression_type)) {
-
- response_header_overwrite(srv, con,
- CONST_STR_LEN("Content-Encoding"),
- compression_name, strlen(compression_name));
-
- response_header_overwrite(srv, con,
- CONST_STR_LEN("Content-Type"),
- CONST_BUF_LEN(sce->content_type));
-
- con->response.content_length = chunkqueue_length(con->send);
-
- if (con->conf.log_request_handling) TRACE("looks like %s could be compressed", SAFE_BUF_STR(con->physical.path));
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_compress_plugin_init(plugin *p);
-LI_EXPORT 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;
-
- /* we have to hook into the response-header settings */
- p->handle_response_header = mod_compress_physical;
-
- p->cleanup = mod_compress_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_deflate.c b/src/mod_deflate.c
deleted file mode 100644
index 79deb11d..00000000
--- a/src/mod_deflate.c
+++ /dev/null
@@ -1,1408 +0,0 @@
-/*
- * mod_deflate - dynamic compression
- *
- * This plugin is a response filter.
- *
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <assert.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-#include "joblist.h"
-#include "stat_cache.h"
-#include "filter.h"
-
-#include "plugin.h"
-
-#include "crc32.h"
-#include "etag.h"
-#include "inet_ntop_cache.h"
-
-#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
-
-#include "sys-mmap.h"
-
-/* 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)
-
-/* encoding names */
-#define ENCODING_NAME_IDENTITY "identity"
-#define ENCODING_NAME_GZIP "gzip"
-#define ENCODING_NAME_DEFLATE "deflate"
-#define ENCODING_NAME_COMPRESS "compress"
-#define ENCODING_NAME_BZIP2 "bzip2"
-
-
-#define CONFIG_DEFLATE_OUTPUT_BUFFER_SIZE "deflate.output-buffer-size"
-#define CONFIG_DEFLATE_MIMETYPES "deflate.mimetypes"
-#define CONFIG_DEFLATE_COMPRESSION_LEVEL "deflate.compression-level"
-#define CONFIG_DEFLATE_MEM_LEVEL "deflate.mem-level"
-#define CONFIG_DEFLATE_WINDOW_SIZE "deflate.window-size"
-#define CONFIG_DEFLATE_MIN_COMPRESS_SIZE "deflate.min-compress-size"
-#define CONFIG_DEFLATE_WORK_BLOCK_SIZE "deflate.work-block-size"
-#define CONFIG_DEFLATE_ENABLED "deflate.enabled"
-#define CONFIG_DEFLATE_DEBUG "deflate.debug"
-#define CONFIG_DEFLATE_ALLOWED_ENCODINGS "deflate.allowed_encodings"
-#define CONFIG_DEFLATE_SYNC_FLUSH "deflate.sync-flush"
-
-#define KByte * 1024
-#define MByte * 1024 KByte
-#define GByte * 1024 MByte
-
-typedef struct {
- unsigned short debug;
- unsigned short enabled;
- unsigned short sync_flush;
- unsigned short output_buffer_size;
- unsigned short min_compress_size;
- unsigned short work_block_size;
- int allowed_encodings;
- short mem_level;
- short compression_level;
- short window_size;
- array *mimetypes;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
- buffer *tmp_buf;
- array *encodings_arr;
-
- plugin_config **config_storage;
- plugin_config conf;
-} plugin_data;
-
-typedef struct {
- off_t bytes_in;
- filter *fl;
- chunkqueue *in;
- chunkqueue *out;
- buffer *output;
- /* compression type & state */
- int compression_type;
- int stream_open;
-#ifdef USE_ZLIB
- unsigned long crc;
- z_stream z;
- unsigned short gzip_header;
-#endif
-#ifdef USE_BZ2LIB
- bz_stream bz;
-#endif
- plugin_data *plugin_data;
-} handler_ctx;
-
-static handler_ctx *handler_ctx_init() {
- handler_ctx *hctx;
-
- hctx = calloc(1, sizeof(*hctx));
- hctx->in = NULL;
- hctx->out = NULL;
-
- return hctx;
-}
-
-static void handler_ctx_free(handler_ctx *hctx) {
- free(hctx);
-}
-
-INIT_FUNC(mod_deflate_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
- p->encodings_arr = array_init();
-
- 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_arr);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { CONFIG_DEFLATE_OUTPUT_BUFFER_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_MIMETYPES, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_COMPRESSION_LEVEL, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_MEM_LEVEL, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_WINDOW_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_MIN_COMPRESS_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_WORK_BLOCK_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_ENABLED, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_DEBUG, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_SYNC_FLUSH, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { CONFIG_DEFLATE_ALLOWED_ENCODINGS, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- array_reset(p->encodings_arr);
-
- s = calloc(1, sizeof(plugin_config));
- s->enabled = 1;
- s->sync_flush = 0;
- s->allowed_encodings = 0;
- s->debug = 0;
- s->output_buffer_size = 0;
- s->mem_level = 9;
- s->window_size = 15;
- s->min_compress_size = 0;
- s->work_block_size = 2048;
- s->compression_level = -1;
- s->mimetypes = array_init();
-
- cv[0].destination = &(s->output_buffer_size);
- cv[1].destination = s->mimetypes;
- cv[2].destination = &(s->compression_level);
- cv[3].destination = &(s->mem_level);
- cv[4].destination = &(s->window_size);
- cv[5].destination = &(s->min_compress_size);
- cv[6].destination = &(s->work_block_size);
- cv[7].destination = &(s->enabled);
- cv[8].destination = &(s->debug);
- cv[9].destination = &(s->sync_flush);
- cv[10].destination = p->encodings_arr; /* temp array for allowed encodings list */
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (p->encodings_arr->used) {
- size_t j = 0;
- for (j = 0; j < p->encodings_arr->used; j++) {
- data_string *ds = (data_string *)p->encodings_arr->data[j];
-#ifdef USE_ZLIB
- if (NULL != strstr(BUF_STR(ds->value), ENCODING_NAME_GZIP))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
- if (NULL != strstr(BUF_STR(ds->value), ENCODING_NAME_DEFLATE))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
-#endif
- /*
- if (NULL != strstr(BUF_STR(ds->value), ENCODING_NAME_COMPRESS))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
- */
-#ifdef USE_BZ2LIB
- if (NULL != strstr(BUF_STR(ds->value), ENCODING_NAME_BZIP2))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
-#endif
- }
- } else {
- /* default encodings */
- s->allowed_encodings = HTTP_ACCEPT_ENCODING_IDENTITY | HTTP_ACCEPT_ENCODING_GZIP |
- HTTP_ACCEPT_ENCODING_DEFLATE | HTTP_ACCEPT_ENCODING_COMPRESS | HTTP_ACCEPT_ENCODING_BZIP2;
- }
-
- if((s->compression_level < 1 || s->compression_level > 9) &&
- s->compression_level != -1) {
- ERROR("compression-level must be between 1 and 9: %i", s->compression_level);
- return HANDLER_ERROR;
- }
-
- if(s->mem_level < 1 || s->mem_level > 9) {
- ERROR("mem-level must be between 1 and 9: %i", s->mem_level);
- return HANDLER_ERROR;
- }
-
- if(s->window_size < 1 || s->window_size > 15) {
- ERROR("window-size must be between 1 and 15: %i", s->window_size);
- return HANDLER_ERROR;
- }
- s->window_size = 0 - s->window_size;
-
- if(s->sync_flush) {
- s->output_buffer_size = 0;
- }
- }
-
- return HANDLER_GO_ON;
-
-}
-
-#ifdef USE_ZLIB
-/* Copied gzip_header from apache 2.2's mod_deflate.c */
-/* RFC 1952 Section 2.3 defines the gzip header:
- *
- * +---+---+---+---+---+---+---+---+---+---+
- * |ID1|ID2|CM |FLG| MTIME |XFL|OS |
- * +---+---+---+---+---+---+---+---+---+---+
- */
-static const char gzip_header[10] =
-{ '\037', '\213', Z_DEFLATED, 0,
- 0, 0, 0, 0, /* mtime */
- 0, 0x03 /* Unix OS_CODE */
-};
-static int stream_deflate_init(server *srv, connection *con, handler_ctx *hctx) {
- plugin_data *p = hctx->plugin_data;
- z_stream *z;
- int r, compression_level;
-
- UNUSED(srv);
- UNUSED(con);
-
- z = &(hctx->z);
- z->zalloc = Z_NULL;
- z->zfree = Z_NULL;
- z->opaque = Z_NULL;
- z->total_in = 0;
- z->total_out = 0;
- z->next_out = NULL;
- z->avail_out = 0;
-
- compression_level = p->conf.compression_level;
- if(compression_level == -1)
- compression_level = Z_DEFAULT_COMPRESSION;
-
- if(p->conf.debug) {
- TRACE("output-buffer-size: %i", p->conf.output_buffer_size);
- TRACE("compression-level: %i", compression_level);
- TRACE("mem-level: %i", p->conf.mem_level);
- TRACE("window-size: %i", p->conf.window_size);
- TRACE("min-compress-size: %i", p->conf.min_compress_size);
- TRACE("work-block-size: %i", p->conf.work_block_size);
- }
- if (Z_OK != (r = deflateInit2(z,
- compression_level,
- Z_DEFLATED,
- p->conf.window_size, /* supress zlib-header */
- p->conf.mem_level,
- Z_DEFAULT_STRATEGY))) {
- ERROR("deflateInit2() failed with %d", r);
- return -1;
- }
- hctx->stream_open = 1;
-
- return 0;
-}
-
-static int stream_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
- plugin_data *p = hctx->plugin_data;
- z_stream *z;
- int len;
- int in = 0, out = 0;
-
- UNUSED(srv);
- UNUSED(con);
-
- z = &(hctx->z);
-
- if(z->next_out == NULL) {
- z->next_out = (unsigned char *)hctx->output->ptr;
- z->avail_out = hctx->output->size;
- }
-
- if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP) {
- if(hctx->gzip_header == 0) {
- hctx->gzip_header = 1;
- /* copy gzip header into output buffer */
- buffer_copy_memory(hctx->output, gzip_header, sizeof(gzip_header));
- if(p->conf.debug) {
- TRACE("gzip_header len=%zu", sizeof(gzip_header));
- }
- /* initialize crc32 */
- hctx->crc = crc32(0L, Z_NULL, 0);
- z->next_out = (unsigned char *)(hctx->output->ptr + sizeof(gzip_header));
- z->avail_out = hctx->output->size - sizeof(gzip_header);
- }
- hctx->crc = crc32(hctx->crc, start, st_size);
- }
-
- z->next_in = start;
- z->avail_in = st_size;
- hctx->bytes_in += st_size;
-
- /* compress data */
- in = z->avail_in;
- do {
- if (Z_OK != deflate(z, Z_NO_FLUSH)) {
- deflateEnd(z);
- hctx->stream_open = 0;
- return -1;
- }
-
- if(z->avail_out == 0 || z->avail_in > 0) {
- len = hctx->output->size - z->avail_out;
- out += len;
- chunkqueue_append_mem(hctx->out, hctx->output->ptr, len);
- hctx->out->bytes_in += len;
- z->next_out = (unsigned char *)hctx->output->ptr;
- z->avail_out = hctx->output->size;
- }
- } while (z->avail_in > 0);
-
- if(p->conf.debug) {
- TRACE("compress: in=%i, out=%i", in, out);
- }
- return st_size;
-}
-
-static int stream_deflate_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
- plugin_data *p = hctx->plugin_data;
- z_stream *z;
- int len;
- int rc = 0;
- int done;
- int flush = 1;
- int in = 0, out = 0;
-
- UNUSED(srv);
- UNUSED(con);
-
- z = &(hctx->z);
-
- if(z->next_out == NULL) {
- z->next_out = (unsigned char *)hctx->output->ptr;
- z->avail_out = hctx->output->size;
- }
- /* compress data */
- in = z->avail_in;
- do {
- done = 1;
- if(end) {
- rc = deflate(z, Z_FINISH);
- if (rc == Z_OK) {
- done = 0;
- } else if (rc != Z_STREAM_END) {
- deflateEnd(z);
- hctx->stream_open = 0;
- return -1;
- }
- } else {
- if(p->conf.sync_flush) {
- rc = deflate(z, Z_SYNC_FLUSH);
- } else if(z->avail_in > 0) {
- if(p->conf.output_buffer_size > 0) flush = 0;
- rc = deflate(z, Z_NO_FLUSH);
- } else {
- if(p->conf.output_buffer_size > 0) flush = 0;
- rc = Z_OK;
- }
- if (rc != Z_OK) {
- deflateEnd(z);
- hctx->stream_open = 0;
- return -1;
- }
- }
-
- len = hctx->output->size - z->avail_out;
- if(z->avail_out == 0 || (flush && len > 0)) {
- out += len;
- chunkqueue_append_mem(hctx->out, hctx->output->ptr, len);
- hctx->out->bytes_in += len;
- z->next_out = (unsigned char *)hctx->output->ptr;
- z->avail_out = hctx->output->size;
- }
- } while (z->avail_in != 0 || !done);
-
-
- if(p->conf.debug) {
- TRACE("flush: in=%i, out=%i", in, out);
- }
- if(p->conf.sync_flush) {
- z->next_out = NULL;
- z->avail_out = 0;
- }
- return 0;
-}
-
-static int stream_deflate_end(server *srv, connection *con, handler_ctx *hctx) {
- plugin_data *p = hctx->plugin_data;
- z_stream *z;
- int rc;
-
- UNUSED(srv);
- UNUSED(con);
-
- z = &(hctx->z);
- if(!hctx->stream_open) return 0;
- hctx->stream_open = 0;
-
- if(hctx->compression_type == HTTP_ACCEPT_ENCODING_GZIP && (hctx->gzip_header)) {
- /* write gzip footer */
- unsigned char c[8];
-
- c[0] = (hctx->crc >> 0) & 0xff;
- c[1] = (hctx->crc >> 8) & 0xff;
- c[2] = (hctx->crc >> 16) & 0xff;
- c[3] = (hctx->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;
- /* append footer to write_queue */
- chunkqueue_append_mem(hctx->out, (char *)c, 8);
- hctx->out->bytes_in += 8;
- if(p->conf.debug) {
- TRACE("gzip_footer len=%i", 8);
- }
- }
-
- if ((rc = deflateEnd(z)) != Z_OK) {
- if(rc == Z_DATA_ERROR) return 0;
- if(z->msg != NULL) {
- ERROR("deflateEnd error ret=%i, msg='%s'", rc, z->msg);
- } else {
- ERROR("deflateEnd error ret=%i", rc);
- }
- return -1;
- }
- return 0;
-}
-
-#endif
-
-#ifdef USE_BZ2LIB
-static int stream_bzip2_init(server *srv, connection *con, handler_ctx *hctx) {
- plugin_data *p = hctx->plugin_data;
- bz_stream *bz;
- int compression_level;
-
- UNUSED(srv);
- UNUSED(con);
-
- bz = &(hctx->bz);
- 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;
-
- compression_level = p->conf.compression_level;
- if(compression_level == -1)
- compression_level = 9;
-
- if(p->conf.debug) {
- TRACE("output-buffer-size: %i", p->conf.output_buffer_size);
- TRACE("compression-level: %i", compression_level);
- TRACE("mem-level: %i", p->conf.mem_level);
- TRACE("window-size: %i", p->conf.window_size);
- TRACE("min-compress-size: %i", p->conf.min_compress_size);
- TRACE("work-block-size: %i", p->conf.work_block_size);
- }
- if (BZ_OK != BZ2_bzCompressInit(bz,
- compression_level, /* blocksize */
- 0, /* no output */
- 30)) { /* workFactor: default */
- return -1;
- }
- hctx->stream_open = 1;
-
- return 0;
-}
-
-static int stream_bzip2_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
- plugin_data *p = hctx->plugin_data;
- bz_stream *bz;
- int len;
- int rc;
- int in = 0, out = 0;
-
- UNUSED(srv);
- UNUSED(con);
-
- bz = &(hctx->bz);
-
- if(bz->next_out == NULL) {
- bz->next_out = hctx->output->ptr;
- bz->avail_out = hctx->output->size;
- }
-
- bz->next_in = (char *)start;
- bz->avail_in = st_size;
- hctx->bytes_in += st_size;
-
- /* compress data */
- in = bz->avail_in;
- do {
- rc = BZ2_bzCompress(bz, BZ_RUN);
- if (rc != BZ_RUN_OK) {
- BZ2_bzCompressEnd(bz);
- hctx->stream_open = 0;
- return -1;
- }
-
- if(bz->avail_out == 0 || bz->avail_in > 0) {
- len = hctx->output->size - bz->avail_out;
- out += len;
- chunkqueue_append_mem(hctx->out, hctx->output->ptr, len);
- hctx->out->bytes_in += len;
- bz->next_out = hctx->output->ptr;
- bz->avail_out = hctx->output->size;
- }
- } while (bz->avail_in > 0);
- if(p->conf.debug) {
- TRACE("compress: in=%i, out=%i", in, out);
- }
- return st_size;
-}
-
-static int stream_bzip2_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
- plugin_data *p = hctx->plugin_data;
- bz_stream *bz;
- int len;
- int rc;
- int done;
- int flush = 1;
- int in = 0, out = 0;
-
- UNUSED(srv);
- UNUSED(con);
-
- bz = &(hctx->bz);
-
- if(bz->next_out == NULL) {
- bz->next_out = hctx->output->ptr;
- bz->avail_out = hctx->output->size;
- }
- /* compress data */
- in = bz->avail_in;
- do {
- done = 1;
- if(end) {
- rc = BZ2_bzCompress(bz, BZ_FINISH);
- if (rc == BZ_FINISH_OK) {
- done = 0;
- } else if (rc != BZ_STREAM_END) {
- BZ2_bzCompressEnd(bz);
- hctx->stream_open = 0;
- return -1;
- }
- } else if(bz->avail_in > 0) {
- rc = BZ2_bzCompress(bz, BZ_RUN);
- if (rc != BZ_RUN_OK) {
- BZ2_bzCompressEnd(bz);
- hctx->stream_open = 0;
- return -1;
- }
- if(p->conf.output_buffer_size > 0) flush = 0;
- }
-
- len = hctx->output->size - bz->avail_out;
- if(bz->avail_out == 0 || (flush && len > 0)) {
- out += len;
- chunkqueue_append_mem(hctx->out, hctx->output->ptr, len);
- hctx->out->bytes_in += len;
- bz->next_out = hctx->output->ptr;
- bz->avail_out = hctx->output->size;
- }
- } while (bz->avail_in != 0 || !done);
- if(p->conf.debug) {
- TRACE("flush: in=%i, out=%i", in, out);
- }
- if(p->conf.sync_flush) {
- bz->next_out = NULL;
- bz->avail_out = 0;
- }
- return 0;
-}
-
-static int stream_bzip2_end(server *srv, connection *con, handler_ctx *hctx) {
- plugin_data *p = hctx->plugin_data;
- bz_stream *bz;
- int rc;
-
- UNUSED(p);
- UNUSED(srv);
- UNUSED(con);
-
- bz = &(hctx->bz);
- if(!hctx->stream_open) return 0;
- hctx->stream_open = 0;
-
- if ((rc = BZ2_bzCompressEnd(bz)) != BZ_OK) {
- if(rc == BZ_DATA_ERROR) return 0;
- ERROR("BZ2_bzCompressEnd error ret=%i", rc);
- return -1;
- }
- return 0;
-}
-
-#endif
-
-static int mod_deflate_compress(server *srv, connection *con, handler_ctx *hctx, unsigned char *start, off_t st_size) {
- int ret = -1;
- if(st_size == 0) return 0;
- switch(hctx->compression_type) {
-#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_GZIP:
- case HTTP_ACCEPT_ENCODING_DEFLATE:
- ret = stream_deflate_compress(srv, con, hctx, start, st_size);
- break;
-#endif
-#ifdef USE_BZ2LIB
- case HTTP_ACCEPT_ENCODING_BZIP2:
- ret = stream_bzip2_compress(srv, con, hctx, start, st_size);
- break;
-#endif
- default:
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-static int mod_deflate_stream_flush(server *srv, connection *con, handler_ctx *hctx, int end) {
- int ret = -1;
-
- if(hctx->bytes_in == 0) return 0;
- switch(hctx->compression_type) {
-#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_GZIP:
- case HTTP_ACCEPT_ENCODING_DEFLATE:
- ret = stream_deflate_flush(srv, con, hctx, end);
- break;
-#endif
-#ifdef USE_BZ2LIB
- case HTTP_ACCEPT_ENCODING_BZIP2:
- ret = stream_bzip2_flush(srv, con, hctx, end);
- break;
-#endif
- default:
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-static int mod_deflate_stream_end(server *srv, connection *con, handler_ctx *hctx) {
- int ret = -1;
- switch(hctx->compression_type) {
-#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_GZIP:
- case HTTP_ACCEPT_ENCODING_DEFLATE:
- ret = stream_deflate_end(srv, con, hctx);
- break;
-#endif
-#ifdef USE_BZ2LIB
- case HTTP_ACCEPT_ENCODING_BZIP2:
- ret = stream_bzip2_end(srv, con, hctx);
- break;
-#endif
- default:
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hctx, chunk *c, off_t st_size) {
- plugin_data *p = hctx->plugin_data;
- off_t abs_offset;
- off_t toSend;
- stat_cache_entry *sce = NULL;
- size_t we_want_to_mmap = 2 MByte;
- size_t we_want_to_send = st_size;
- char *start = NULL;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- ERROR("stat_cache_get_entry('%s') failed: %s",
- SAFE_BUF_STR(c->file.name), strerror(errno));
- return -1;
- }
-
- abs_offset = c->file.start + c->offset;
-
- if (c->file.length + c->file.start > sce->st.st_size) {
- ERROR("file '%s' was shrinked: was %ju, is %ju (%ju, %ju)",
- SAFE_BUF_STR(c->file.name), (intmax_t) c->file.length + c->file.start, (intmax_t) sce->st.st_size,
- (intmax_t) c->file.start, (intmax_t) c->offset);
-
- return -1;
- }
-
- we_want_to_send = st_size;
- /* 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 */
- size_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 + (off_t) 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 (-1 == c->file.fd) { /* open the file if not already open */
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
- ERROR("open failed for '%s': %s", SAFE_BUF_STR(c->file.name), strerror(errno));
- return -1;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
- }
-
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
- /* close it here, otherwise we'd have to set FD_CLOEXEC */
-
- ERROR("mmap failed for '%s' (%i): %s", SAFE_BUF_STR(c->file.name), c->file.fd, strerror(errno));
- return -1;
- }
-
- c->file.mmap.length = to_mmap;
-#ifdef LOCAL_BUFFERING
- buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
-#else
-#ifdef HAVE_MADVISE
- /* don't advise files < 64Kb */
- if (c->file.mmap.length > (64 KByte) &&
- 0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) {
- ERROR("madvise failed for '%s' (%i): %s", SAFE_BUF_STR(c->file.name), c->file.fd, strerror(errno));
- }
-#endif
-#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 > (off_t) we_want_to_send) toSend = we_want_to_send;
-
- if (toSend < 0) {
- ERROR("toSend is negative: %u %u %u %u",
- (unsigned int) toSend,
- (unsigned int) c->file.mmap.length,
- (unsigned int) abs_offset,
- (unsigned int) c->file.mmap.offset);
- assert(toSend < 0);
- }
-
-#ifdef LOCAL_BUFFERING
- start = c->mem->ptr;
-#else
- start = c->file.mmap.start;
-#endif
-
- if(p->conf.debug) {
- TRACE("compress file chunk: offset=%i, toSend=%i", (int)c->offset, (int)toSend);
- }
- if (mod_deflate_compress(srv, con, hctx,
- (unsigned char *)start + (abs_offset - c->file.mmap.offset), toSend) < 0) {
- ERROR("%s", "compress failed.");
- return -1;
- }
-
- return toSend;
-}
-
-static int deflate_compress_cleanup(server *srv, connection *con, handler_ctx *hctx) {
- plugin_data *p = hctx->plugin_data;
- int rc;
-
- rc = mod_deflate_stream_end(srv, con, hctx);
- if(rc < 0) {
- TRACE("error closing compressed stream for '%s', compressing with %d: %d",
- SAFE_BUF_STR(con->uri.path_raw), hctx->compression_type, rc);
- }
-
- if(p->conf.debug && hctx->bytes_in < hctx->out->bytes_in) {
- TRACE("compressing uri '%s' increased the sent content-size from %jd to %jd",
- SAFE_BUF_STR(con->uri.path_raw), (intmax_t) hctx->bytes_in, (intmax_t) hctx->out->bytes_in);
- }
-
- /* cleanup compression state */
- if(hctx->output != p->tmp_buf) {
- buffer_free(hctx->output);
- }
- handler_ctx_free(hctx);
- con->plugin_ctx[p->id] = NULL;
-
- return 0;
-}
-
-/**
- * compress the in queue and move the content to the out queue
- *
- */
-static handler_t deflate_compress_response(server *srv, connection *con, handler_ctx *hctx, int end) {
- plugin_data *p = hctx->plugin_data;
- chunk *c;
- size_t chunks_written = 0;
- int chunk_finished = 0;
- int rc=-1;
- int we_want = 0, we_have = 0;
- int out = 0, max = 0;
-
- we_have = chunkqueue_length(hctx->in);
- if (p->conf.debug) {
- TRACE("compress: in_queue len=%i", we_have);
- }
- /* calculate max bytes to compress for this call. */
- if (!end) {
- max = p->conf.work_block_size * 1024;
- if(max == 0 || max > we_have) max = we_have;
- } else {
- max = we_have;
- }
-
- /* Compress chunks from in queue into chunks for out queue */
- for (c = hctx->in->first; c && max > 0; c = c->next) {
- chunk_finished = 0;
- we_have = 0;
- we_want = 0;
-
- switch(c->type) {
- case MEM_CHUNK:
- if (c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- if (we_have == 0) continue;
-
- we_want = we_have < max ? we_have : max;
-
- if (mod_deflate_compress(srv, con, hctx, (unsigned char *)(c->mem->ptr + c->offset), we_want) < 0) {
- ERROR("%s", "compress failed.");
- return HANDLER_ERROR;
- }
-
- break;
- case FILE_CHUNK:
- if (c->file.length == 0) continue;
-
- we_have = c->file.length - c->offset;
- if (we_have == 0) continue;
-
- we_want = we_have < max ? we_have : max;
-
- if ((we_want = mod_deflate_file_chunk(srv, con, hctx, c, we_want)) < 0) {
- ERROR("%s", "compress file chunk failed.");
- return HANDLER_ERROR;
- }
-
- break;
- default:
- ERROR("type not known: %d", c->type);
-
- return HANDLER_ERROR;
- }
-
- hctx->in->bytes_out += we_want;
- c->offset += we_want;
- out += we_want;
- max -= we_want;
-
- if (c->type == FILE_CHUNK &&
- c->offset == c->file.length &&
- c->file.mmap.start != MAP_FAILED) {
- /* we don't need the mmaping anymore */
- munmap(c->file.mmap.start, c->file.mmap.length);
- c->file.mmap.start = MAP_FAILED;
- }
-
- if (we_have == we_want) {
- /* chunk finished */
- chunk_finished = 1;
- chunks_written++;
- }
- /* make sure we finished compressing the chunk before going to the next chunk */
- if(!chunk_finished) break;
- }
-
- if (p->conf.debug) {
- TRACE("compressed bytes: %i", out);
- }
-
- if (chunks_written > 0) {
- chunkqueue_remove_finished_chunks(hctx->in);
- }
-
- /* check if we finished compressing all the content. */
- end = (hctx->in->is_closed && hctx->in->bytes_in == hctx->in->bytes_out);
-
- if (p->conf.debug) {
- TRACE("end: %d - %jd - %jd", hctx->in->is_closed, (intmax_t) hctx->in->bytes_in, (intmax_t) hctx->in->bytes_out);
- }
-
- /* flush the output buffer to make room for more data. */
- rc = mod_deflate_stream_flush(srv, con, hctx, end);
-
- if (rc < 0) {
- ERROR("%s", "flush error");
- }
-
- if (end) {
- hctx->out->is_closed = 1;
- if(p->conf.debug) {
- TRACE("finished uri: '%s', query: '%s'", SAFE_BUF_STR(con->uri.path_raw), SAFE_BUF_STR(con->uri.query));
- }
- } else if (hctx->in->first) {
- /* We have more data to compress. */
- joblist_append(srv, con);
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(output_buffer_size);
- PATCH_OPTION(mimetypes);
- PATCH_OPTION(compression_level);
- PATCH_OPTION(mem_level);
- PATCH_OPTION(window_size);
- PATCH_OPTION(min_compress_size);
- PATCH_OPTION(work_block_size);
- PATCH_OPTION(enabled);
- PATCH_OPTION(debug);
- PATCH_OPTION(allowed_encodings);
- PATCH_OPTION(sync_flush);
-
- /* 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_DEFLATE_OUTPUT_BUFFER_SIZE))) {
- PATCH_OPTION(output_buffer_size);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_MIMETYPES))) {
- PATCH_OPTION(mimetypes);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_COMPRESSION_LEVEL))) {
- PATCH_OPTION(compression_level);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_MEM_LEVEL))) {
- PATCH_OPTION(mem_level);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_WINDOW_SIZE))) {
- PATCH_OPTION(window_size);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_MIN_COMPRESS_SIZE))) {
- PATCH_OPTION(min_compress_size);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_WORK_BLOCK_SIZE))) {
- PATCH_OPTION(work_block_size);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_ENABLED))) {
- PATCH_OPTION(enabled);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_DEBUG))) {
- PATCH_OPTION(debug);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_ALLOWED_ENCODINGS))) {
- PATCH_OPTION(allowed_encodings);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEFLATE_SYNC_FLUSH))) {
- PATCH_OPTION(sync_flush);
- }
- }
- }
-
- return 0;
-}
-
-PHYSICALPATH_FUNC(mod_deflate_handle_response_header) {
- plugin_data *p = p_d;
- handler_ctx *hctx;
- filter *fl;
- chunkqueue *in;
- data_string *ds;
- int accept_encoding = 0;
- char *value;
- int matched_encodings = 0;
- const char *compression_name = NULL;
- int file_len=0;
- int rc=-2;
- int end = 0;
- size_t m;
-
- /* 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);
-
- /* is compression allowed */
- if(!p->conf.enabled) {
- if(p->conf.debug) {
- TRACE("%s", "compression disabled.");
- }
- return HANDLER_GO_ON;
- }
-
- /* Check if response has a Content-Encoding. */
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("Content-Encoding")))) {
- return HANDLER_GO_ON;
- }
-
- /* Check Accept-Encoding for supported encoding. */
- if (NULL == (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Accept-Encoding")))) {
- return HANDLER_GO_ON;
- }
-
- /* get client side support encodings */
- value = ds->value->ptr;
-#ifdef USE_ZLIB
- if (NULL != strstr(value, ENCODING_NAME_GZIP)) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
- if (NULL != strstr(value, ENCODING_NAME_DEFLATE)) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
-#endif
- /* if (NULL != strstr(value, ENCODING_NAME_COMPRESS)) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; */
-#ifdef USE_BZ2LIB
- if (NULL != strstr(value, ENCODING_NAME_BZIP2)) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
-#endif
- if (NULL != strstr(value, ENCODING_NAME_IDENTITY)) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
-
- /* find matching encodings */
- matched_encodings = accept_encoding & p->conf.allowed_encodings;
- if (!matched_encodings) {
- return HANDLER_GO_ON;
- }
-
-#if 0
- /* TODO: add option to disable compression for HTTP 1.0 clients. */
- if (con->request.true_http_10_client) {
- /*disable gzip/bzip2 when we meet HTTP 1.0 client with Accept-Encoding
- * maybe old buggy proxy server
- */
- /* most of buggy clients are Yahoo Slurp;) */
- if (p->conf.debug) TRACE("Buggy HTTP 1.0 client sending 'Accept Encoding: gzip, deflate': %i",
- (char *) inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
- return HANDLER_GO_ON;
- }
-#endif
-
- /* get filter. */
- fl = filter_chain_get_filter(con->send_filters, p->id);
- if (!fl) {
- if(p->conf.debug) TRACE("%s", "add deflate filter to filter chain");
- fl = filter_chain_create_filter(con->send_filters, p->id);
- }
- /* get our input and output chunkqueues. */
- if (!fl || !fl->prev) {
- filter_chain_remove_filter(con->send_filters, fl);
- return HANDLER_GO_ON;
- }
- in = fl->prev->cq;
-
- /* check if size of response is below min-compress-size */
- if(in->is_closed && con->request.http_method != HTTP_METHOD_HEAD) {
- file_len = chunkqueue_length(in);
- if(file_len == 0) {
- filter_chain_remove_filter(con->send_filters, fl);
- return HANDLER_GO_ON;
- }
- } else {
- file_len = 0;
- }
-
- if(file_len > 0 && p->conf.min_compress_size > 0 && file_len < p->conf.min_compress_size) {
- if(p->conf.debug) {
- TRACE("Content-Length smaller then min_compress_size: file_len=%i", file_len);
- }
- filter_chain_remove_filter(con->send_filters, fl);
- return HANDLER_GO_ON;
- }
-
- /* Check mimetype in response header "Content-Type" */
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("Content-Type")))) {
- int found = 0;
- if(p->conf.debug) {
- TRACE("Content-Type: %s", SAFE_BUF_STR(ds->value));
- }
- for (m = 0; m < p->conf.mimetypes->used; m++) {
- data_string *mimetype = (data_string *)p->conf.mimetypes->data[m];
-
- if(p->conf.debug) {
- TRACE("mime-type: %s", SAFE_BUF_STR(mimetype->value));
- }
- if (strncmp(mimetype->value->ptr, ds->value->ptr, mimetype->value->used-1) == 0) {
- /* mimetype found */
- found = 1;
- break;
- }
- }
- if(!found && p->conf.mimetypes->used > 0) {
- if(p->conf.debug) {
- TRACE("No compression for mimetype: %s", SAFE_BUF_STR(ds->value));
- }
- filter_chain_remove_filter(con->send_filters, fl);
- return HANDLER_GO_ON;
- }
-#if 0
- if(strncasecmp(ds->value->ptr, "application/x-javascript", 24) == 0) {
- /*reset compress type to deflate for javascript
- * prevent buggy IE6 SP1 doesn't work for js in IFrame
- */
- matched_encodings = HTTP_ACCEPT_ENCODING_DEFLATE;
- }
-#endif
- }
-
- /* the response might change according to Accept-Encoding */
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("Vary")))) {
- /* append Accept-Encoding to Vary header */
- if (NULL == strstr(ds->value->ptr, "Accept-Encoding")) {
- buffer_append_string_len(ds->value, CONST_STR_LEN(",Accept-Encoding"));
- if (p->conf.debug) {
- TRACE("appending ,Accept-Encoding for '%s'", SAFE_BUF_STR(con->uri.path));
- }
- }
- } else {
- if (p->conf.debug) {
- TRACE("add Vary: Accept-Encoding for '%s'", SAFE_BUF_STR(con->uri.path));
- }
- response_header_insert(srv, con, CONST_STR_LEN("Vary"),
- CONST_STR_LEN("Accept-Encoding"));
- }
-
- /* enable compression */
- hctx = handler_ctx_init();
- hctx->plugin_data = p;
- hctx->fl = fl;
- hctx->in = fl->prev->cq;
- hctx->out = fl->cq;
-
- rc = -1;
-
- /* select best matching encoding */
- if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
-#ifdef USE_BZ2LIB
- hctx->compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
- compression_name = ENCODING_NAME_BZIP2;
- rc = stream_bzip2_init(srv, con, hctx);
-#endif
- } else if (matched_encodings & HTTP_ACCEPT_ENCODING_GZIP) {
-#ifdef USE_ZLIB
- hctx->compression_type = HTTP_ACCEPT_ENCODING_GZIP;
- compression_name = ENCODING_NAME_GZIP;
- rc = stream_deflate_init(srv, con, hctx);
- } else if (matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE) {
- hctx->compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
- compression_name = ENCODING_NAME_DEFLATE;
- rc = stream_deflate_init(srv, con, hctx);
-#endif
- } else if (matched_encodings & HTTP_ACCEPT_ENCODING_IDENTITY) {
- /* no compression */
- } else {
- ERROR("Failed to initialize compression for '%s' with compression = %s",
- SAFE_BUF_STR(con->uri.path),
- value);
- }
-
- if (rc == -1 && compression_name) {
- ERROR("Failed to initialize compression for '%s' with compression = %s",
- SAFE_BUF_STR(con->uri.path),
- compression_name);
- }
-
- if (rc < 0) {
- filter_chain_remove_filter(con->send_filters, hctx->fl);
- handler_ctx_free(hctx);
- return HANDLER_GO_ON;
- }
-
- if (p->conf.debug) {
- TRACE("compressing '%s' with compression = %s",
- SAFE_BUF_STR(con->uri.path),
- compression_name);
- }
-
- /* setup output buffer. */
- if(p->conf.sync_flush || p->conf.output_buffer_size == 0) {
- buffer_prepare_copy(p->tmp_buf, 32 * 1024);
- hctx->output = p->tmp_buf;
- } else {
- hctx->output = buffer_init();
- buffer_prepare_copy(hctx->output, p->conf.output_buffer_size);
- }
- con->plugin_ctx[p->id] = hctx;
-
- /* set Content-Encoding to show selected compression type. */
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
-
- /* clear old Content-Length */
- con->response.content_length = -1;
-
- if (hctx->in->is_closed &&
- (p->conf.work_block_size == 0 || file_len < (p->conf.work_block_size * 1024))
- && con->request.http_method != HTTP_METHOD_HEAD) {
- end = 1;
- if(p->conf.debug) {
- TRACE("Compress all content and use Content-Length header: uncompress len=%i", file_len);
- }
- }
-
- if (p->conf.debug)
- TRACE("end = %i for uri '%s'", end, SAFE_BUF_STR(con->uri.path));
-
- rc = deflate_compress_response(srv, con, hctx, end);
- /* check if we finished compressing all the content. */
- if (rc == HANDLER_GO_ON && hctx->out->is_closed) {
- con->response.content_length = chunkqueue_length(hctx->out);
-
- deflate_compress_cleanup(srv, con, hctx);
- }
-
- return rc;
-}
-
-CONNECTION_FUNC(mod_deflate_handle_filter_response_content) {
- plugin_data *p = p_d;
- handler_ctx *hctx = con->plugin_ctx[p->id];
- handler_t ret;
-
- if (hctx == NULL) return HANDLER_GO_ON;
- if (!hctx->stream_open) return HANDLER_GO_ON;
-
- /**
- * HEAD requests don't have a content body */
- if (con->request.http_method == HTTP_METHOD_HEAD) return HANDLER_GO_ON;
-
- /** compress the streams */
- ret = deflate_compress_response(srv, con, hctx, 0);
-
- if (ret == HANDLER_GO_ON && hctx->out->is_closed) {
- deflate_compress_cleanup(srv, con, hctx);
- }
-
- return ret;
-}
-
-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(hctx == NULL) return HANDLER_GO_ON;
-
- if(p->conf.debug && hctx->stream_open) {
- TRACE("stream open at cleanup. uri='%s', query='%s'", SAFE_BUF_STR(con->uri.path_raw), SAFE_BUF_STR(con->uri.query));
- }
-
- deflate_compress_cleanup(srv, con, hctx);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_deflate_plugin_init(plugin *p);
-LI_EXPORT 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_connection_close = mod_deflate_cleanup;
- p->handle_response_header = mod_deflate_handle_response_header;
- p->handle_filter_response_content = mod_deflate_handle_filter_response_content;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
deleted file mode 100644
index 63f412dc..00000000
--- a/src/mod_dirlisting.c
+++ /dev/null
@@ -1,957 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <time.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "response.h"
-#include "stat_cache.h"
-#include "stream.h"
-#include "etag.h"
-
-#include "sys-strings.h"
-
-/**
- * this is a dirlisting for a lighttpd plugin
- */
-
-
-#ifdef HAVE_SYS_SYSLIMITS_H
-#include <sys/syslimits.h>
-#endif
-
-#ifdef HAVE_XATTR
-#include <attr/attributes.h>
-#endif
-
-#include "sys-files.h"
-#include "sys-strings.h"
-
-/* 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 show_readme;
- unsigned short hide_readme_file;
- unsigned short show_header;
- unsigned short hide_header_file;
-
- excludes_buffer *excludes;
-
- buffer *external_css;
- buffer *encoding;
- buffer *set_footer;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
- buffer *content_charset;
- buffer *path;
-
- 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;
-}
-
-static int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
-#ifdef HAVE_PCRE_H
- 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_string_buffer(exb->ptr[exb->used]->string, string);
-
- exb->used++;
-
- return 0;
-#else
- UNUSED(exb);
- UNUSED(string);
-
- return -1;
-#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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
- p->content_charset = buffer_init();
- p->path = buffer_init();
-
- return p;
-}
-
-/* destroy the plugin data */
-FREE_FUNC(mod_dirlisting_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- excludes_buffer_free(s->excludes);
- buffer_free(s->external_css);
- buffer_free(s->encoding);
- buffer_free(s->set_footer);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->tmp_buf);
- buffer_free(p->path);
- buffer_free(p->content_charset);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option) {
- data_unset *du;
-
- if (NULL != (du = array_get_element(ca, option, strlen(option)))) {
- data_array *da = (data_array *)du;
- size_t j;
-
- if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "unexpected type for key: ", option, "array of strings");
-
- return HANDLER_ERROR;
- }
-
- da = (data_array *)du;
-
- for (j = 0; j < da->value->used; j++) {
- if (da->value->data[j]->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ", option, "[",
- da->value->data[j]->key, "](string)");
-
- return HANDLER_ERROR;
- }
-
- if (0 != excludes_buffer_append(s->excludes,
- ((data_string *)(da->value->data[j]))->value)) {
-#ifdef HAVE_PCRE_H
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
-#else
- log_error_write(srv, __FILE__, __LINE__, "s",
- "pcre support is missing, please install libpcre and the headers");
-#endif
- }
- }
- }
-
- return 0;
-}
-
-/* handle plugin config and check values */
-
-#define CONFIG_EXCLUDE "dir-listing.exclude"
-#define CONFIG_ACTIVATE "dir-listing.activate"
-#define CONFIG_HIDE_DOTFILES "dir-listing.hide-dotfiles"
-#define CONFIG_EXTERNAL_CSS "dir-listing.external-css"
-#define CONFIG_ENCODING "dir-listing.encoding"
-#define CONFIG_SHOW_README "dir-listing.show-readme"
-#define CONFIG_HIDE_README_FILE "dir-listing.hide-readme-file"
-#define CONFIG_SHOW_HEADER "dir-listing.show-header"
-#define CONFIG_HIDE_HEADER_FILE "dir-listing.hide-header-file"
-#define CONFIG_DIR_LISTING "server.dir-listing"
-#define CONFIG_SET_FOOTER "dir-listing.set-footer"
-
-
-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_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { CONFIG_HIDE_README_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { CONFIG_SHOW_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { CONFIG_HIDE_HEADER_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { CONFIG_DIR_LISTING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
- { CONFIG_SET_FOOTER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
-
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- array *ca;
-
- s = calloc(1, sizeof(plugin_config));
- s->excludes = excludes_buffer_init();
- s->dir_listing = 0;
- s->external_css = buffer_init();
- s->hide_dot_files = 0;
- s->show_readme = 0;
- s->hide_readme_file = 0;
- s->show_header = 0;
- s->hide_header_file = 0;
- 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;
-
- p->config_storage[i] = s;
- ca = ((data_config *)srv->config_context->data[i])->value;
-
- if (0 != config_insert_values_global(srv, ca, cv)) {
- return HANDLER_ERROR;
- }
-
- parse_config_entry(srv, s, ca, CONFIG_EXCLUDE);
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(dir_listing);
- PATCH_OPTION(external_css);
- PATCH_OPTION(hide_dot_files);
- PATCH_OPTION(encoding);
- PATCH_OPTION(show_readme);
- PATCH_OPTION(hide_readme_file);
- PATCH_OPTION(show_header);
- PATCH_OPTION(hide_header_file);
- PATCH_OPTION(excludes);
- PATCH_OPTION(set_footer);
-
- /* 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_OPTION(dir_listing);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_DOTFILES))) {
- PATCH_OPTION(hide_dot_files);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXTERNAL_CSS))) {
- PATCH_OPTION(external_css);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODING))) {
- PATCH_OPTION(encoding);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_README))) {
- PATCH_OPTION(show_readme);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_README_FILE))) {
- PATCH_OPTION(hide_readme_file);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_HEADER))) {
- PATCH_OPTION(show_header);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_HEADER_FILE))) {
- PATCH_OPTION(hide_header_file);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SET_FOOTER))) {
- PATCH_OPTION(set_footer);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXCLUDE))) {
- PATCH_OPTION(excludes);
- }
- }
- }
-
- return 0;
-}
-
-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, off_t size) {
- const char unit[] = "KMGTPE"; /* Kilo, Mega, Tera, Peta, Exa */
- const char *u = unit - 1; /* u will always increment at least once */
- int remain;
- char *out = buf;
-
- 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++;
- }
-
- out += LI_ltostr(out, size);
- out[0] = '.';
- out[1] = remain + '0';
- out[2] = *u;
- out[3] = '\0';
-
- return (out + 3 - buf);
-}
-
-static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
- UNUSED(srv);
-
- buffer_append_string_len(out, CONST_STR_LEN(
- "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
- "<head>\n"
- "<title>Index of "
- ));
- buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
- buffer_append_string_len(out, CONST_STR_LEN("</title>\n"));
-
- if (p->conf.external_css->used > 1) {
- buffer_append_string_len(out, CONST_STR_LEN("<link rel=\"stylesheet\" type=\"text/css\" href=\""));
- buffer_append_string_buffer(out, p->conf.external_css);
- buffer_append_string_len(out, CONST_STR_LEN("\" />\n"));
- } else {
- buffer_append_string_len(out, CONST_STR_LEN(
- "<style type=\"text/css\">\n"
- "a, a:active {text-decoration: none; color: blue;}\n"
- "a:visited {color: #48468F;}\n"
- "a:hover, a:focus {text-decoration: underline; color: red;}\n"
- "body {background-color: #F5F5F5;}\n"
- "h2 {margin-bottom: 12px;}\n"
- "table {margin-left: 12px;}\n"
- "th, td {"
- " font: 90% monospace;"
- " text-align: left;"
- "}\n"
- "th {"
- " font-weight: bold;"
- " padding-right: 14px;"
- " padding-bottom: 3px;"
- "}\n"
-
- "td {padding-right: 14px;}\n"
- "td.s, th.s {text-align: right;}\n"
- "div.list {"
- " background-color: white;"
- " border-top: 1px solid #646464;"
- " border-bottom: 1px solid #646464;"
- " padding-top: 10px;"
- " padding-bottom: 14px;"
- "}\n"
- "div.foot {"
- " font: 90% monospace;"
- " color: #787878;"
- " padding-top: 4px;"
- "}\n"
- "</style>\n"
- ));
- }
-
- buffer_append_string_len(out, CONST_STR_LEN("</head>\n<body>\n"));
-
- /* HEADER.txt */
- if (p->conf.show_header) {
- stream s;
- /* if we have a HEADER file, display it in <pre class="header"></pre> */
-
- buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
- PATHNAME_APPEND_SLASH(p->tmp_buf);
- buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("HEADER.txt"));
-
- if (-1 != stream_open(&s, p->tmp_buf)) {
- buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"header\">"));
- buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
- buffer_append_string_len(out, CONST_STR_LEN("</pre>"));
- }
- stream_close(&s);
- }
-
- 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"
- "<tr>"
- "<td class=\"n\"><a href=\"../\">Parent Directory</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 (p->conf.show_readme) {
- stream s;
- /* if we have a README file, display it in <pre class="readme"></pre> */
-
- buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
- PATHNAME_APPEND_SLASH(p->tmp_buf);
- buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt"));
-
- if (-1 != stream_open(&s, p->tmp_buf)) {
- buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"readme\">"));
- buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
- buffer_append_string_len(out, CONST_STR_LEN("</pre>"));
- }
- stream_close(&s);
- }
-
- buffer_append_string_len(out, CONST_STR_LEN(
- "<div class=\"foot\">"
- ));
-
- if (p->conf.set_footer->used > 1) {
- buffer_append_string_buffer(out, p->conf.set_footer);
- } else if (buffer_is_empty(con->conf.server_tag)) {
- buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_NAME "/" PACKAGE_VERSION));
- } else {
- buffer_append_string_buffer(out, con->conf.server_tag);
- }
-
- buffer_append_string_len(out, CONST_STR_LEN(
- "</div>\n"
- "</body>\n"
- "</html>\n"
- ));
-}
-
-static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) {
- DIR *dp;
- buffer *out;
- struct dirent *dent;
- struct stat st;
- 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")];
- size_t k;
- const char *content_type;
- long name_max;
-
-#ifdef HAVE_XATTR
- char attrval[128];
- int attrlen;
-#endif
-#ifdef HAVE_LOCALTIME_R
- struct tm tm;
-#endif
-
- /* empty pathname, never ... */
- if (buffer_is_empty(dir)) return -1;
-
- /* max-length for the opendir */
-#ifdef HAVE_PATHCONF
- if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
-#ifdef NAME_MAX
- name_max = NAME_MAX;
-#else
- name_max = 256; /* stupid default */
-#endif
- }
-#elif defined _WIN32
- name_max = FILENAME_MAX;
-#else
- name_max = NAME_MAX;
-#endif
-
- buffer_copy_string_buffer(p->path, dir);
- PATHNAME_APPEND_SLASH(p->path);
-
-#ifdef _WIN32
- /* append *.* to the path */
- buffer_append_string_len(p->path, CONST_STR_LEN("*.*"));
-#endif
-
- if (NULL == (dp = opendir(p->path->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "opendir failed:", dir, strerror(errno));
-
- return -1;
- }
-
- dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
- assert(dirs.ent);
- dirs.size = DIRLIST_BLOB_SIZE;
- dirs.used = 0;
- files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
- assert(files.ent);
- files.size = DIRLIST_BLOB_SIZE;
- files.used = 0;
-
- while ((dent = readdir(dp)) != NULL) {
- unsigned short exclude_match = 0;
-
- 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) {
- if (strcmp(dent->d_name, "README.txt") == 0)
- continue;
- }
- if (p->conf.hide_header_file) {
- if (strcmp(dent->d_name, "HEADER.txt") == 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);
-
- return -1;
- }
- }
- 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;
-
- /* build the dirname */
- buffer_copy_string_buffer(p->path, dir);
- PATHNAME_APPEND_SLASH(p->path);
- buffer_append_string(p->path, dent->d_name);
-
- if (stat(p->path->ptr, &st) != 0) {
- fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
- 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);
- 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_get_append_buffer(con->send);
- buffer_copy_string_len(out, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\""));
- if (buffer_is_empty(p->conf.encoding)) {
- buffer_append_string_len(out, CONST_STR_LEN("iso-8859-1"));
- } else {
- buffer_append_string_buffer(out, p->conf.encoding);
- }
- buffer_append_string_len(out, CONST_STR_LEN("\"?>\n"));
- 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><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;
-
-#ifdef HAVE_XATTR
- if (con->conf.use_xattr) {
- /* build the dirname */
- buffer_copy_string_buffer(p->path, dir);
- PATHNAME_APPEND_SLASH(p->path);
- buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
-
- attrlen = sizeof(attrval) - 1;
- if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
- attrval[attrlen] = '\0';
- content_type = attrval;
- }
- }
-#endif
-
- if (content_type == NULL) {
- content_type = "application/octet-stream";
- for (k = 0; k < con->conf.mimetypes->used; k++) {
- data_string *ds = (data_string *)con->conf.mimetypes->data[k];
- size_t ct_len;
-
- if (ds->key->used == 0)
- continue;
-
- ct_len = ds->key->used - 1;
- if (tmp->namelen < ct_len)
- continue;
-
- if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) {
- content_type = ds->value->ptr;
- break;
- }
- }
- }
-
-#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, 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);
-
- http_list_directory_footer(srv, con, p, out);
-
- /* Insert possible charset to Content-Type */
- if (buffer_is_empty(p->conf.encoding)) {
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- } else {
- buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset="));
- buffer_append_string_buffer(p->content_charset, p->conf.encoding);
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
- }
-
- con->send->bytes_in += out->used - 1;
-
- con->send->is_closed = 1;
-
- return 0;
-}
-
-
-
-URIHANDLER_FUNC(mod_dirlisting_subrequest) {
- plugin_data *p = p_d;
- stat_cache_entry *sce = NULL;
- buffer *mtime;
- data_string *ds;
-
- /* we only handle GET, POST and HEAD */
- switch(con->request.http_method) {
- case HTTP_METHOD_GET:
- case HTTP_METHOD_POST:
- case HTTP_METHOD_HEAD:
- break;
- default:
- return HANDLER_GO_ON;
- }
-
- if (con->uri.path->used < 2) return HANDLER_GO_ON;
- if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
- if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
- mod_dirlisting_patch_connection(srv, con, p);
-
- if (!p->conf.dir_listing) return HANDLER_GO_ON;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- /* just a second ago the file was still there */
- return HANDLER_GO_ON;
- }
-
- if (!S_ISDIR(sce->st.st_mode)) 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);
- }
-
- /* perhaps this a cachable request
- * - we use the etag of the directory
- * */
-
- etag_mutate(con->physical.etag, sce->etag);
- response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
-
- /* prepare header */
- if (NULL == (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("Last-Modified")))) {
- mtime = strftime_cache_get(srv, sce->st.st_mtime);
- response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
- } else {
- mtime = ds->value;
- }
-
- if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
- return HANDLER_FINISHED;
- }
-
- if (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 */
-
-LI_EXPORT int mod_dirlisting_plugin_init(plugin *p);
-LI_EXPORT 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_start_backend = mod_dirlisting_subrequest;
- p->set_defaults = mod_dirlisting_set_defaults;
- p->cleanup = mod_dirlisting_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_evasive.c b/src/mod_evasive.c
deleted file mode 100644
index 1c0e5586..00000000
--- a/src/mod_evasive.c
+++ /dev/null
@@ -1,200 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "inet_ntop_cache.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;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-INIT_FUNC(mod_evasive_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-FREE_FUNC(mod_evasive_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->max_conns = 0;
-
- cv[0].destination = &(s->max_conns);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(max_conns);
-
- /* 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_OPTION(max_conns);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_evasive_uri_handler) {
- plugin_data *p = p_d;
- size_t conns_by_ip = 0;
- size_t j;
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_evasive_patch_connection(srv, con, p);
-
- /* no limit set, nothing to block */
- if (p->conf.max_conns == 0) return HANDLER_GO_ON;
-
- switch (con->dst_addr.plain.sa_family) {
- case AF_INET:
-#ifdef HAVE_IPV6
- case AF_INET6:
-#endif
- break;
- default: // Address family not supported
- return HANDLER_GO_ON;
- };
-
- for (j = 0; j < srv->conns->used; j++) {
- connection *c = srv->conns->ptr[j];
-
- /* check if other connections are already actively serving data for the same IP
- * we can only ban connections which are already behind the 'read request' state
- * */
- if (c->dst_addr.plain.sa_family != con->dst_addr.plain.sa_family) continue;
- if (c->state <= CON_STATE_HANDLE_REQUEST_HEADER) continue;
-
- switch (con->dst_addr.plain.sa_family) {
- case AF_INET:
- if (c->dst_addr.ipv4.sin_addr.s_addr != con->dst_addr.ipv4.sin_addr.s_addr) continue;
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- if (0 != memcmp(c->dst_addr.ipv6.sin6_addr.s6_addr, con->dst_addr.ipv6.sin6_addr.s6_addr, 16)) continue;
- break;
-#endif
- default: // Address family not supported, should never be reached
- continue;
- };
- conns_by_ip++;
-
- if (conns_by_ip > p->conf.max_conns) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
- "turned away. Too many connections.");
-
- con->http_status = 403;
- return HANDLER_FINISHED;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-
-LI_EXPORT int mod_evasive_plugin_init(plugin *p);
-LI_EXPORT int mod_evasive_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("evasive");
-
- p->init = mod_evasive_init;
- p->set_defaults = mod_evasive_set_defaults;
- p->handle_uri_clean = mod_evasive_uri_handler;
- p->cleanup = mod_evasive_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_evhost.c b/src/mod_evhost.c
deleted file mode 100644
index 8b8d016e..00000000
--- a/src/mod_evhost.c
+++ /dev/null
@@ -1,347 +0,0 @@
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include "plugin.h"
-#include "log.h"
-#include "response.h"
-#include "stat_cache.h"
-
-#include "sys-files.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;
-
- UNUSED(srv);
-
- 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 (!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 void mod_evhost_parse_pattern(plugin_config *s) {
- char *ptr = s->path_pieces_raw->ptr,*pos;
-
- s->path_pieces = NULL;
-
- for(pos=ptr;*ptr;ptr++) {
- if(*ptr == '%') {
- s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
- s->path_pieces[s->len] = buffer_init();
- s->path_pieces[s->len+1] = buffer_init();
-
- buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
- pos = ptr + 2;
-
- buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
-
- s->len += 2;
- }
- }
-
- if(*pos != '\0') {
- s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
- s->path_pieces[s->len] = buffer_init();
-
- buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
-
- s->len += 1;
- }
-}
-
-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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->path_pieces_raw = buffer_init();
- s->path_pieces = NULL;
- s->len = 0;
-
- cv[0].destination = s->path_pieces_raw;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (s->path_pieces_raw->used != 0) {
- mod_evhost_parse_pattern(s);
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * assign the different parts of the domain to array-indezes (sub2.sub1.domain.tld)
- * - %0 - domain.tld
- * - %1 - tld
- * - %2 - domain
- * - %3 - sub1
- * - ...
- */
-
-static int mod_evhost_parse_host(connection *con,array *host) {
- /* con->uri.authority->used is always > 0 if we come here */
- register char *ptr = con->uri.authority->ptr + con->uri.authority->used - 1;
- char *colon = ptr; /* needed to filter out the colon (if exists) */
- int first = 1;
- data_string *ds;
- int i;
-
- /* first, find the domain + tld */
- for(;ptr > con->uri.authority->ptr;ptr--) {
- if(*ptr == '.') {
- if(first) first = 0;
- else break;
- } else if(*ptr == ':') {
- colon = ptr;
- first = 1;
- }
- }
-
- ds = data_string_init();
- buffer_copy_string_len(ds->key,CONST_STR_LEN("%0"));
-
- /* if we stopped at a dot, skip the dot */
- if (*ptr == '.') ptr++;
- buffer_copy_string_len(ds->value, ptr, colon-ptr);
-
- array_insert_unique(host,(data_unset *)ds);
-
- /* if the : is not the start of the authority, go on parsing the hostname */
-
- if (colon != con->uri.authority->ptr) {
- for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
- if(*ptr == '.') {
- if (ptr != colon - 1) {
- /* is something between the dots */
- ds = data_string_init();
- buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
- buffer_append_long(ds->key, i++);
- buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
-
- array_insert_unique(host,(data_unset *)ds);
- }
- colon = ptr;
- }
- }
-
- /* if the . is not the first charactor of the hostname */
- if (colon != ptr) {
- ds = data_string_init();
- buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
- buffer_append_long(ds->key, i++);
- buffer_copy_string_len(ds->value,ptr,colon-ptr);
-
- array_insert_unique(host,(data_unset *)ds);
- }
- }
-
- return 0;
-}
-
-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_OPTION(path_pieces);
- PATCH_OPTION(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_OPTION(path_pieces);
- PATCH_OPTION(len);
- }
- }
- }
-
- return 0;
-}
-
-static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
- size_t i;
- array *parsed_host;
- register char *ptr;
- int not_good = 0;
- stat_cache_entry *sce = NULL;
-
- /* not authority set */
- if (con->uri.authority->used == 0) return HANDLER_GO_ON;
-
- mod_evhost_patch_connection(srv, con, p);
-
- /* missing even default(global) conf */
- if (0 == p->conf.len) {
- return HANDLER_GO_ON;
- }
-
- parsed_host = array_init();
-
- mod_evhost_parse_host(con, parsed_host);
-
- /* build document-root */
- buffer_reset(p->tmp_buf);
-
- for (i = 0; i < p->conf.len; i++) {
- ptr = p->conf.path_pieces[i]->ptr;
- if (*ptr == '%') {
- data_string *ds;
-
- if (*(ptr+1) == '%') {
- /* %% */
- buffer_append_string_len(p->tmp_buf,CONST_STR_LEN("%"));
- } else if (*(ptr+1) == '_' ) {
- /* %_ == full hostname */
- char *colon = strchr(con->uri.authority->ptr, ':');
-
- if(colon == NULL) {
- buffer_append_string_buffer(p->tmp_buf, con->uri.authority); /* adds fqdn */
- } else {
- /* strip the port out of the authority-part of the URI scheme */
- buffer_append_string_len(p->tmp_buf, con->uri.authority->ptr, colon - con->uri.authority->ptr); /* adds fqdn */
- }
- } else if (NULL != (ds = (data_string *)array_get_element(parsed_host, CONST_BUF_LEN(p->conf.path_pieces[i])))) {
- if (ds->value->used) {
- buffer_append_string_buffer(p->tmp_buf,ds->value);
- }
- } else {
- /* unhandled %-sequence */
- }
- } else {
- buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
- }
- }
-
- PATHNAME_APPEND_SLASH(p->tmp_buf);
-
- array_free(parsed_host);
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
- not_good = 1;
- } else if(!S_ISDIR(sce->st.st_mode)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
- not_good = 1;
- }
-
- if (!not_good) {
- buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
- }
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_evhost_plugin_init(plugin *p);
-LI_EXPORT 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/src/mod_expire.c b/src/mod_expire.c
deleted file mode 100644
index c844deeb..00000000
--- a/src/mod_expire.c
+++ /dev/null
@@ -1,375 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-
-#include "plugin.h"
-#include "stat_cache.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;
-} 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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->expire_tstmp = buffer_init();
-
- buffer_prepare_copy(p->expire_tstmp, 255);
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_expire_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->expire_tstmp);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
- if (!s) continue;
-
- array_free(s->expire_url);
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, 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 (expire->used == 0) {
- 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 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->expire_url = array_init();
-
- cv[0].destination = s->expire_url;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- for (k = 0; k < s->expire_url->used; k++) {
- data_string *ds = (data_string *)s->expire_url->data[k];
-
- /* parse lines */
- if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing expire.url failed:", ds->value);
- return HANDLER_ERROR;
- }
- }
- }
-
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(expire_url);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
- PATCH_OPTION(expire_url);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_expire_path_handler) {
- plugin_data *p = p_d;
- int s_len;
- size_t k;
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_expire_patch_connection(srv, con, p);
-
- s_len = con->uri.path->used - 1;
-
- for (k = 0; k < p->conf.expire_url->used; k++) {
- data_string *ds = (data_string *)p->conf.expire_url->data[k];
- int ct_len = ds->key->used - 1;
-
- if (ct_len > s_len) continue;
- if (ds->key->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
- time_t ts, expires;
- size_t len;
-
- switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
- case 0:
- /* access */
- expires = (ts + srv->cur_ts);
- break;
- case 1: {
- /* modification */
- stat_cache_entry *sce = NULL;
-
- if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
-
- if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- /* it failed for some reason, just skip it */
- return HANDLER_GO_ON;
- }
-
- expires = (ts + sce->st.st_mtime);
-
- break; }
- default:
- /* -1 is handled at parse-time */
- break;
- }
-
- /* expires should be at least srv->cur_ts */
- if (expires < srv->cur_ts) expires = srv->cur_ts;
-
- if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires))))) {
- /* could not set expire header, out of mem */
-
- return HANDLER_GO_ON;
- }
-
- p->expire_tstmp->used = len + 1;
-
- /* HTTP/1.0 */
- response_header_overwrite(srv, con, 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_long(p->expire_tstmp, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
-
- response_header_append(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
-
- return HANDLER_GO_ON;
- }
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_expire_plugin_init(plugin *p);
-LI_EXPORT 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_header = mod_expire_path_handler;
- p->set_defaults = mod_expire_set_defaults;
- p->cleanup = mod_expire_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
deleted file mode 100644
index b527ad58..00000000
--- a/src/mod_flv_streaming.c
+++ /dev/null
@@ -1,322 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-#include "stat_cache.h"
-
-#include "plugin.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* plugin config for all request/connections */
-
-typedef struct {
- array *extensions;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- buffer *query_str;
- array *get_params;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-/* init the plugin data */
-INIT_FUNC(mod_flv_streaming_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->query_str = buffer_init();
- p->get_params = array_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_flv_streaming_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->extensions);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->query_str);
- array_free(p->get_params);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->extensions = array_init();
-
- cv[0].destination = s->extensions;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(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_OPTION(extensions);
- }
- }
- }
-
- return 0;
-}
-
-static int split_get_params(array *get_params, buffer *qrystr) {
- size_t is_key = 1;
- size_t i;
- char *key = NULL, *val = NULL;
-
- key = qrystr->ptr;
-
- /* we need the \0 */
- for (i = 0; i < qrystr->used; i++) {
- switch(qrystr->ptr[i]) {
- case '=':
- if (is_key) {
- val = qrystr->ptr + i + 1;
-
- qrystr->ptr[i] = '\0';
-
- is_key = 0;
- }
-
- break;
- case '&':
- case '\0': /* fin symbol */
- if (!is_key) {
- data_string *ds;
- /* we need at least a = since the last & */
-
- /* terminate the value */
- qrystr->ptr[i] = '\0';
-
- if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
- ds = data_string_init();
- }
- buffer_copy_string_len(ds->key, key, strlen(key));
- buffer_copy_string_len(ds->value, val, strlen(val));
-
- array_insert_unique(get_params, (data_unset *)ds);
- }
-
- key = qrystr->ptr + i + 1;
- val = NULL;
- is_key = 1;
- break;
- }
- }
-
- return 0;
-}
-
-/**
- *
- * @param
- */
-URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
- plugin_data *p = p_d;
- int s_len;
- size_t k;
-
- UNUSED(srv);
-
- if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
-
- if (con->conf.log_request_handling) {
- TRACE("-- handling %s in mod_flv_streaming", SAFE_BUF_STR(con->physical.path));
- }
-
- mod_flv_streaming_patch_connection(srv, con, p);
-
- s_len = con->physical.path->used - 1;
-
- for (k = 0; k < p->conf.extensions->used; k++) {
- data_string *ds = (data_string *)p->conf.extensions->data[k];
- int ct_len = ds->value->used - 1;
-
- if (ct_len > s_len) continue;
- if (ds->value->used == 0) continue;
-
- if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- data_string *get_param;
- stat_cache_entry *sce = NULL;
- buffer *b;
- long start;
- char *err = NULL;
- /* if there is a start=[0-9]+ in the header use it as start,
- * otherwise send the full file */
-
- array_reset(p->get_params);
- buffer_copy_string_buffer(p->query_str, con->uri.query);
- split_get_params(p->get_params, p->query_str);
-
- if (NULL == (get_param = (data_string *)array_get_element(p->get_params, CONST_STR_LEN("start")))) {
- if (con->conf.log_request_handling) {
- TRACE("start=... not found, skipping %s", SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- /* too short */
- if (get_param->value->used < 2) {
- if (con->conf.log_request_handling) {
- TRACE("start=... found, but empty, skipping %s", SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- /* check if it is a number */
- start = strtol(get_param->value->ptr, &err, 10);
- if (*err != '\0') {
- if (con->conf.log_request_handling) {
- TRACE("parsing start '%s' as number failed, skipping %s",
- SAFE_BUF_STR(get_param->value), SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- if (start <= 0) {
- if (con->conf.log_request_handling) {
- TRACE("start is <= 0, skipping %s", SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- /* check if start is > filesize */
- if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- if (con->conf.log_request_handling) {
- TRACE("stat() for %s failed", SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- if (start > sce->st.st_size) {
- if (con->conf.log_request_handling) {
- TRACE("start > file-size, skipping %s", SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- /* we are safe now, let's build a flv header */
- b = chunkqueue_get_append_buffer(con->send);
- buffer_copy_string_len(b, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
-
- chunkqueue_append_file(con->send, con->physical.path, start, sce->st.st_size - start);
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
-
- con->send->is_closed = 1;
-
- if (con->conf.log_request_handling) {
- TRACE("sending %s from position %ld", SAFE_BUF_STR(con->physical.path), start);
- }
-
- return HANDLER_FINISHED;
- }
- }
-
- if (con->conf.log_request_handling) {
- TRACE("none of the extensions matched %s, leaving", SAFE_BUF_STR(con->physical.path));
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_flv_streaming_plugin_init(plugin *p);
-LI_EXPORT int mod_flv_streaming_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("flv_streaming");
-
- p->init = mod_flv_streaming_init;
- p->handle_physical = mod_flv_streaming_path_handler;
- p->set_defaults = mod_flv_streaming_set_defaults;
- p->cleanup = mod_flv_streaming_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
deleted file mode 100644
index d48ee03f..00000000
--- a/src/mod_indexfile.c
+++ /dev/null
@@ -1,254 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "configfile.h"
-
-#include "stat_cache.h"
-
-#include "sys-strings.h"
-#include "sys-files.h"
-
-#include "configfile.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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_indexfile_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->indexfiles);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->indexfiles = array_init();
-
- cv[0].destination = s->indexfiles;
- cv[1].destination = s->indexfiles; /* old name for [0] */
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(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_OPTION(indexfiles);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
- PATCH_OPTION(indexfiles);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_indexfile_subrequest) {
- plugin_data *p = p_d;
- size_t k;
- stat_cache_entry *sce = NULL;
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
- if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
-
- mod_indexfile_patch_connection(srv, con, p);
-
- /* is the physical-path really a dir ? */
- switch(stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- case HANDLER_WAIT_FOR_EVENT:
- return HANDLER_WAIT_FOR_EVENT;
- case HANDLER_ERROR:
- return HANDLER_GO_ON;
- default:
- break;
- }
-
- if (!S_ISDIR(sce->st.st_mode)) {
- return HANDLER_GO_ON;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "handling the request as Indexfile");
- TRACE("URI : %s", SAFE_BUF_STR(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_string_buffer(p->tmp_buf, con->physical.doc_root);
- } else {
- buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
- PATHNAME_APPEND_SLASH(p->tmp_buf);
- }
- buffer_append_string_buffer(p->tmp_buf, ds->value);
-
- switch(stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
- case HANDLER_WAIT_FOR_EVENT:
- return HANDLER_WAIT_FOR_EVENT;
- case HANDLER_ERROR:
- 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;
- default:
- break;
- }
-
- /* rewrite uri.path to the real path (/ -> /index.php) */
- buffer_append_string_buffer(con->uri.path, ds->value);
- buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
-
- if (con->conf.log_request_handling) {
- TRACE("rewrite path to %s (%s)",
- SAFE_BUF_STR(con->physical.path),
- SAFE_BUF_STR(con->uri.path));
- }
-
- /* need to reset condition cache since uri.path changed. */
- config_cond_cache_reset_item(srv, con, COMP_PHYSICAL_PATH);
- config_cond_cache_reset_item(srv, con, COMP_PHYSICAL_PATH_EXISTS);
- config_cond_cache_reset_item(srv, con, COMP_HTTP_URL);
-
- return HANDLER_GO_ON;
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_indexfile_plugin_init(plugin *p);
-LI_EXPORT 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_start_backend = mod_indexfile_subrequest;
- p->set_defaults = mod_indexfile_set_defaults;
- p->cleanup = mod_indexfile_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_magnet.c b/src/mod_magnet.c
deleted file mode 100644
index d1260396..00000000
--- a/src/mod_magnet.c
+++ /dev/null
@@ -1,984 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <setjmp.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "mod_magnet_cache.h"
-#include "response.h"
-#include "stat_cache.h"
-#include "status_counter.h"
-#include "etag.h"
-#include "configfile.h"
-
-#ifdef HAVE_LUA_H
-#include <lua.h>
-#include <lauxlib.h>
-
-#define PLUGIN_NAME "magnet"
-
-#define MAGNET_CONFIG_RAW_URL PLUGIN_NAME ".attract-raw-url-to"
-#define MAGNET_CONFIG_PHYSICAL_PATH PLUGIN_NAME ".attract-physical-path-to"
-#define MAGNET_CONFIG_FILTER_CONTENT PLUGIN_NAME ".attract-response-content-to"
-#define MAGNET_CONFIG_FILTER_HEADER PLUGIN_NAME ".attract-response-header-to"
-#define MAGNET_RESTART_REQUEST 99
-
-/* plugin config for all request/connections */
-
-static jmp_buf exceptionjmp;
-
-typedef struct {
- array *url_raw;
- array *physical_path;
- array *filter_header;
- array *filter_content;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- script_cache *cache;
-
- buffer *encode_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-/* init the plugin data */
-INIT_FUNC(mod_magnet_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->cache = script_cache_init();
- p->encode_buf = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_magnet_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->url_raw);
- array_free(s->physical_path);
- array_free(s->filter_header);
- array_free(s->filter_content);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- script_cache_free(p->cache);
- buffer_free(p->encode_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { MAGNET_CONFIG_FILTER_CONTENT, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { MAGNET_CONFIG_FILTER_HEADER, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->url_raw = array_init();
- s->physical_path = array_init();
- s->filter_content = array_init();
- s->filter_header = array_init();
-
- cv[0].destination = s->url_raw;
- cv[1].destination = s->physical_path;
- cv[2].destination = s->filter_content;
- cv[3].destination = s->filter_header;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(url_raw);
- PATCH(physical_path);
- PATCH(filter_header);
- PATCH(filter_content);
-
- /* 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);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_FILTER_CONTENT))) {
- PATCH(filter_content);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_FILTER_HEADER))) {
- PATCH(filter_header);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
-static int magnet_print(lua_State *L) {
- const char *s = luaL_checkstring(L, 1);
- server *srv;
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "(lua-print)", s);
-
- return 0;
-}
-
-static int magnet_stat(lua_State *L) {
- const char *s = luaL_checkstring(L, 1);
- server *srv;
- connection *con;
- buffer sb;
- stat_cache_entry *sce = NULL;
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- lua_pushstring(L, "lighty.con");
- lua_gettable(L, LUA_REGISTRYINDEX);
- con = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- sb.ptr = (char *)s;
- sb.used = sb.size = strlen(s) + 1;
-
- if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) {
- lua_pushnil(L);
-
- return 1;
- }
-
- lua_newtable(L);
-
- lua_pushboolean(L, S_ISREG(sce->st.st_mode));
- lua_setfield(L, -2, "is_file");
-
- lua_pushboolean(L, S_ISDIR(sce->st.st_mode));
- lua_setfield(L, -2, "is_dir");
-
- lua_pushboolean(L, S_ISCHR(sce->st.st_mode));
- lua_setfield(L, -2, "is_char");
-
- lua_pushboolean(L, S_ISBLK(sce->st.st_mode));
- lua_setfield(L, -2, "is_block");
-
- lua_pushboolean(L, S_ISSOCK(sce->st.st_mode));
- lua_setfield(L, -2, "is_socket");
-
- lua_pushboolean(L, S_ISLNK(sce->st.st_mode));
- lua_setfield(L, -2, "is_link");
-
- lua_pushboolean(L, S_ISFIFO(sce->st.st_mode));
- lua_setfield(L, -2, "is_fifo");
-
- lua_pushinteger(L, sce->st.st_mtime);
- lua_setfield(L, -2, "st_mtime");
-
- lua_pushinteger(L, sce->st.st_ctime);
- lua_setfield(L, -2, "st_ctime");
-
- lua_pushinteger(L, sce->st.st_atime);
- lua_setfield(L, -2, "st_atime");
-
- lua_pushinteger(L, sce->st.st_uid);
- lua_setfield(L, -2, "st_uid");
-
- lua_pushinteger(L, sce->st.st_gid);
- lua_setfield(L, -2, "st_gid");
-
- lua_pushinteger(L, sce->st.st_size);
- lua_setfield(L, -2, "st_size");
-
- lua_pushinteger(L, sce->st.st_ino);
- lua_setfield(L, -2, "st_ino");
-
-
- if (!buffer_is_empty(sce->etag)) {
- /* we have to mutate the etag */
- buffer *b = buffer_init();
- etag_mutate(b, sce->etag);
-
- lua_pushlstring(L, b->ptr, b->used - 1);
- buffer_free(b);
- } else {
- lua_pushnil(L);
- }
- lua_setfield(L, -2, "etag");
-
- if (!buffer_is_empty(sce->content_type)) {
- lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1);
- } else {
- lua_pushnil(L);
- }
- lua_setfield(L, -2, "content-type");
-
- return 1;
-}
-
-
-static int magnet_atpanic(lua_State *L) {
- const char *s = luaL_checkstring(L, 1);
- server *srv;
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "(lua-atpanic)", s);
-
- longjmp(exceptionjmp, 1);
-}
-
-static int magnet_reqhdr_get(lua_State *L) {
- server *srv;
- connection *con;
- data_string *ds;
-
- const char *key = luaL_checkstring(L, 2);
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- lua_pushstring(L, "lighty.con");
- lua_gettable(L, LUA_REGISTRYINDEX);
- con = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key, strlen(key)))) {
- if (ds->value->used) {
- lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
- } else {
- lua_pushnil(L);
- }
- } else {
- lua_pushnil(L);
- }
- return 1;
-}
-
-static int magnet_status_get(lua_State *L) {
- data_integer *di;
- server *srv;
- size_t key_len = 0;
-
- const char *key = luaL_checklstring(L, 2, &key_len);
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- di = status_counter_get_counter(key, key_len);
-
- lua_pushnumber(L, (double)di->value);
-
- return 1;
-}
-
-static int magnet_status_set(lua_State *L) {
- size_t key_len = 0;
- server *srv;
-
- const char *key = luaL_checklstring(L, 2, &key_len);
- int counter = luaL_checkint(L, 3);
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- status_counter_set(key, key_len, counter);
-
- return 0;
-}
-
-typedef struct {
- const char *name;
- enum {
- MAGNET_ENV_UNSET,
-
- MAGNET_ENV_PHYICAL_PATH,
- MAGNET_ENV_PHYICAL_REL_PATH,
- MAGNET_ENV_PHYICAL_DOC_ROOT,
-
- MAGNET_ENV_URI_PATH,
- MAGNET_ENV_URI_PATH_RAW,
- MAGNET_ENV_URI_SCHEME,
- MAGNET_ENV_URI_AUTHORITY,
- MAGNET_ENV_URI_QUERY,
-
- MAGNET_ENV_REQUEST_METHOD,
- MAGNET_ENV_REQUEST_URI,
- MAGNET_ENV_REQUEST_ORIG_URI,
- MAGNET_ENV_REQUEST_PROTOCOL
- } type;
-} magnet_env_t;
-
-static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
- buffer *dest = NULL;
- size_t i;
-
- const magnet_env_t env[] = {
- { "physical.path", MAGNET_ENV_PHYICAL_PATH },
- { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
- { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
-
- { "uri.path", MAGNET_ENV_URI_PATH },
- { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
- { "uri.scheme", MAGNET_ENV_URI_SCHEME },
- { "uri.authority", MAGNET_ENV_URI_AUTHORITY },
- { "uri.query", MAGNET_ENV_URI_QUERY },
-
- { "request.method", MAGNET_ENV_REQUEST_METHOD },
- { "request.uri", MAGNET_ENV_REQUEST_URI },
- { "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI },
- { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
-
- { NULL, MAGNET_ENV_UNSET }
- };
-
- UNUSED(srv);
-
- /**
- * map all internal variables to lua
- *
- */
-
- for (i = 0; env[i].name; i++) {
- if (0 == strcmp(key, env[i].name)) break;
- }
-
- switch (env[i].type) {
- case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
- case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
- case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
-
- case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
- case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
- case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
- case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
- case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
-
- case MAGNET_ENV_REQUEST_METHOD:
- buffer_copy_string(srv->tmp_buf, get_http_method_name(con->request.http_method));
- dest = srv->tmp_buf;
- break;
- case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break;
- case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break;
- case MAGNET_ENV_REQUEST_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 int magnet_env_get(lua_State *L) {
- server *srv;
- connection *con;
-
- const char *key = luaL_checkstring(L, 2);
- buffer *dest = NULL;
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- lua_pushstring(L, "lighty.con");
- lua_gettable(L, LUA_REGISTRYINDEX);
- con = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- dest = magnet_env_get_buffer(srv, con, key);
-
- if (dest && dest->used) {
- lua_pushlstring(L, dest->ptr, dest->used - 1);
- } else {
- lua_pushnil(L);
- }
-
- return 1;
-}
-
-static int magnet_env_set(lua_State *L) {
- server *srv;
- connection *con;
-
- const char *key = luaL_checkstring(L, 2);
- const char *val = luaL_checkstring(L, 3);
- buffer *dest = NULL;
-
- lua_pushstring(L, "lighty.srv");
- lua_gettable(L, LUA_REGISTRYINDEX);
- srv = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- lua_pushstring(L, "lighty.con");
- lua_gettable(L, LUA_REGISTRYINDEX);
- con = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
- buffer_copy_string(dest, val);
- } else {
- /* couldn't save */
-
- return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
- }
-
- return 0;
-}
-
-
-static int magnet_cgi_get(lua_State *L) {
- connection *con;
- data_string *ds;
-
- const char *key = luaL_checkstring(L, 2);
-
- lua_pushstring(L, "lighty.con");
- lua_gettable(L, LUA_REGISTRYINDEX);
- con = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- if (NULL != (ds = (data_string *)array_get_element(con->environment, key, strlen(key))) && ds->value->used)
- lua_pushlstring(L, CONST_BUF_LEN(ds->value));
- else
- lua_pushnil(L);
-
- return 1;
-}
-
-static int magnet_cgi_set(lua_State *L) {
- connection *con;
-
- const char *key = luaL_checkstring(L, 2);
- const char *val = luaL_checkstring(L, 3);
-
- lua_pushstring(L, "lighty.con");
- lua_gettable(L, LUA_REGISTRYINDEX);
- con = lua_touserdata(L, -1);
- lua_pop(L, 1);
-
- array_set_key_value(con->environment, key, strlen(key), val, strlen(val));
-
- return 0;
-}
-
-
-static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) {
- UNUSED(p);
- /**
- * get the environment of the function
- */
-
- lua_getfenv(L, -1); /* -1 is the function */
-
- /* lighty.header */
-
- lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
- assert(lua_istable(L, -1));
-
- lua_getfield(L, -1, "header"); /* lighty.header */
- if (lua_istable(L, -1)) {
- /* header is found, and is a table */
-
- lua_pushnil(L);
- while (lua_next(L, -2) != 0) {
- if (lua_isstring(L, -1) && lua_isstring(L, -2)) {
- const char *key, *val;
- size_t key_len, val_len;
-
- key = lua_tolstring(L, -2, &key_len);
- val = lua_tolstring(L, -1, &val_len);
-
- response_header_overwrite(srv, con, key, key_len, val, val_len);
- }
-
- lua_pop(L, 1);
- }
- }
-
- lua_pop(L, 1); /* pop the header-table */
- lua_pop(L, 1); /* pop the lighty-env */
- lua_pop(L, 1); /* pop the function env */
-
- return 0;
-}
-
-/**
- * walk through the content array
- *
- * content = { "<pre>", { file = "/content" } , "</pre>" }
- *
- * header["Content-Type"] = "text/html"
- *
- * return 200
- */
-static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) {
- UNUSED(p);
- /**
- * get the environment of the function
- */
-
- assert(lua_isfunction(L, -1));
- lua_getfenv(L, -1); /* -1 is the function */
-
- lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
- assert(lua_istable(L, -1));
-
- lua_getfield(L, -1, "content"); /* lighty.content */
- if (lua_istable(L, -1)) {
- int i;
- /* header is found, and is a table */
-
- for (i = 1; ; i++) {
- lua_rawgeti(L, -1, i);
-
- /* -1 is the value and should be the value ... aka a table */
- if (lua_isstring(L, -1)) {
- size_t s_len = 0;
- const char *s = lua_tolstring(L, -1, &s_len);
-
- chunkqueue_append_mem(con->send, s, s_len);
- } else if (lua_istable(L, -1)) {
- lua_getfield(L, -1, "filename");
- lua_getfield(L, -2, "length");
- lua_getfield(L, -3, "offset");
-
- if (lua_isstring(L, -3)) { /* filename has to be a string */
- buffer *fn = buffer_init();
- stat_cache_entry *sce;
-
- buffer_copy_string(fn, lua_tostring(L, -3));
-
- if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) {
- off_t off = 0;
- off_t len = 0;
-
- if (lua_isnumber(L, -1)) {
- off = lua_tonumber(L, -1);
- }
-
- if (lua_isnumber(L, -2)) {
- len = lua_tonumber(L, -2);
- } else {
- len = sce->st.st_size;
- }
-
- if (off < 0) {
- return luaL_error(L, "offset for '%s' is negative", fn->ptr);
- }
-
- if (len < off) {
- return luaL_error(L, "offset > length for '%s'", fn->ptr);
- }
-
- chunkqueue_append_file(con->send, fn, off, len - off);
- }
-
- buffer_free(fn);
- } else {
- lua_pop(L, 3 + 2); /* correct the stack */
-
- return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i);
- }
-
- lua_pop(L, 3);
- } else if (lua_isnil(L, -1)) {
- /* oops, end of list */
-
- lua_pop(L, 1);
-
- break;
- } else {
- lua_pop(L, 4);
-
- return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
- }
-
- lua_pop(L, 1); /* pop the content[...] table */
- }
- } else {
- return luaL_error(L, "lighty.content has to be a table");
- }
- lua_pop(L, 1); /* pop the header-table */
- lua_pop(L, 1); /* pop the lighty-table */
- lua_pop(L, 1); /* php the function env */
-
- return 0;
-}
-
-static int traceback (lua_State *L) {
- if (!lua_isstring(L, 1)) /* 'message' not a string? */
- return 1; /* keep it intact */
- lua_getfield(L, LUA_GLOBALSINDEX, "debug");
- if (!lua_istable(L, -1)) {
- lua_pop(L, 1);
- return 1;
- }
- lua_getfield(L, -1, "traceback");
- if (!lua_isfunction(L, -1)) {
- lua_pop(L, 2);
- return 1;
- }
- lua_pushvalue(L, 1); /* pass error message */
- lua_pushinteger(L, 2); /* skip this function and traceback */
- lua_call(L, 2, 1); /* call debug.traceback */
- return 1;
-}
-
-static int push_traceback(lua_State *L, int narg) {
- int base = lua_gettop(L) - narg; /* function index */
- lua_pushcfunction(L, traceback);
- lua_insert(L, base);
- return base;
-}
-
-static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
- lua_State *L;
- int lua_return_value = -1;
- int errfunc;
- /* get the script-context */
-
-
- L = script_cache_get_script(srv, con, p->cache, name);
-
- if (lua_isstring(L, -1)) {
- log_error_write(srv, __FILE__, __LINE__,
- "sbss",
- "loading script",
- name,
- "failed:",
- lua_tostring(L, -1));
-
- lua_pop(L, 1);
-
- assert(lua_gettop(L) == 0); /* only the function should be on the stack */
-
- con->http_status = 500;
-
- return HANDLER_FINISHED;
- }
-
- lua_pushstring(L, "lighty.srv");
- lua_pushlightuserdata(L, srv);
- lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */
-
- lua_pushstring(L, "lighty.con");
- lua_pushlightuserdata(L, con);
- lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */
-
- lua_atpanic(L, magnet_atpanic);
-
- /**
- * we want to create empty environment for our script
- *
- * setmetatable({}, {__index = _G})
- *
- * if a function, symbol is not defined in our env, __index will lookup
- * in the global env.
- *
- * all variables created in the script-env will be thrown
- * away at the end of the script run.
- */
- lua_newtable(L); /* my empty environment aka {} (sp += 1) */
-
- /* we have to overwrite the print function */
- lua_pushcfunction(L, magnet_print); /* (sp += 1) */
- lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */
-
- /**
- * lighty.request[] has the HTTP-request headers
- * lighty.content[] is a table of string/file
- * lighty.header[] is an array to set response headers
- */
-
- lua_newtable(L); /* lighty.* (sp += 1) */
-
- lua_newtable(L); /* {} (sp += 1) */
- lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
- lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */
- lua_setfield(L, -2, "__index"); /* (sp -= 1) */
- lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
- lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */
-
- lua_newtable(L); /* {} (sp += 1) */
- lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
- lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */
- lua_setfield(L, -2, "__index"); /* (sp -= 1) */
- lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */
- lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
- lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
- lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */
-
- lua_newtable(L); /* {} (sp += 1) */
- lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
- lua_pushcfunction(L, magnet_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_setmetatable(L, -2); /* tie the metatable to req_env (sp -= 1) */
- lua_setfield(L, -2, "req_env"); /* content = {} (sp -= 1) */
-
- lua_newtable(L); /* {} (sp += 1) */
- lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
- lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */
- lua_setfield(L, -2, "__index"); /* (sp -= 1) */
- lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */
- lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
- lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
- lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */
-
- /* add empty 'content' and 'header' tables */
- lua_newtable(L); /* {} (sp += 1) */
- lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */
-
- lua_newtable(L); /* {} (sp += 1) */
- lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */
-
- lua_pushinteger(L, MAGNET_RESTART_REQUEST);
- lua_setfield(L, -2, "RESTART_REQUEST");
-
- lua_pushcfunction(L, magnet_stat); /* (sp += 1) */
- lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */
-
- lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */
-
- lua_newtable(L); /* the meta-table for the new env (sp += 1) */
- lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */
- lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */
- lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
-
-
- lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */
-
- errfunc = push_traceback(L, 0);
- if (lua_pcall(L, 0, 1, errfunc)) {
- lua_remove(L, errfunc);
- log_error_write(srv, __FILE__, __LINE__,
- "ss",
- "lua_pcall():",
- lua_tostring(L, -1));
- lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */
-
- assert(lua_gettop(L) == 1); /* only the function should be on the stack */
-
- con->http_status = 500;
-
- return HANDLER_FINISHED;
- }
- lua_remove(L, errfunc);
-
- /* we should have the function-copy and the return value on the stack */
- assert(lua_gettop(L) == 2);
-
- if (lua_isnumber(L, -1)) {
- /* if the ret-value is a number, take it */
- lua_return_value = lua_tointeger(L, -1);
- }
- lua_pop(L, 1); /* pop the ret-value */
-
- magnet_copy_response_header(srv, con, p, L);
-
- if (lua_return_value > 99) {
- con->http_status = lua_return_value;
- con->send->is_closed = 1;
-
- /* try { ...*/
- if (0 == setjmp(exceptionjmp)) {
- magnet_attach_content(srv, con, p, L);
- } else {
- /* } catch () { */
- con->http_status = 500;
- }
-
- if (chunkqueue_is_empty(con->send)) {
- con->mode = DIRECT;
- } else {
- con->mode = p->id;
- }
-
- assert(lua_gettop(L) == 1); /* only the function should be on the stack */
-
- /* we are finished */
- return HANDLER_FINISHED;
- } else if (MAGNET_RESTART_REQUEST == lua_return_value) {
- assert(lua_gettop(L) == 1); /* only the function should be on the stack */
- buffer_reset(con->physical.path);
-
- return HANDLER_COMEBACK;
- } else {
- assert(lua_gettop(L) == 1); /* only the function should be on the stack */
-
- return HANDLER_GO_ON;
- }
-}
-
-static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
- size_t i;
- handler_t ret = HANDLER_GO_ON;
-
- /* no filename set */
- if (files->used == 0) return HANDLER_GO_ON;
-
- /**
- * execute all files and jump out on the first !HANDLER_GO_ON
- */
- for (i = 0; i < files->used; i++) {
- data_string *ds = (data_string *)files->data[i];
-
- if (buffer_is_empty(ds->value)) continue;
-
- ret = magnet_attract(srv, con, p, ds->value);
-
- if (ret != HANDLER_GO_ON) break;
- }
-
- /* reset conditional cache. */
- config_cond_cache_reset_all_items(srv, con);
-
- 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);
-}
-
-URIHANDLER_FUNC(mod_magnet_handle_response_header) {
- plugin_data *p = p_d;
-
- mod_magnet_patch_connection(srv, con, p);
-
- return magnet_attract_array(srv, con, p, p->conf.filter_header);
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_magnet_plugin_init(plugin *p);
-LI_EXPORT int mod_magnet_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string(PLUGIN_NAME);
-
- p->init = mod_magnet_init;
- p->set_defaults = mod_magnet_set_defaults;
- p->cleanup = mod_magnet_free;
-
- p->handle_uri_clean = mod_magnet_uri_handler; /* match against the uri */
- p->handle_physical = mod_magnet_physical; /* match against the filename */
-
- p->handle_response_header = mod_magnet_handle_response_header;
-#if 0
- p->handle_filter_response_content = mod_magnet_handle_filter_response_content;
-#endif
-
- p->data = NULL;
-
- return 0;
-}
-
-#else
-LI_EXPORT int mod_magnet_plugin_init(plugin *p);
-LI_EXPORT int mod_magnet_plugin_init(plugin *p) {
- UNUSED(p);
- return -1;
-}
-#endif
diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c
deleted file mode 100644
index 0cd1bcc3..00000000
--- a/src/mod_magnet_cache.c
+++ /dev/null
@@ -1,137 +0,0 @@
-#include <stdlib.h>
-#include <time.h>
-#include <assert.h>
-
-#include "stat_cache.h"
-#include "mod_magnet_cache.h"
-
-#ifdef HAVE_LUA_H
-#include <lualib.h>
-#include <lauxlib.h>
-
-static script *script_init() {
- script *sc;
-
- sc = calloc(1, sizeof(*sc));
- sc->name = buffer_init();
- sc->etag = buffer_init();
-
- return sc;
-}
-
-static void script_free(script *sc) {
- if (!sc) return;
-
- lua_pop(sc->L, 1); /* the function copy */
-
- buffer_free(sc->name);
- buffer_free(sc->etag);
-
- lua_close(sc->L);
-
- free(sc);
-}
-
-script_cache *script_cache_init() {
- script_cache *p;
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-void script_cache_free(script_cache *p) {
- size_t i;
-
- if (!p) return;
-
- for (i = 0; i < p->used; i++) {
- script_free(p->ptr[i]);
- }
-
- free(p->ptr);
-
- free(p);
-}
-
-lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
- size_t i;
- script *sc = NULL;
- stat_cache_entry *sce;
-
- for (i = 0; i < cache->used; i++) {
- sc = cache->ptr[i];
-
- if (buffer_is_equal(name, sc->name)) {
- sc->last_used = time(NULL);
-
- /* oops, the script failed last time */
-
- if (lua_gettop(sc->L) == 0) break;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
- lua_pop(sc->L, 1); /* pop the old function */
- break;
- }
-
- if (!buffer_is_equal(sce->etag, sc->etag)) {
- /* the etag is outdated, reload the function */
- lua_pop(sc->L, 1);
- break;
- }
-
- assert(lua_isfunction(sc->L, -1));
- lua_pushvalue(sc->L, -1); /* copy the function-reference */
-
- return sc->L;
- }
-
- sc = NULL;
- }
-
- /* if the script was script already loaded but either got changed or
- * failed to load last time */
- if (sc == NULL) {
- sc = script_init();
-
- if (cache->size == 0) {
- cache->size = 16;
- cache->ptr = malloc(cache->size * sizeof(*(cache->ptr)));
- } else if (cache->used == cache->size) {
- cache->size += 16;
- cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
- }
-
- cache->ptr[cache->used++] = sc;
-
- buffer_copy_string_buffer(sc->name, name);
-
- sc->L = luaL_newstate();
- luaL_openlibs(sc->L);
- }
-
- sc->last_used = time(NULL);
-
- if (0 != luaL_loadfile(sc->L, name->ptr)) {
- /* oops, an error, return it */
-
- return sc->L;
- }
-
- if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
- buffer_copy_string_buffer(sc->etag, sce->etag);
- }
-
- /**
- * pcall() needs the function on the stack
- *
- * as pcall() will pop the script from the stack when done, we have to
- * duplicate it here
- */
- assert(lua_isfunction(sc->L, -1));
- lua_pushvalue(sc->L, -1); /* copy the function-reference */
-
- return sc->L;
-}
-
-#endif
diff --git a/src/mod_magnet_cache.h b/src/mod_magnet_cache.h
deleted file mode 100644
index 50c9e44a..00000000
--- a/src/mod_magnet_cache.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef _MOD_MAGNET_CACHE_H_
-#define _MOD_MAGNET_CACHE_H_
-
-#include "buffer.h"
-#include "base.h"
-
-#ifdef HAVE_LUA_H
-#include <lua.h>
-
-typedef struct {
- buffer *name;
- buffer *etag;
-
- lua_State *L;
-
- time_t last_used; /* LRU */
-} script;
-
-typedef struct {
- script **ptr;
-
- size_t used;
- size_t size;
-} script_cache;
-
-script_cache *script_cache_init(void);
-void script_cache_free(script_cache *cache);
-
-lua_State *script_cache_get_script(server *srv, connection *con,
- script_cache *cache, buffer *name);
-
-#endif
-#endif
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
deleted file mode 100644
index 68b65d52..00000000
--- a/src/mod_mysql_vhost.c
+++ /dev/null
@@ -1,309 +0,0 @@
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_MYSQL_H
-# ifdef HAVE_LIBMYSQL
-# define HAVE_MYSQL
-# endif
-#endif
-
-#ifdef HAVE_MYSQL
-#include <mysql.h>
-#endif
-
-#include "plugin.h"
-#include "log.h"
-
-#include "stat_cache.h"
-#include "sys-files.h"
-
-#include "mod_sql_vhost_core.h"
-
-#ifdef HAVE_MYSQL
-
-#define CORE_PLUGIN "mod_sql_vhost_core"
-
-typedef struct {
- MYSQL *mysql;
-
- buffer *mysql_pre;
- buffer *mysql_post;
-
- mod_sql_vhost_core_plugin_config *core;
-} plugin_config;
-
-/* global plugin data */
-typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost);
-
-/* init the plugin data */
-INIT_FUNC(mod_mysql_vhost_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- 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_pre);
- buffer_free(s->mysql_post);
-
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* set configuration values */
-SERVER_FUNC(mod_mysql_vhost_set_defaults) {
- plugin_data *p = p_d;
- mod_sql_vhost_core_plugin_data *core_config;
-
- size_t i = 0;
-
- /* our very own plugin storage, one entry for each conditional
- *
- * srv->config_context->used is the number of conditionals
- * */
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- /* get the config of the core-plugin */
- core_config = plugin_get_config(srv, CORE_PLUGIN);
-
- /* walk through all conditionals and check for assignments */
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- buffer *sel;
- char *qmark;
-
- /* get the config from the core plugin for this conditional-context */
- s = calloc(1, sizeof(plugin_config));
-
- s->core = core_config->config_storage[i];
-
- s->mysql = NULL;
-
- s->mysql_pre = buffer_init();
- s->mysql_post = buffer_init();
-
- p->config_storage[i] = s;
-
- /* check if we are the plugin for this backend */
- if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
-
- /* attach us to the core-plugin */
- s->core->backend_data = p;
- s->core->get_vhost = mod_mysql_vhost_get_vhost;
-
- sel = buffer_init();
- buffer_copy_string_buffer(sel, s->core->select_vhost);
-
- if (sel->used && (qmark = strchr(sel->ptr, '?'))) {
- *qmark = '\0';
- buffer_copy_string(s->mysql_pre, sel->ptr);
- buffer_copy_string(s->mysql_post, qmark+1);
- } else {
- buffer_copy_string_buffer(s->mysql_pre, sel);
- }
- buffer_free(sel);
-
- /* 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_is_empty(s->core->user) ||
- buffer_is_empty(s->core->db))) {
-
- int fd;
-
- if (NULL == (s->mysql = mysql_init(NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
-
- return HANDLER_ERROR;
- }
-
-#if MYSQL_VERSION_ID >= 50003
- /* in mysql versions above 5.0.3 the reconnect flag is off by default */
- {
- my_bool reconnect = 1;
- mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
- }
-#endif
-
-#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
-
- s->mysql->free_me = 1;
-
- if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
- FOO(db), s->core->port, FOO(sock), 0)) {
- log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
-
- return HANDLER_ERROR;
- }
-#undef FOO
- /* set close_on_exec for mysql the hard way */
- /* Note: this only works as it is done during startup, */
- /* otherwise we cannot be sure that mysql is fd i-1 */
- if (-1 == (fd = open("/dev/null", 0))) {
- close(fd);
- fcntl(fd-1, F_SETFD, FD_CLOEXEC);
- }
- }
- }
-
-
-
- return HANDLER_GO_ON;
-}
-
-static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(mysql_pre);
- PATCH_OPTION(mysql_post);
- PATCH_OPTION(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;
-
- if (s->mysql) {
- PATCH_OPTION(mysql);
- PATCH_OPTION(mysql_pre);
- PATCH_OPTION(mysql_post);
- }
- }
-
- return 0;
-}
-
-/**
- * get the vhost info from the database
- */
-SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
- plugin_data *p = p_d;
- unsigned cols;
- MYSQL_ROW row;
- MYSQL_RES *result = NULL;
-
- UNUSED(host);
-
- /* no host specified? */
- if (!con->uri.authority->used) return HANDLER_ERROR;
-
- mod_mysql_vhost_patch_connection(srv, con, p);
-
- if (!p->conf.mysql) return HANDLER_ERROR;
-
- /* build and run SQL query */
- buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
- if (p->conf.mysql_post->used) {
- buffer_append_string_buffer(p->tmp_buf, con->uri.authority);
- buffer_append_string_buffer(p->tmp_buf, p->conf.mysql_post);
- }
- if (mysql_query(p->conf.mysql, BUF_STR(p->tmp_buf))) {
- ERROR("mysql_query(%s) failed: %s", SAFE_BUF_STR(p->tmp_buf), mysql_error(p->conf.mysql));
-
- mysql_free_result(result);
- return HANDLER_ERROR;
- }
- 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);
- return HANDLER_ERROR;
- }
-
- buffer_copy_string(docroot, row[0]);
-
- mysql_free_result(result);
-
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-LI_EXPORT int mod_mysql_vhost_plugin_init(plugin *p);
-LI_EXPORT int mod_mysql_vhost_plugin_init(plugin *p) {
- data_string *ds;
-
- 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->set_defaults = mod_mysql_vhost_set_defaults;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-#else
-/* we don't have mysql support, this plugin does nothing */
-LI_EXPORT int mod_mysql_vhost_plugin_init(plugin *p);
-LI_EXPORT int mod_mysql_vhost_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mysql_vhost");
-
- return 0;
-}
-#endif
diff --git a/src/mod_postgresql_vhost.c b/src/mod_postgresql_vhost.c
deleted file mode 100644
index 2e0f4a7f..00000000
--- a/src/mod_postgresql_vhost.c
+++ /dev/null
@@ -1,371 +0,0 @@
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdbool.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_LIBPQ_FE_H
-# ifdef HAVE_LIBPQ
-# define HAVE_POSTGRESQL
-# endif
-#endif
-
-#ifdef HAVE_POSTGRESQL
-#include <glib.h>
-#include <libpq-fe.h>
-#include <time.h>
-#endif
-
-#include "plugin.h"
-#include "log.h"
-
-#include "stat_cache.h"
-#include "sys-files.h"
-
-#include "mod_sql_vhost_core.h"
-
-#ifdef HAVE_POSTGRESQL
-// Define a couple constants so the cache expires and we
-// do a countdown for when to do some cleanup.
-
-typedef struct {
- PGconn **pconn;
- PGconn *conn;
-
- buffer *postgresql_pre;
- buffer *postgresql_post;
-
- buffer *conninfo;
-
- mod_sql_vhost_core_plugin_config *core;
-} plugin_config;
-
-/* global plugin data */
-typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-#define CORE_PLUGIN "mod_sql_vhost_core"
-
-SQLVHOST_BACKEND_GETVHOST(mod_postgresql_vhost_get_vhost);
-
-/* init the plugin data */
-INIT_FUNC(mod_postgresql_vhost_init) {
- plugin_data *p;
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- return p;
-}
-
-/* cleanup the plugin data */
-SERVER_FUNC(mod_postgresql_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;
-
- PQfinish(s->conn);
- buffer_free(s->postgresql_pre);
- buffer_free(s->postgresql_post);
- buffer_free(s->conninfo);
-
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-
-/* set configuration values */
-SERVER_FUNC(mod_postgresql_vhost_set_defaults) {
- plugin_data *p = p_d;
- mod_sql_vhost_core_plugin_data *core_config;
-
- size_t i = 0;
-
- /* our very own plugin storage, one entry for each conditional
- *
- * srv->config_context->used is the number of conditionals
- * */
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- /* get the config of the core-plugin */
- core_config = plugin_get_config(srv, CORE_PLUGIN);
-
- /* walk through all conditionals and check for assignments */
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- buffer *sel;
- char *qmark;
-
- /* get the config from the core plugin for this conditional-context */
- s = calloc(1, sizeof(plugin_config));
-
- s->core = core_config->config_storage[i];
- s->conn = NULL;
- s->pconn = &(s->conn);
-
- s->postgresql_pre = buffer_init();
- s->postgresql_post = buffer_init();
- s->conninfo = buffer_init();
-
- p->config_storage[i] = s;
-
- /* check if we are the plugin for this backend */
- if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("postgresql"))) continue;
-
- /* attach us to the core-plugin */
- s->core->backend_data = p;
- s->core->get_vhost = mod_postgresql_vhost_get_vhost;
-
- sel = buffer_init();
- buffer_copy_string_buffer(sel, s->core->select_vhost);
-
- if (sel->used && (qmark = strchr(sel->ptr, '?'))) {
- *qmark = '\0';
- buffer_copy_string(s->postgresql_pre, sel->ptr);
- buffer_copy_string(s->postgresql_post, qmark+1);
- } else {
- buffer_copy_string_buffer(s->postgresql_pre, sel);
- }
- buffer_free(sel);
-
- /* see if we can build our connection string based on the parts we know from the config
- *
- * "host=/tmp dbname=lighttpd user=lighttpd"
- * */
-
- if (!buffer_is_empty(s->core->hostname)) {
- buffer_append_string_len(s->conninfo, CONST_STR_LEN("host="));
- buffer_append_string_buffer(s->conninfo, s->core->hostname);
- if (s->core->port) {
- buffer_append_string_len(s->conninfo, CONST_STR_LEN(" "));
- buffer_append_string_len(s->conninfo, CONST_STR_LEN("port="));
- buffer_append_long(s->conninfo, s->core->port);
- }
- } else if (!buffer_is_empty(s->core->sock)) {
- buffer_append_string_len(s->conninfo, CONST_STR_LEN("host="));
- buffer_append_string_buffer(s->conninfo, s->core->sock);
- }
-
- if (!buffer_is_empty(s->core->db)) {
- if (!buffer_is_empty(s->conninfo)) buffer_append_string_len(s->conninfo, CONST_STR_LEN(" "));
- buffer_append_string_len(s->conninfo, CONST_STR_LEN("dbname="));
- buffer_append_string_buffer(s->conninfo, s->core->db);
- }
-
- if (!buffer_is_empty(s->core->user)) {
- if (!buffer_is_empty(s->conninfo)) buffer_append_string_len(s->conninfo, CONST_STR_LEN(" "));
- buffer_append_string_len(s->conninfo, CONST_STR_LEN("user="));
- buffer_append_string_buffer(s->conninfo, s->core->user);
- }
-
- if (!buffer_is_empty(s->core->pass)) {
- if (!buffer_is_empty(s->conninfo)) buffer_append_string_len(s->conninfo, CONST_STR_LEN(" "));
- buffer_append_string_len(s->conninfo, CONST_STR_LEN("password="));
- buffer_append_string_buffer(s->conninfo, s->core->pass);
- }
-
- }
-
- return HANDLER_GO_ON;
-}
-
-
-static int mod_postgresql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(postgresql_pre);
- PATCH_OPTION(postgresql_post);
- PATCH_OPTION(conn);
- PATCH_OPTION(pconn);
- PATCH_OPTION(conninfo);
- PATCH_OPTION(core);
-
- /* 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;
-
- if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("postgresql"))) continue;
-
- PATCH_OPTION(pconn);
- PATCH_OPTION(conn);
- PATCH_OPTION(conninfo);
- PATCH_OPTION(postgresql_pre);
- PATCH_OPTION(postgresql_post);
- PATCH_OPTION(core);
- }
-
- return 0;
-}
-
-/*
- * get the vhost info from the database
- */
-SQLVHOST_BACKEND_GETVHOST(mod_postgresql_vhost_get_vhost) {
- plugin_data *p = p_d;
- int nFields;
- PGresult *result;
- gchar *field;
-
- UNUSED(host);
-
- /* no host specified? */
- if (buffer_is_empty(con->uri.authority)) return HANDLER_ERROR;
-
- mod_postgresql_vhost_patch_connection(srv, con, p);
-
- if (buffer_is_empty(p->conf.conninfo)) return HANDLER_ERROR;
-
- /**
- * try to connect the pg-server
- */
- if (p->conf.conn == NULL) {
- if (p->conf.core->debug) TRACE("connecting to postgres: %s", SAFE_BUF_STR(p->conf.conninfo));
-
- if (NULL == (p->conf.conn = PQconnectdb(BUF_STR(p->conf.conninfo)))) {
- ERROR("%s", "postgresql malloc failure");
-
- return HANDLER_ERROR;
- }
-
- /* we have to update the pointer in the conditional cache too */
- *(p->conf.pconn) = p->conf.conn;
-
- /* For when we move to Async requests
- * PQsetnonblocking(s->conn,1);
- */
-
- if (CONNECTION_BAD == PQstatus(p->conf.conn)) {
- /* Even if bad connection. maybe next time it can be fixed
- */
- ERROR("Bad connection for '%s': %s", SAFE_BUF_STR(p->conf.conninfo), PQerrorMessage(p->conf.conn));
-
- PQfinish(p->conf.conn);
-
- p->conf.conn = NULL;
-
- return HANDLER_ERROR;
- }
-
- if (PQstatus(p->conf.conn) != CONNECTION_OK){
- ERROR("PQconnectdb() failed: %i", PQstatus(p->conf.conn));
-
- PQfinish(p->conf.conn);
-
- p->conf.conn = NULL;
-
- return HANDLER_ERROR;
- }
- }
-
- /**
- * TODO: Change to a stored proc to simiplify this
- * build and run SQL query
- */
- if (PQstatus(p->conf.conn) != CONNECTION_OK) {
- PQreset(p->conf.conn);
- }
-
- buffer_copy_string_buffer(p->tmp_buf, p->conf.postgresql_pre);
- if (p->conf.postgresql_post->used) {
- buffer_append_string_buffer(p->tmp_buf, con->uri.authority);
- buffer_append_string_buffer(p->tmp_buf, p->conf.postgresql_post);
- }
-
- result = PQexec(p->conf.conn, p->tmp_buf->ptr);
-
- /**
- * For Async requests. Database will block/slow down your daemon
- * result = PQsendQuery(p->conf.conn, p->tmp_buf->ptr);
- */
- if (result == NULL) {
- ERROR("PQexec(%s) failed: %s", SAFE_BUF_STR(p->tmp_buf), PQerrorMessage(p->conf.conn));
- return HANDLER_ERROR;
- }
-
- if (PQresultStatus(result) != PGRES_TUPLES_OK) {
- ERROR("PQresultStatus(%s): %s", SAFE_BUF_STR(p->tmp_buf), PQerrorMessage(p->conf.conn));
-
- PQclear(result);
-
- return HANDLER_ERROR;
- }
- /**
- * FIXME:
- * We checked for tupels already, but will add more sanity
- */
- nFields = PQnfields(result);
- if (PQntuples(result) < 1 || nFields < 1 ||
- (field = PQgetvalue(result, 0, 0)) == NULL || !*field) {
- /* no such virtual host */
- PQclear(result);
-
- return HANDLER_ERROR;
- }
-
- buffer_copy_string(docroot, field);
-
- PQclear(result);
-
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-LI_EXPORT int mod_postgresql_vhost_plugin_init(plugin *p);
-LI_EXPORT int mod_postgresql_vhost_plugin_init(plugin *p) {
- data_string *ds;
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("postgresql_vhost");
- p->init = mod_postgresql_vhost_init;
- p->cleanup = mod_postgresql_vhost_cleanup;
- p->set_defaults = mod_postgresql_vhost_set_defaults;
-
- ds = data_string_init();
-
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-#else
-/* we don't have postgresql support, this plugin does nothing */
-LI_EXPORT int mod_postgresql_vhost_plugin_init(plugin *p);
-LI_EXPORT int mod_postgresql_vhost_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("postgresql_vhost");
-
- return 0;
-}
-#endif
diff --git a/src/mod_proxy_backend_ajp13.c b/src/mod_proxy_backend_ajp13.c
deleted file mode 100644
index 1c674f8f..00000000
--- a/src/mod_proxy_backend_ajp13.c
+++ /dev/null
@@ -1,836 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-
-#include "inet_ntop_cache.h"
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "buffer.h"
-#include "log.h"
-#include "array.h"
-#include "keyvalue.h"
-#include "ajp13.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- http_method_t http;
- ajp13_method_t ajp13;
-} http_method_map;
-
-static http_method_map http_methods[] = {
- { HTTP_METHOD_GET, AJP13_METHOD_GET },
- { HTTP_METHOD_POST, AJP13_METHOD_POST },
- { HTTP_METHOD_HEAD, AJP13_METHOD_HEAD },
- { HTTP_METHOD_OPTIONS, AJP13_METHOD_OPTIONS },
- { HTTP_METHOD_PROPFIND, AJP13_METHOD_PROPFIND },
- { HTTP_METHOD_MKCOL, AJP13_METHOD_MKCOL },
- { HTTP_METHOD_PUT, AJP13_METHOD_PUT },
- { HTTP_METHOD_DELETE, AJP13_METHOD_DELETE },
- { HTTP_METHOD_COPY, AJP13_METHOD_COPY },
- { HTTP_METHOD_MOVE, AJP13_METHOD_MOVE },
- { HTTP_METHOD_PROPPATCH, AJP13_METHOD_PROPPATCH },
- { HTTP_METHOD_REPORT, AJP13_METHOD_REPORT },
- { HTTP_METHOD_CHECKOUT, AJP13_METHOD_CHECKOUT },
- { HTTP_METHOD_CHECKIN, AJP13_METHOD_CHECKIN },
- { HTTP_METHOD_VERSION_CONTROL, AJP13_METHOD_VERSION_CONTROL },
- { HTTP_METHOD_UNCHECKOUT, AJP13_METHOD_UNCHECKOUT },
- { HTTP_METHOD_MKACTIVITY, AJP13_METHOD_MKACTIVITY },
- { HTTP_METHOD_MERGE, AJP13_METHOD_MERGE },
- { HTTP_METHOD_LOCK, AJP13_METHOD_LOCK },
- { HTTP_METHOD_UNLOCK, AJP13_METHOD_UNLOCK },
- { HTTP_METHOD_LABEL, AJP13_METHOD_LABEL },
- { HTTP_METHOD_CONNECT, AJP13_METHOD_UNKNOWN },
- { HTTP_METHOD_UNSET, AJP13_METHOD_UNKNOWN }
-};
-
-static ajp13_method_t ajp13_convert_http_method(http_method_t http_method) {
- int i;
- /* try fast lookup. if http_methods[] is sorted, we will find it this way. */
- if(http_method != HTTP_METHOD_UNSET) {
- if(http_methods[http_method].http == http_method) {
- return http_methods[http_method].ajp13;
- }
- }
- /* walk the list to find ajp13 method. */
- for(i = 0; http_methods[i].http != HTTP_METHOD_UNSET; i++) {
- if(http_methods[i].http == http_method) return http_methods[i].http;
- }
- return AJP13_METHOD_UNKNOWN;
-}
-
-/*
- * request header keyvalue map.
- *
- * Note: The strings have to be uppercase
- */
-static keyvalue request_headers[] = {
- { AJP13_REQ_ACCEPT, "ACCEPT" },
- { AJP13_REQ_ACCEPT_CHARSET, "ACCEPT-CHARSET" },
- { AJP13_REQ_ACCEPT_ENCODING, "ACCEPT-ENCODING" },
- { AJP13_REQ_ACCEPT_LANGUAGE, "ACCEPT-LANGUAGE" },
- { AJP13_REQ_AUTHORIZATION, "AUTHORIZATION" },
- { AJP13_REQ_CONNECTION, "CONNECTION" },
- { AJP13_REQ_CONTENT_TYPE, "CONTENT-TYPE" },
- { AJP13_REQ_CONTENT_LENGTH, "CONTENT-LENGTH" },
- { AJP13_REQ_COOKIE, "COOKIE" },
- { AJP13_REQ_COOKIE2, "COOKIE2" },
- { AJP13_REQ_HOST, "HOST" },
- { AJP13_REQ_PRAGMA, "PRAGMA" },
- { AJP13_REQ_REFERER, "REFERER" },
- { AJP13_REQ_USER_AGENT, "USER-AGENT" },
-
- { -1, NULL }
-};
-
-/*
- * response header keyvalue map
- *
- * Note: The strings don't have to be all uppercase here
- */
-static keyvalue response_headers[] = {
- { AJP13_RESP_CONTENT_TYPE, "Content-Type" },
- { AJP13_RESP_CONTENT_LANGUAGE, "Content-Language" },
- { AJP13_RESP_CONTENT_LENGTH, "Content-Length" },
- { AJP13_RESP_DATE, "Date" },
- { AJP13_RESP_LAST_MODIFIED, "Last-Modified" },
- { AJP13_RESP_LOCATION, "Location" },
- { AJP13_RESP_SET_COOKIE, "Set-Cookie" },
- { AJP13_RESP_SET_COOKIE2, "Set-Cookie2" },
- { AJP13_RESP_SERVLET_ENGINE, "Servlet-Engine" },
- { AJP13_RESP_STATUS, "Status" },
- { AJP13_RESP_WWW_AUTHENTICATE, "WWW-Authenticate" },
- { -1, NULL }
-};
-
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-typedef struct {
- size_t len;
- off_t offset;
- int type;
-} ajp13_packet;
-
-typedef struct {
- unsigned char magicB0;
- unsigned char magicB1;
- unsigned char lengthB0;
- unsigned char lengthB1;
- unsigned char type;
-} AJP13_Header;
-
-/**
- * init the AJP13_header
- */
-static int ajp13_header(char *ptr, int length) {
- AJP13_Header * header = (AJP13_Header *)ptr;
- header->magicB0 = (AJP13_SERVER_MAGIC >> 8) & 0xff;
- header->magicB1 = (AJP13_SERVER_MAGIC ) & 0xff;
- header->lengthB0 = (length >> 8) & 0xff;
- header->lengthB1 = (length ) & 0xff;
- return AJP13_HEADER_LEN;
-}
-
-/**
- * The ajp13 protocol decoder will use this struct for storing state variables
- * used in decoding the stream
- */
-typedef struct {
- buffer *buf; /* holds raw header bytes or used to buffer STDERR */
- off_t offset; /* parse offset into buffer. */
- ajp13_packet packet; /* parsed info about current packet. */
- size_t chunk_len; /* chunk length */
- size_t requested_bytes; /* backend requested we send this many bytes of the request content. */
-} ajp13_state_data;
-
-static ajp13_state_data *ajp13_state_data_init(void) {
- ajp13_state_data *data;
-
- data = calloc(1, sizeof(*data));
- data->buf = buffer_init();
-
- return data;
-}
-
-static void ajp13_state_data_free(ajp13_state_data *data) {
- buffer_free(data->buf);
- free(data);
-}
-
-static void ajp13_state_data_reset(ajp13_state_data *data) {
- buffer_reset(data->buf);
- data->packet.len = 0;
- data->packet.offset = 0;
- data->packet.type = 0;
- data->offset = 0;
- data->chunk_len = 0;
-}
-
-/**
- * encode ajp13 byte/boolean
- */
-static int ajp13_encode_byte(buffer *buf, int val) {
-
- /* format : 2 bytes integer */
- buffer_prepare_append(buf, 1);
-
- buf->ptr[buf->used++] = val;
-
- return 1;
-}
-
-/**
- * encode ajp13 integer (2 bytes)
- */
-static int ajp13_encode_int(buffer *buf, int val) {
-
- /* format : 2 bytes integer */
- buffer_prepare_append(buf, 2);
-
- buf->ptr[buf->used++] = (val >> 8) & 0xff;
- buf->ptr[buf->used++] = (val >> 0) & 0xff;
-
- return 2;
-}
-
-/**
- * encode ajp13 string.
- */
-static int ajp13_encode_string(buffer *buf, const char *str, size_t str_len) {
- size_t len = 0;
-
- if (!str || str_len == 0) {
- return ajp13_encode_int(buf,0xFFFF);
- }
-
- /* format : 2 byte string length : string : null */
- len = 2 + str_len + 1;
-
- buffer_prepare_append(buf, len);
-
- ajp13_encode_int(buf,str_len);
- /* include the NUL */
- buffer_append_memory(buf, str, str_len + 1);
-
- return len;
-}
-
-/**
- * add a key-value pair to the ajp13-buffer
- */
-#define MAX_KEY_LEN 16
-static int ajp13_env_add(buffer *buf, const char *key, size_t key_len, const char *val, size_t val_len) {
- char uppercase_key[MAX_KEY_LEN];
- size_t len = 0;
- int code = -1;
- size_t i;
-
- if (!key || !val) return -1;
-
- if(key_len < MAX_KEY_LEN) {
- /* convert key to uppercase */
- for(i=0;i <key_len;i++) {
- uppercase_key[i] = toupper(key[i]);
- }
- uppercase_key[key_len] = '\0';
- code = keyvalue_get_key(request_headers, uppercase_key);
- }
- if(code >= 0) {
- len += ajp13_encode_int(buf, AJP13_COMMON_HEADER_CODE + code);
- } else {
- len += ajp13_encode_string(buf, key, key_len);
- }
- len += ajp13_encode_string(buf, val, val_len);
-
- return len;
-}
-
-/**
- * decode ajp13 integer (2 bytes)
- */
-static int ajp13_decode_int(ajp13_state_data *data) {
- int val = 0;
-
- if ((data->buf->used - data->offset) <= 2) return -1;
-
- val = (unsigned char)data->buf->ptr[data->offset++];
- val <<= 8;
- val |= (unsigned char)data->buf->ptr[data->offset++];
-
- return val;
-}
-
-/**
- * decode ajp13 string.
- */
-static int ajp13_decode_string(buffer *str, ajp13_state_data *data, int is_header) {
- size_t len = 0;
- const char *p = NULL;
-
- if (!str) {
- return len;
- }
-
- /* string length */
- len = ajp13_decode_int(data);
- if ((ssize_t)len == -1) {
- ERROR("ajp13_decode_int() returned invalid len: %zu", len);
- return len;
- }
-#ifdef AJP13_DEBUG
- TRACE("ajp13_decode_string() string-len: %zu (is_header: %d, common-header: %zd)", len, is_header, (len & AJP13_COMMON_HEADER_CODE));
-#endif
-
- /* if string is header, check for common header code. */
- if (is_header && (len & AJP13_COMMON_HEADER_CODE)) {
- p = keyvalue_get_value(response_headers, len & ~AJP13_COMMON_HEADER_CODE);
- if (p) {
- len = strlen(p);
- } else {
- ERROR("ajp13_decode_string() can't resolve common-header: %zd", len & ~AJP13_COMMON_HEADER_CODE);
-
- return -1;
- }
- }
- /* copy string from buffer. */
- if (p == NULL) {
- if ((data->buf->used - data->offset) <= (len + 1)) {
- ERROR("we have %jd bytes, but a partial-string wants %zu. no way", (intmax_t) (data->buf->used - data->offset), len);
- return -1;
- }
- p = data->buf->ptr + data->offset;
- data->offset += len + 1;
- }
- buffer_copy_string_len(str, p, len);
-
- return len;
-}
-
-/**
- * decode ajp13 response headers
- */
-static int ajp13_decode_response_headers(http_resp *resp, ajp13_state_data *data) {
- buffer *key, *value;
- int key_len, value_len;
- int i,num;
-
- resp->protocol = HTTP_VERSION_UNSET;
- resp->status = ajp13_decode_int(data);
-
- if (resp->status == -1) {
- ERROR("parsing AJP13 response-status failed, got %d", resp->status);
- return -1;
- }
-
- if (ajp13_decode_string(resp->reason, data, 0) == -1) {
- ERROR("parsing AJP13 response-reason failed: %s", "...");
- return -1;
- }
-
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header-status: %d", resp->status);
- TRACE("ajp13: header-reason: %s", resp->reason->ptr);
-#endif
-
- /* leave if we have no headers to decode */
- num = ajp13_decode_int(data);
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header-count: %d", num);
-#endif
-
- if (0 == num) return 0;
-
- key = buffer_init();
- value = buffer_init();
- for(i = 0; i < num; i++) {
- key_len = ajp13_decode_string(key, data, 1);
- value_len = ajp13_decode_string(value, data, 1);
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header[%d]: key-len: %d, value-len: %d", i, key_len, value_len);
-#endif
-
- if (key_len > 0 && value_len >= 0) {
- data_string *HDR;
- if (NULL == (HDR = (data_string *)array_get_unused_element(resp->headers, TYPE_STRING))) {
- HDR = data_response_init();
- }
-
- buffer_copy_string_len(HDR->key, key->ptr, key_len);
- buffer_copy_string_len(HDR->value, value->ptr, value_len);
-
- array_insert_unique(resp->headers, (data_unset *)HDR);
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header[%d]: %s = %s", i, key->ptr, value->ptr);
-#endif
- } else {
- ERROR("ajp13: response-headers skipped: key-len = %d, val-len = %d", key_len, value_len);
- }
- }
- buffer_free(key);
- buffer_free(value);
-
- return 0;
-}
-
-PROXY_CONNECTION_FUNC(proxy_ajp13_init) {
- UNUSED(srv);
-
- if(!proxy_con->protocol_data) {
- proxy_con->protocol_data = ajp13_state_data_init();
- }
- return 1;
-}
-
-PROXY_CONNECTION_FUNC(proxy_ajp13_cleanup) {
- UNUSED(srv);
-
- if(proxy_con->protocol_data) {
- ajp13_state_data_free((ajp13_state_data *)proxy_con->protocol_data);
- proxy_con->protocol_data = NULL;
- }
- return 1;
-}
-
-static int proxy_ajp13_forward_request(server *srv, connection *con, proxy_session *sess, buffer *packet) {
- char buf[32];
- const char *str;
- server_socket *srv_sock = con->srv_socket;
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-#endif
- int len = 0,port = 0;
- size_t i;
-
- /* prefix_code */
- len += ajp13_encode_byte(packet, AJP13_TYPE_FORWARD_REQUEST);
-
- /* http method */
- len += ajp13_encode_byte(packet, ajp13_convert_http_method(con->request.http_method));
-
- /* protocol */
- str = get_http_version_name(con->request.http_version);
- len += ajp13_encode_string(packet, str, strlen(str));
-
- /* request uri
- *
- * the docs where unspecific here, but it looks like tomcat wants to get
- * the uri without the query-string here */
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->uri.path));
-
- /* remote address */
- str = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- len += ajp13_encode_string(packet, str, strlen(str));
-
- /* remote host */
- len += ajp13_encode_string(packet, CONST_STR_LEN(""));
-
- /* server name */
- if (con->server_name->used) {
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->server_name));
- } else {
-#ifdef HAVE_IPV6
- str = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1);
-#else
- str = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
-#endif
- len += ajp13_encode_string(packet, str, strlen(str));
- }
-
- /* server port */
-#ifdef HAVE_IPV6
- port = ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port);
-#else
- port = ntohs(srv_sock->addr.ipv4.sin_port);
-#endif
- len += ajp13_encode_int(packet, port);
-
- /* is_ssl */
-#ifdef USE_OPENSSL
- len += ajp13_encode_byte(packet, srv_sock->is_ssl);
-#else
- len += ajp13_encode_byte(packet, 0);
-#endif
-
- /* make sure we have content-length header */
- if(con->request.content_length > 0) {
- LI_ltostr(buf, con->request.content_length);
- array_set_key_value(sess->request_headers, CONST_STR_LEN("Content-Length"), buf, strlen(buf));
- } else {
- array_set_key_value(sess->request_headers, CONST_STR_LEN("Content-Length"), CONST_STR_LEN("0"));
- }
-
- /* request headers count */
- len += ajp13_encode_int(packet, sess->request_headers->used);
-
- /* request headers */
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
- ds = (data_string *)sess->request_headers->data[i];
- len += ajp13_env_add(packet, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
- }
-
- /* remote user */
- if (!buffer_is_empty(con->authed_user)) {
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_REMOTE_USER);
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->authed_user));
- }
-
- /* query string */
- if (!buffer_is_empty(con->uri.query)) {
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_QUERY_STRING);
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->uri.query));
- }
-
- /* jvm_route */
- if (!buffer_is_empty(sess->proxy_con->address->name)) {
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_JVM_ROUTE);
- len += ajp13_encode_string(packet, CONST_BUF_LEN(sess->proxy_con->address->name));
- }
-
- /* request terminator */
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_ARE_DONE);
-
- return len;
-}
-
-PROXY_STREAM_ENCODER_FUNC(proxy_ajp13_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- ajp13_state_data *data = (ajp13_state_data *)proxy_con->protocol_data;
- chunkqueue *out = proxy_con->send;
- connection *con = sess->remote_con;
- buffer *packet;
- size_t len;
-
- UNUSED(srv);
- UNUSED(in);
-
- packet = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(packet, 1024);
-
- /* reserve bytes for header. Will over right header when we know packet length. */
- packet->used += AJP13_HEADER_LEN;
-
- /* send AJP13_TYPE_FORWARD_REQUEST */
- len = proxy_ajp13_forward_request(srv, con, sess, packet);
- packet->used++; /* this is needed because the network will only write "used - 1" bytes */
- out->bytes_in += packet->used - 1;
-
- /* rewrite packet header with correct length. */
- ajp13_header(packet->ptr, len);
-
- if(con->request.content_length > AJP13_MAX_BODY_PACKET_SIZE) {
- data->requested_bytes = AJP13_MAX_BODY_PACKET_SIZE;
- } else if(con->request.content_length > 0) {
- data->requested_bytes = con->request.content_length;
- } else {
- data->requested_bytes = 0;
- }
-
- return HANDLER_FINISHED;
-}
-
-/*
- * copy len bytes from chunk-chain into buffer
- */
-static int proxy_ajp13_fill_buffer(ajp13_state_data *data, chunkqueue *in, size_t len) {
- off_t we_have = 0, we_need = len;
- chunk *c;
-
- buffer_prepare_append(data->buf, we_need);
- for (c = in->first; c && we_need > 0; c = c->next) {
- if(c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- if (we_have == 0) continue;
- if (we_have > we_need) we_have = we_need;
-
- buffer_append_string_len(data->buf, c->mem->ptr + c->offset, we_have);
- data->packet.offset += we_have;
- c->offset += we_have;
- in->bytes_out += we_have;
- we_need -= we_have;
- }
- return we_need;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_ajp13_stream_decoder_internal) {
- proxy_connection *proxy_con = sess->proxy_con;
- ajp13_state_data *data = (ajp13_state_data *)proxy_con->protocol_data;
- chunkqueue *in = proxy_con->recv;
- AJP13_Header *header;
- size_t we_parsed = 0, we_need = 0;
- handler_t rc = HANDLER_GO_ON;
- int magic = 0;
- int reuse = 0;
-
- UNUSED(srv);
-
- /* no data ? */
- if (!in->first) return HANDLER_WAIT_FOR_EVENT;
-
- /* parse the packet header. */
- if(data->packet.offset < AJP13_FULL_HEADER_LEN) {
- we_need = (AJP13_FULL_HEADER_LEN - data->packet.offset);
- /* copy ajp13 header to buffer */
- we_need = proxy_ajp13_fill_buffer(data, in, we_need);
- /* make sure we have the full ajp13 header. */
- if(we_need > 0) {
- /* we need more data to parse the header. */
- return HANDLER_WAIT_FOR_EVENT;
- }
- /* parse raw header. */
- header = (AJP13_Header *)(data->buf->ptr);
-
- data->packet.len = ((header->lengthB0 << 8) | header->lengthB1);
- data->packet.len--; /* packet type byte already parsed. */
- data->packet.type = header->type;
- magic = ((header->magicB0 << 8) | header->magicB1);
- if (magic != AJP13_CONTAINER_MAGIC) {
- ERROR("%s", "bad ajp13 magic code, invalid protocl stream");
- return HANDLER_ERROR;
- }
-
- /* Finished parsing raw header bytes. */
- buffer_reset(data->buf);
- }
-
- /* for most packet types copy the content into the data buffer */
- if (data->packet.type != AJP13_TYPE_SEND_BODY_CHUNK) {
- we_need = data->packet.len - (data->packet.offset - AJP13_FULL_HEADER_LEN);
- if(we_need > 0) {
- /* copy ajp13 packet contents to buffer */
- we_need = proxy_ajp13_fill_buffer(data, in, we_need);
- /* make sure we have the full ajp13 packet content. */
- if(we_need > 0) {
- /* we need more data to parse the content. */
- return HANDLER_WAIT_FOR_EVENT;
- }
- }
- }
-
- switch (data->packet.type) {
- case AJP13_TYPE_GET_BODY_CHUNK:
- data->requested_bytes = ajp13_decode_int(data);
- break;
- case AJP13_TYPE_SEND_HEADERS:
- if (ajp13_decode_response_headers(sess->resp, data) == -1) {
- ERROR("%s", "Error parsing response_headers");
- rc = HANDLER_ERROR;
- }
- sess->have_response_headers = 1;
- break;
- case AJP13_TYPE_SEND_BODY_CHUNK:
- /* parse chunk length */
- we_parsed = (data->packet.offset - AJP13_FULL_HEADER_LEN);
- if (we_parsed < 2) {
- we_need = 2 - we_parsed;
- /* copy chunk length bytes to buffer */
- we_need = proxy_ajp13_fill_buffer(data, in, we_need);
- if(we_need > 0) {
- /* we need more data to parse the chunk length. */
- return HANDLER_WAIT_FOR_EVENT;
- }
- /* parse chunk length */
- data->chunk_len = ajp13_decode_int(data);
- }
- /* parse chunk data. */
- we_parsed = (data->packet.offset - 2 - AJP13_FULL_HEADER_LEN);
- if(we_parsed < data->chunk_len) {
- we_need = data->chunk_len - we_parsed;
- /* copy chunk data */
- we_parsed = chunkqueue_steal_chunks_len(out, in->first, we_need);
- data->packet.offset += we_parsed;
- we_need -= we_parsed;
- in->bytes_out += we_parsed;
- out->bytes_in += we_parsed;
- }
- we_need = data->packet.len - (data->packet.offset - AJP13_FULL_HEADER_LEN);
- /* ignore padding */
- if(we_need > 0) {
- we_parsed = chunkqueue_skip(in, we_need);
- data->packet.offset += we_parsed;
- we_need -= we_parsed;
- in->bytes_out += we_parsed;
- }
- rc = HANDLER_GO_ON;
- break;
- case AJP13_TYPE_END_RESPONSE:
- if(data->buf->used >= 1) {
- reuse = data->buf->ptr[0];
- }
- if(reuse != 1) {
- sess->is_closing = 1;
- }
- sess->is_request_finished = 1;
- /* close the queues. no more data to decode. */
- in->is_closed = 1;
- out->is_closed = 1;
- /* make sure the send queue is closed, since we can't send any more request content. */
- proxy_con->send->is_closed = 1;
- rc = HANDLER_FINISHED;
- break;
- default:
- TRACE("unknown packet.type: %d", data->packet.type);
- rc = HANDLER_ERROR;
- break;
- }
-
- if(we_need == 0) {
- /* packet finished, reset state for next packet */
- ajp13_state_data_reset(data);
- }
-
- chunkqueue_remove_finished_chunks(in);
-
- return rc;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_ajp13_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- int res;
-
- if(out->is_closed) return 1;
- /* decode the whole packet stream */
- do {
- /* decode the packet */
- res = proxy_ajp13_stream_decoder_internal(srv, sess, out);
- } while (in->first && res == HANDLER_GO_ON);
-
- if (res == HANDLER_WAIT_FOR_EVENT) {
- if (in->is_closed) return HANDLER_ERROR;
- return HANDLER_GO_ON;
- }
-
- return res;
-}
-
-/**
- * transform the content-stream into a valid FastCGI STDIN content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_ajp13_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- ajp13_state_data *data = (ajp13_state_data *)proxy_con->protocol_data;
- chunkqueue *out = proxy_con->send;
- size_t we_need = 0, we_have = 0;
- buffer *b;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- if (data->requested_bytes == 0) {
- /* backend needs to send a request for more content before we can encode more. */
- return HANDLER_GO_ON;
- }
-
- /* calculate how many bytes we can encode. */
- if (in->bytes_in > in->bytes_out) {
- we_need = in->bytes_in - in->bytes_out;
- if (we_need > AJP13_MAX_BODY_PACKET_SIZE) we_need = AJP13_MAX_BODY_PACKET_SIZE;
- if (we_need > data->requested_bytes) we_need = data->requested_bytes;
-
- data->requested_bytes = 0;
- }
- /*
- * write ajp13 header
- */
- b = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(b, AJP13_HEADER_LEN);
- b->used += AJP13_HEADER_LEN;
- if (we_need > 0) {
- ajp13_header(b->ptr, we_need + 2);
- ajp13_encode_int(b, we_need);
- } else {
- /* empty body packet to mark EOF, if the backend requested data beyond
- * the end of the request content.
- */
- ajp13_header(b->ptr, we_need);
- }
- out->bytes_in += b->used;
- b->used++;
-
- we_have = chunkqueue_steal_chunks_len(out, in->first, we_need);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
-
- if (in->bytes_in == in->bytes_out && in->is_closed) {
- /* We are finished encoding the request content,
- * but we can't close the send queue here since the backend might
- * try to request more request content then is available and
- * we will have to response with a 0 length body packet.
- */
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-INIT_FUNC(mod_proxy_backend_ajp13_init) {
- mod_proxy_core_plugin_data *core_data;
- protocol_plugin_data *p;
-
- /* get the plugin_data of the core-plugin */
- core_data = plugin_get_config(srv, CORE_PLUGIN);
- if(!core_data) return NULL;
-
- p = calloc(1, sizeof(*p));
-
- /* define protocol handler callbacks */
- p->protocol = core_data->proxy_register_protocol("ajp13");
-
- p->protocol->proxy_stream_init = proxy_ajp13_init;
- p->protocol->proxy_stream_cleanup = proxy_ajp13_cleanup;
- p->protocol->proxy_stream_decoder = proxy_ajp13_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_ajp13_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_ajp13_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_ajp13_free) {
- protocol_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_backend_ajp13_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_ajp13_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_ajp13");
-
- p->init = mod_proxy_backend_ajp13_init;
- p->cleanup = mod_proxy_backend_ajp13_free;
-
- p->data = NULL;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-
-
diff --git a/src/mod_proxy_backend_fastcgi.c b/src/mod_proxy_backend_fastcgi.c
deleted file mode 100644
index 3ba7c5e6..00000000
--- a/src/mod_proxy_backend_fastcgi.c
+++ /dev/null
@@ -1,819 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "sys-strings.h"
-#include "inet_ntop_cache.h"
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "buffer.h"
-#include "log.h"
-#include "fastcgi.h"
-#include "array.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-/**
- * we aren't supporting multiplexing
- *
- * use always the same request-id
- */
-#define PROXY_FASTCGI_REQUEST_ID 1
-#if 1
-#define PROXY_FASTCGI_USE_KEEP_ALIVE 1
-#endif
-
-typedef struct {
- size_t len;
- off_t offset;
- int type;
- int padding;
- size_t request_id;
-} fastcgi_packet;
-
-/**
- * The fastcgi protocol decoder will use this struct for storing state variables
- * used in decoding the stream
- */
-typedef struct {
- buffer *buf; /* holds raw header bytes or used to buffer STDERR */
- fastcgi_packet packet; /* parsed info about current packet. */
- int is_complete;
-} fcgi_state_data;
-
-static fcgi_state_data *fcgi_state_data_init(void) {
- fcgi_state_data *data;
-
- data = calloc(1, sizeof(*data));
- data->buf = buffer_init();
-
- return data;
-}
-
-static void fcgi_state_data_free(fcgi_state_data *data) {
- buffer_free(data->buf);
- free(data);
-}
-
-static void fcgi_state_data_reset(fcgi_state_data *data) {
- buffer_reset(data->buf);
- data->packet.len = 0;
- data->packet.offset = 0;
- data->packet.type = 0;
- data->packet.padding = 0;
- data->packet.request_id = 0;
- data->is_complete = 0;
-}
-
-PROXY_CONNECTION_FUNC(proxy_fastcgi_init) {
- UNUSED(srv);
-
- if(!proxy_con->protocol_data) {
- proxy_con->protocol_data = fcgi_state_data_init();
- }
- return 1;
-}
-
-PROXY_CONNECTION_FUNC(proxy_fastcgi_cleanup) {
- UNUSED(srv);
-
- if(proxy_con->protocol_data) {
- fcgi_state_data_free((fcgi_state_data *)proxy_con->protocol_data);
- proxy_con->protocol_data = NULL;
- }
- return 1;
-}
-
-static int proxy_fastcgi_get_env_fastcgi(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
- char buf[32];
- const char *s;
- server_socket *srv_sock = con->srv_socket;
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-#endif
-
- sock_addr our_addr;
- socklen_t our_addr_len;
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
-
- if (con->server_name->used) {
- size_t len = con->server_name->used - 1;
- char *colon = strchr(con->server_name->ptr, ':');
- if (colon) len = colon - con->server_name->ptr;
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
- } else {
-#ifdef HAVE_IPV6
- s = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1);
-#else
- s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
-#endif
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
- }
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
-
- LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
-#else
- ntohs(srv_sock->addr.ipv4.sin_port)
-#endif
- );
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
-
- /* get the server-side of the connection to the client */
- our_addr_len = sizeof(our_addr);
-
- if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
- s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
- } else {
- s = inet_ntop_cache_get_ip(srv, &(our_addr));
- }
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
-
- LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
-#else
- ntohs(con->dst_addr.ipv4.sin_port)
-#endif
- );
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
-
- s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
-
- if (!buffer_is_empty(con->authed_user)) {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REMOTE_USER"),
- CONST_BUF_LEN(con->authed_user));
- }
-
- if (con->request.content_length > 0) {
- /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
-
- /* request.content_length < SSIZE_MAX, see request.c */
- LI_ltostr(buf, con->request.content_length);
- array_set_key_value(sess->env_headers, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
- }
-
-
- /*
- * 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)
- * For AUTHORIZER mode these headers should be omitted.
- */
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
-
- if (!buffer_is_empty(con->request.pathinfo)) {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
-
- /* PATH_TRANSLATED is only defined if PATH_INFO is set */
-
- buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
- buffer_append_string_buffer(p->tmp_buf, con->request.pathinfo);
- array_set_key_value(sess->env_headers, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->tmp_buf));
- } else {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
- }
-
- /*
- * 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.
- * TODO: this code should be checked against cgi.fix_pathinfo php
- * parameter.
- */
-
- if (1) {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
- array_set_key_value(sess->env_headers, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
- }
-
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
-
- if (!buffer_is_equal(sess->request_uri, con->request.orig_uri)) {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(sess->request_uri));
- }
- if (!buffer_is_empty(con->uri.query)) {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
- } else {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
- }
-
- s = get_http_method_name(con->request.http_method);
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
- array_set_key_value(sess->env_headers, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
- s = get_http_version_name(con->request.http_version);
- array_set_key_value(sess->env_headers, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
-
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- array_set_key_value(sess->env_headers, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
- }
-#endif
-
- return 0;
-}
-
-/**
- * transform the HTTP-Request headers into CGI notation
- */
-static int proxy_fastcgi_get_env_request(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
- size_t i;
-
- UNUSED(srv);
- UNUSED(con);
-
- /* the request header got already copied into the sess->request_headers for us
- * no extra filter is needed
- *
- * prepend a HTTP_ and uppercase the keys
- */
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
- size_t j;
-
- ds = (data_string *)sess->request_headers->data[i];
-
- buffer_reset(p->tmp_buf);
-
- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_"));
- p->tmp_buf->used--;
- }
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = '_';
- if (light_isalpha(ds->key->ptr[j])) {
- /* upper-case */
- c = ds->key->ptr[j] & ~32;
- } else if (light_isdigit(ds->key->ptr[j])) {
- /* copy */
- c = ds->key->ptr[j];
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = c;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- array_set_key_value(sess->env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
-
- for (i = 0; i < con->environment->used; i++) {
- data_string *ds;
- size_t j;
-
- ds = (data_string *)con->environment->data[i];
-
- buffer_reset(p->tmp_buf);
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = '_';
- if (light_isalpha(ds->key->ptr[j])) {
- /* upper-case */
- c = ds->key->ptr[j] & ~32;
- } else if (light_isdigit(ds->key->ptr[j])) {
- /* copy */
- c = ds->key->ptr[j];
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = c;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- array_set_key_value(sess->env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
-
- return 0;
-}
-
-
-/**
- * add a key-value pair to the fastcgi-buffer
- */
-
-static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
- size_t len;
-
- if (!key || !val) return -1;
-
- len = key_len + val_len;
-
- len += key_len > 127 ? 4 : 1;
- len += val_len > 127 ? 4 : 1;
-
- /**
- * ensure we don't create a longer packet than fastcgi can handle
- */
- if (env->used + len >= FCGI_MAX_LENGTH) {
- return -1;
- }
-
- buffer_prepare_append(env, len);
-
- if (key_len > 127) {
- env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
- env->ptr[env->used++] = (key_len >> 16) & 0xff;
- env->ptr[env->used++] = (key_len >> 8) & 0xff;
- env->ptr[env->used++] = (key_len >> 0) & 0xff;
- } else {
- env->ptr[env->used++] = (key_len >> 0) & 0xff;
- }
-
- if (val_len > 127) {
- env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
- env->ptr[env->used++] = (val_len >> 16) & 0xff;
- env->ptr[env->used++] = (val_len >> 8) & 0xff;
- env->ptr[env->used++] = (val_len >> 0) & 0xff;
- } else {
- env->ptr[env->used++] = (val_len >> 0) & 0xff;
- }
-
- memcpy(env->ptr + env->used, key, key_len);
- env->used += key_len;
- memcpy(env->ptr + env->used, val, val_len);
- env->used += val_len;
-
- return 0;
-}
-
-/**
- * init the FCGI_header
- */
-static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {
- 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;
-
- return 0;
-}
-
-
-PROXY_STREAM_ENCODER_FUNC(proxy_fastcgi_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- connection *con = sess->remote_con;
- buffer *b, *packet;
- size_t i;
- FCGI_BeginRequestRecord beginRecord;
- FCGI_Header header;
- plugin_data *p = sess->p;
-
- UNUSED(srv);
- UNUSED(in);
-
- b = chunkqueue_get_append_buffer(out);
- /* send FCGI_BEGIN_REQUEST */
-
- fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, PROXY_FASTCGI_REQUEST_ID, sizeof(beginRecord.body), 0);
- beginRecord.body.roleB0 = FCGI_RESPONDER;
- beginRecord.body.roleB1 = 0;
-#ifdef PROXY_FASTCGI_USE_KEEP_ALIVE
- if (p->conf.max_keep_alive_requests && p->conf.max_pool_size) {
- /**
- * only announce keep-alive if we really can handle it
- */
- beginRecord.body.flags = FCGI_KEEP_CONN;
- } else {
- beginRecord.body.flags = 0;
- }
-#else
- beginRecord.body.flags = 0;
-#endif
- memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
-
- buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
- out->bytes_in += sizeof(beginRecord);
-
- /* send FCGI_PARAMS */
- b = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(b, 1024);
-
- /* fill the sess->env_headers */
- array_reset(sess->env_headers);
- proxy_fastcgi_get_env_request(srv, con, p, sess);
- proxy_fastcgi_get_env_fastcgi(srv, con, p, sess);
-
- packet = buffer_init();
-
- for (i = 0; i < sess->env_headers->used; i++) {
- data_string *ds;
-
- ds = (data_string *)sess->env_headers->data[i];
- fcgi_env_add(packet, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
- }
-
- fcgi_header(&(header), FCGI_PARAMS, PROXY_FASTCGI_REQUEST_ID, packet->used, 0);
- buffer_append_memory(b, (const char *)&header, sizeof(header));
- buffer_append_memory(b, (const char *)packet->ptr, packet->used);
- out->bytes_in += sizeof(header);
- out->bytes_in += packet->used - 1;
-
- buffer_free(packet);
-
- fcgi_header(&(header), FCGI_PARAMS, PROXY_FASTCGI_REQUEST_ID, 0, 0);
- buffer_append_memory(b, (const char *)&header, sizeof(header));
- b->used++;
- out->bytes_in += sizeof(header) + 1;
-
- return HANDLER_FINISHED;
-}
-
-/**
- * parse the HTTP response header
- */
-static handler_t proxy_fastcgi_http_response_headers(proxy_session *sess, chunkqueue *in) {
- http_response_reset(sess->resp);
-
- /* http response parser. */
- switch(http_response_parse_cq(in, sess->resp)) {
- case PARSE_ERROR:
- /* bad gateway */
- http_response_reset(sess->resp);
- sess->have_response_headers = 1;
- sess->resp->status = 502;
- return HANDLER_ERROR;
- case PARSE_NEED_MORE:
- return HANDLER_GO_ON;
- case PARSE_SUCCESS:
- default:
- /* finished parsing response headers. */
- sess->have_response_headers = 1;
- return HANDLER_FINISHED;
- }
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_fastcgi_stream_decoder_internal) {
- proxy_connection *proxy_con = sess->proxy_con;
- fcgi_state_data *data = (fcgi_state_data *)proxy_con->protocol_data;
- chunkqueue *in = proxy_con->recv;
- FCGI_Header *header;
- off_t we_have = 0, we_need = 0;
- handler_t rc = HANDLER_GO_ON;
- chunk *c;
-
- UNUSED(srv);
-
- if ((in->bytes_in == in->bytes_out) && in->is_closed) {
- /* everything got passed through,
- *
- * as we usually have a FIN packet we should expect to get a is_closed within the
- * fcgi-stream. Looks like the remote side crashed
- * */
- out->is_closed = 1;
-
- TRACE("%jd / %jd -> %d",
- (intmax_t) in->bytes_in, (intmax_t) in->bytes_out,
- in->is_closed);
-
-
- ERROR("looks like the fastcgi-backend (%s) terminated before it sent a FIN packet", SAFE_BUF_STR(sess->request_uri));
-
- return HANDLER_FINISHED;
- }
-
- /* no data ? */
- if (!in->first) return HANDLER_GO_ON;
-
- /* a single network packet might contain multiple fcgi packets */
- if(!data->is_complete) {
- we_need = (FCGI_HEADER_LEN - data->packet.offset);
-
- /**
- * a the fcgi header might spread over multiple network packets
- */
- for (c = in->first; c && we_need > 0; c = c->next) {
- if (c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- if (we_have == 0) continue;
- if (we_have > we_need) we_have = we_need;
-
- buffer_append_string_len(data->buf, c->mem->ptr + c->offset, we_have);
- data->packet.offset += we_have;
- c->offset += we_have;
- in->bytes_out += we_have;
- we_need -= we_have;
- }
- /* make sure we have the full fastcgi header. */
- if(we_need > 0) {
- chunkqueue_remove_finished_chunks(in);
- /* we need more data to parse the header. */
- return HANDLER_GO_ON;
- }
-
- /* parse raw header. */
- header = (FCGI_Header *)(data->buf->ptr);
-
- data->packet.len = (header->contentLengthB0 | (header->contentLengthB1 << 8));
- data->packet.request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
- data->packet.type = header->type;
- data->packet.padding = header->paddingLength;
- data->is_complete = 1;
-
- /* Finished parsing raw header bytes. */
- buffer_reset(data->buf);
- }
-
- /* proccess the packet's contents. */
- we_need = data->packet.len - (data->packet.offset - FCGI_HEADER_LEN);
-
- switch (data->packet.type) {
- case FCGI_STDOUT:
- if (we_need > 0) {
- /* copy packet contents */
- we_have = chunkqueue_steal_chunks_len(out, in->first, we_need);
- data->packet.offset += we_have;
- we_need -= we_have;
- in->bytes_out += we_have;
- out->bytes_in += we_have;
- } else {
- /**
- * we might come here again if the padding is part of the next packet
- *
- * read(15, "\1\6\0\1\1D\4\0", 16384) = 8
- * read(15, "Status: 200 Ok\r\nCache-contro...
- * read(15, "\0\0\0\0\1\6\0\1\37\370\0\0", 16384) = 12
- *
- */
-#if 0
- /* FIXME: for which case did we set this to 1 ? */
- out->is_closed = 1;
-#endif
- }
-
- /* parse response headers. */
- if (!sess->have_response_headers) {
- /* check if we have all the response headers */
- switch (proxy_fastcgi_http_response_headers(sess, out)) {
- case HANDLER_FINISHED:
- /* the headers are complete */
-
- rc = HANDLER_GO_ON;
- break;
- case HANDLER_GO_ON:
- /* no finished yet */
- rc = HANDLER_GO_ON;
- break;
- default:
- /* something failed */
- rc = HANDLER_ERROR;
- break;
- }
- } else {
- rc = HANDLER_GO_ON;
- }
- break;
- case FCGI_STDERR:
- if(we_need > 0) {
- buffer *b = buffer_init();
- buffer_prepare_append(b, we_need);
- for (c = in->first; c && we_need > 0; c = c->next) {
- if (c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- if (we_have == 0) continue;
- if (we_have > we_need) we_have = we_need;
-
- buffer_append_string_len(b, c->mem->ptr + c->offset, we_have);
- data->packet.offset += we_have;
- c->offset += we_have;
- in->bytes_out += we_have;
- we_need -= we_have;
- }
-/**
-==18752== Conditional jump or move depends on uninitialised value(s)
-==18752== at 0x401D255: strlen (mc_replace_strmem.c:246)
-==18752== by 0x42B7A1B: vfprintf (in /lib/tls/i686/cmov/libc-2.3.6.so)
-==18752== by 0x42D6280: vsnprintf (in /lib/tls/i686/cmov/libc-2.3.6.so)
-==18752== by 0x805EAAD: log_trace (log.c:325)
-==18752== by 0x4513C5B: proxy_fastcgi_stream_decoder (mod_proxy_backend_fastcgi.c:594)
-==18752== by 0x4565130: proxy_stream_decoder (mod_proxy_core.c:587)
-==18752== by 0x4565D46: proxy_stream_encode_decode (mod_proxy_core.c:855)
-==18752== by 0x4567D69: proxy_state_engine (mod_proxy_core.c:1567)
-==18752== by 0x45686C7: mod_proxy_core_start_backend (mod_proxy_core.c:2397)
-==18752== by 0x4568CBC: mod_proxy_send_request_content (mod_proxy_core.c:2441)
-==18752== by 0x80634EC: plugins_call_handle_send_request_content (plugin.c:387)
-==18752== by 0x8054CE7: connection_state_machine (connections.c:1192)
-==18752==
-==18752== Syscall param write(buf) points to uninitialised byte(s)
-==18752== at 0x4000792: (within /lib/ld-2.3.6.so)
-==18752== by 0x4513C5B: proxy_fastcgi_stream_decoder (mod_proxy_backend_fastcgi.c:594)
-==18752== by 0x4565130: proxy_stream_decoder (mod_proxy_core.c:587)
-==18752== by 0x4565D46: proxy_stream_encode_decode (mod_proxy_core.c:855)
-==18752== by 0x4567D69: proxy_state_engine (mod_proxy_core.c:1567)
-==18752== by 0x45686C7: mod_proxy_core_start_backend (mod_proxy_core.c:2397)
-==18752== by 0x4568CBC: mod_proxy_send_request_content (mod_proxy_core.c:2441)
-==18752== by 0x80634EC: plugins_call_handle_send_request_content (plugin.c:387)
-==18752== by 0x8054CE7: connection_state_machine (connections.c:1192)
-==18752== by 0x804F5D8: lighty_mainloop (server.c:1001)
-==18752== by 0x80517AE: main (server.c:1705)
-==18752== Address 0x4A7C899 is 81 bytes inside a block of size 4,160 alloc'd
-==18752== at 0x401C4B0: malloc (vg_replace_malloc.c:149)
-==18752== by 0x805DCFA: buffer_prepare_copy (buffer.c:85)
-==18752== by 0x805EA7E: log_trace (log.c:321)
-==18752== by 0x4513C5B: proxy_fastcgi_stream_decoder (mod_proxy_backend_fastcgi.c:594)
-==18752== by 0x4565130: proxy_stream_decoder (mod_proxy_core.c:587)
-==18752== by 0x4565D46: proxy_stream_encode_decode (mod_proxy_core.c:855)
-==18752== by 0x4567D69: proxy_state_engine (mod_proxy_core.c:1567)
-==18752== by 0x45686C7: mod_proxy_core_start_backend (mod_proxy_core.c:2397)
-==18752== by 0x4568CBC: mod_proxy_send_request_content (mod_proxy_core.c:2441)
-==18752== by 0x80634EC: plugins_call_handle_send_request_content (plugin.c:387)
-==18752== by 0x8054CE7: connection_state_machine (connections.c:1192)
-==18752== by 0x804F5D8: lighty_mainloop (server.c:1001)
-mod_proxy_backend_fastcgi.c.597: (trace) (stderr from 127.0.0.1:9090 for /trac/) SERVER_ADDR
-*/
- TRACE("(stderr from %s for %s) %s",
- SAFE_BUF_STR(proxy_con->address->name),
- SAFE_BUF_STR(sess->remote_con->uri.path),
- SAFE_BUF_STR(b));
- buffer_free(b);
- }
- rc = HANDLER_GO_ON;
- break;
- case FCGI_END_REQUEST:
- /* ignore packet content. */
- if(we_need > 0) {
- we_have = chunkqueue_skip(in, we_need);
- data->packet.offset += we_have;
- we_need -= we_have;
- in->bytes_out += we_have;
- }
- if(we_need == 0) {
-#ifndef PROXY_FASTCGI_USE_KEEP_ALIVE
- sess->is_closing = 1;
-#endif
- sess->have_response_headers = 1;
- sess->is_request_finished = 1;
- in->is_closed = 1;
- out->is_closed = 1;
- rc = HANDLER_FINISHED;
- }
- break;
- default:
- TRACE("unknown packet.type: %d", data->packet.type);
- rc = HANDLER_ERROR;
- break;
- }
-
- /* skip packet padding, once content has been processed. */
- if(we_need == 0 && data->packet.padding > 0) {
- we_have = chunkqueue_skip(in, data->packet.padding);
- data->packet.padding -= we_have;
- in->bytes_out += we_have;
- }
-
- if(we_need == 0 && data->packet.padding == 0) {
- /* packet finished, reset state for next packet */
- fcgi_state_data_reset(data);
- }
-
- chunkqueue_remove_finished_chunks(in);
-
- return rc;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_fastcgi_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- int res;
-
- if(out->is_closed) return HANDLER_FINISHED;
- /* decode the whole packet stream */
- do {
- /* decode the packet */
- res = proxy_fastcgi_stream_decoder_internal(srv, sess, out);
- } while (in->first && res == HANDLER_GO_ON);
-
- return res;
-}
-
-/**
- * transform the content-stream into a valid FastCGI STDIN content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_fastcgi_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- chunk *c;
- buffer *b;
- FCGI_Header header;
- off_t we_need = 0, we_have = 0;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- /* encode data into output queue. */
- for (c = in->first; in->bytes_out < in->bytes_in; ) {
- /*
- * write fcgi header
- */
- if(we_need == 0) {
- we_need = in->bytes_in - in->bytes_out;
- if(we_need > FCGI_MAX_LENGTH) we_need = FCGI_MAX_LENGTH;
-
- b = chunkqueue_get_append_buffer(out);
- fcgi_header(&(header), FCGI_STDIN, PROXY_FASTCGI_REQUEST_ID, we_need, 0);
- buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1);
- out->bytes_in += sizeof(header);
- }
-
- we_have = chunkqueue_steal_chunks_len(out, c, we_need);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
- we_need -= we_have;
- }
-
- if (in->bytes_in == in->bytes_out && in->is_closed && !out->is_closed) {
- /* send the closing packet */
- b = chunkqueue_get_append_buffer(out);
- /* terminate STDIN */
- fcgi_header(&(header), FCGI_STDIN, PROXY_FASTCGI_REQUEST_ID, 0, 0);
- buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1);
-
- out->bytes_in += sizeof(header);
- out->is_closed = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-INIT_FUNC(mod_proxy_backend_fastcgi_init) {
- mod_proxy_core_plugin_data *core_data;
- protocol_plugin_data *p;
-
- /* get the plugin_data of the core-plugin */
- core_data = plugin_get_config(srv, CORE_PLUGIN);
- if(!core_data) return NULL;
-
- p = calloc(1, sizeof(*p));
-
- /* define protocol handler callbacks */
- p->protocol = core_data->proxy_register_protocol("fastcgi");
-
- p->protocol->proxy_stream_init = proxy_fastcgi_init;
- p->protocol->proxy_stream_cleanup = proxy_fastcgi_cleanup;
- p->protocol->proxy_stream_decoder = proxy_fastcgi_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_fastcgi_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_fastcgi_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_fastcgi_free) {
- protocol_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_backend_fastcgi_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_fastcgi_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_fastcgi");
-
- p->init = mod_proxy_backend_fastcgi_init;
- p->cleanup = mod_proxy_backend_fastcgi_free;
-
- p->data = NULL;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-
-
diff --git a/src/mod_proxy_backend_http.c b/src/mod_proxy_backend_http.c
deleted file mode 100644
index a56bd602..00000000
--- a/src/mod_proxy_backend_http.c
+++ /dev/null
@@ -1,423 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "configfile.h"
-#include "buffer.h"
-#include "log.h"
-#include "sys-strings.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-typedef enum {
- HTTP_CHUNK_LEN,
- HTTP_CHUNK_EXTENSION,
- HTTP_CHUNK_DATA,
- HTTP_CHUNK_END
-} http_chunk_state_t;
-
-/**
- * The protocol will use this struct for storing state variables
- * used in decoding the stream
- */
-typedef struct {
- http_chunk_state_t chunk_parse_state;
- off_t chunk_len;
- off_t chunk_offset;
- buffer *buf;
-} protocol_state_data;
-
-static protocol_state_data *protocol_state_data_init(void) {
- protocol_state_data *data;
-
- data = calloc(1, sizeof(*data));
- data->chunk_parse_state = HTTP_CHUNK_LEN;
- data->buf = buffer_init();
-
- return data;
-}
-
-static void protocol_state_data_free(protocol_state_data *data) {
- buffer_free(data->buf);
- free(data);
-}
-
-static void protocol_state_data_reset(protocol_state_data *data) {
- buffer_reset(data->buf);
- data->chunk_parse_state = HTTP_CHUNK_LEN;
-}
-
-PROXY_CONNECTION_FUNC(proxy_http_init) {
-
- UNUSED(srv);
-
- if(!proxy_con->protocol_data) {
- proxy_con->protocol_data = protocol_state_data_init();
- }
- return 1;
-}
-
-PROXY_CONNECTION_FUNC(proxy_http_cleanup) {
-
- UNUSED(srv);
-
- if(proxy_con->protocol_data) {
- protocol_state_data_free((protocol_state_data *)proxy_con->protocol_data);
- proxy_con->protocol_data = NULL;
- }
- return 1;
-}
-
-/**
- * parse the HTTP response header
- */
-static handler_t proxy_http_parse_response_headers(proxy_session *sess, chunkqueue *in) {
- data_string *ds;
-
- http_response_reset(sess->resp);
-
- /* http response parser. */
- switch(http_response_parse_cq(in, sess->resp)) {
- case PARSE_ERROR:
- /* bad gateway */
- http_response_reset(sess->resp);
- sess->have_response_headers = 1;
- sess->resp->status = 502;
- return HANDLER_ERROR;
- case PARSE_NEED_MORE:
- return HANDLER_GO_ON;
- case PARSE_SUCCESS:
- default:
- break;
- }
- /* check for Transfer-Encoding header. */
- if (NULL != (ds = (data_string *)array_get_element(sess->resp->headers, CONST_STR_LEN("Transfer-Encoding")))) {
- if (strstr(ds->value->ptr, "chunked")) {
- sess->is_chunked = 1;
- }
- }
- /* finished parsing response headers. */
- sess->have_response_headers = 1;
-
- switch (sess->resp->status) {
- case 205: /* class: header only */
- case 304:
- sess->is_request_finished = 1;
- }
- return HANDLER_FINISHED;
-}
-
-static handler_t proxy_http_parse_chunked_stream(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
- protocol_state_data *data = (protocol_state_data *)sess->proxy_con->protocol_data;
- char *err = NULL;
- off_t we_have = 0, we_want = 0;
- off_t chunk_len = 0;
- off_t offset = 0;
- buffer *b;
- chunk *c;
- char ch = '\0';
- int finished = 0;
-
- UNUSED(srv);
-
- for (c = in->first; c && !finished;) {
- if(c->mem->used == 0) {
- c = c->next;
- continue;
- }
- switch(data->chunk_parse_state) {
- case HTTP_CHUNK_LEN:
- /* parse chunk len. */
- for(offset = c->offset; (size_t)(offset) < (c->mem->used - 1) ; offset++) {
- ch = c->mem->ptr[offset];
- if(!light_isxdigit(ch)) break;
- }
- if(offset > c->offset) {
- buffer_append_string_len(data->buf, (c->mem->ptr + c->offset), offset - c->offset);
- in->bytes_out += (offset - c->offset);
- c->offset = offset;
- }
- if ( (size_t)offset == c->mem->used - 1) {
- break; /* get next chunk from queue */
- }
- /* now ch is the last character, and it wasn't an xdigit */
- if (!(ch == ' ' || ch == '\r' || ch == ';')) {
- /* protocol error. bad http-chunk len */
- return HANDLER_ERROR;
- }
- data->chunk_len = strtol(BUF_STR(data->buf), &err, 16);
- data->chunk_offset = 0;
- buffer_reset(data->buf);
- data->chunk_parse_state = HTTP_CHUNK_EXTENSION;
- case HTTP_CHUNK_EXTENSION:
- /* find CRLF. discard chunk-extension */
- for(ch = 0; (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) {
- ch = c->mem->ptr[c->offset];
- c->offset++;
- in->bytes_out++;
- }
- if(ch != '\n') {
- /* get next chunk from queue */
- break;
- }
- if(data->chunk_len > 0) {
- data->chunk_parse_state = HTTP_CHUNK_DATA;
- } else {
- data->chunk_parse_state = HTTP_CHUNK_END;
- }
- case HTTP_CHUNK_DATA:
- chunk_len = data->chunk_len - data->chunk_offset;
- /* copy chunk_len bytes from in queue to out queue. */
- we_have = c->mem->used - c->offset - 1;
- we_want = chunk_len > we_have ? we_have : chunk_len;
-
- if (c->offset == 0 && we_want == we_have) {
- /* we are copying the whole buffer, just steal it */
- chunkqueue_steal_chunk(out, c);
- /* c is an empty chunk now */
- } else {
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
- c->offset += we_want;
- }
-
- chunk_len -= we_want;
- out->bytes_in += we_want;
- in->bytes_out += we_want;
- data->chunk_offset += we_want;
- if(chunk_len > 0) {
- /* get next chunk from queue */
- break;
- }
- data->chunk_offset = 0;
- data->chunk_parse_state = HTTP_CHUNK_END;
- case HTTP_CHUNK_END:
- /* discard CRLF.*/
- for(ch = 0; c->mem->used > 0 && (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) {
- ch = c->mem->ptr[c->offset];
- c->offset++;
- in->bytes_out++;
- }
- if(ch != '\n') {
- /* get next chunk from queue */
- break;
- }
- /* final chunk */
- if(data->chunk_len == 0) {
- finished = 1;
- }
- /* finished http-chunk. reset and parse next chunk. */
- protocol_state_data_reset(data);
- break;
- }
- if((size_t)(c->offset) == c->mem->used - 1) {
- c = c->next;
- }
- }
- chunkqueue_remove_finished_chunks(in);
- if (finished) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED;
- }
- /* ran out of data. */
- return HANDLER_GO_ON;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_http_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- chunk *c;
-
- if (in->first == NULL) {
- if ((sess->content_length >= 0 && sess->bytes_read == sess->content_length) || in->is_closed) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
- }
-
- /* parse response headers. */
- if (!sess->have_response_headers) {
- handler_t rc = proxy_http_parse_response_headers(sess, in);
- if (rc != HANDLER_FINISHED) return rc;
- }
-
- if (sess->is_request_finished) return HANDLER_FINISHED;
-
- if (sess->is_chunked) {
- return proxy_http_parse_chunked_stream(srv, sess, in, out);
- } else {
- /* no chunked encoding, ok, perhaps a content-length ? */
-
- chunkqueue_remove_finished_chunks(in);
- for (c = in->first; c; c = c->next) {
- buffer *b;
-
- if (c->mem->used == 0) continue;
-
- out->bytes_in += c->mem->used - c->offset - 1;
- in->bytes_out += c->mem->used - c->offset - 1;
-
- sess->bytes_read += c->mem->used - c->offset - 1;
-
- if (c->offset == 0) {
- /* we are copying the whole buffer, just steal it */
-
- chunkqueue_steal_chunk(out, c);
- } else {
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1; /* marks is read */
- }
-
- if (sess->bytes_read == sess->content_length) {
- break;
- }
- }
-
- if (in->is_closed || sess->bytes_read == sess->content_length) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED; /* finished */
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * transform the content-stream into a valid HTTP-content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_http_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- int we_have = 0;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- /* encode all request content data into output queue. */
- we_have = chunkqueue_steal_all_chunks(out, in);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
-
- if (in->bytes_in == in->bytes_out && in->is_closed) {
- out->is_closed = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * generate a HTTP/1.1 proxy request from the set of request-headers
- *
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_http_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- connection *con = sess->remote_con;
- buffer *b;
- size_t i;
-
- UNUSED(srv);
- UNUSED(in);
-
- b = chunkqueue_get_append_buffer(out);
-
- /* request line */
- buffer_copy_string(b, get_http_method_name(con->request.http_method));
- buffer_append_string_len(b, CONST_STR_LEN(" "));
-
- /* request uri */
- buffer_append_string_buffer(b, sess->request_uri);
-
- if (con->request.http_version == HTTP_VERSION_1_1) {
- buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1\r\n"));
- } else {
- buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
- }
-
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
-
- ds = (data_string *)sess->request_headers->data[i];
-
- buffer_append_string_buffer(b, ds->key);
- buffer_append_string_len(b, CONST_STR_LEN(": "));
- buffer_append_string_buffer(b, ds->value);
- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
- }
-
- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
-
- out->bytes_in += b->used - 1;
-
- return HANDLER_FINISHED;
-}
-
-INIT_FUNC(mod_proxy_backend_http_init) {
- mod_proxy_core_plugin_data *core_data;
- protocol_plugin_data *p;
-
- /* get the plugin_data of the core-plugin */
- core_data = plugin_get_config(srv, CORE_PLUGIN);
- if(!core_data) return NULL;
-
- p = calloc(1, sizeof(*p));
-
- /* define protocol handler callbacks */
- p->protocol = (core_data->proxy_register_protocol)("http");
-
- p->protocol->proxy_stream_init = proxy_http_init;
- p->protocol->proxy_stream_cleanup = proxy_http_cleanup;
- p->protocol->proxy_stream_decoder = proxy_http_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_http_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_http_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_http_free) {
- protocol_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_backend_http_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_http_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_http");
-
- p->init = mod_proxy_backend_http_init;
- p->cleanup = mod_proxy_backend_http_free;
-
- p->data = NULL;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-
-
diff --git a/src/mod_proxy_backend_scgi.c b/src/mod_proxy_backend_scgi.c
deleted file mode 100644
index 60e1de83..00000000
--- a/src/mod_proxy_backend_scgi.c
+++ /dev/null
@@ -1,475 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-#include "sys-strings.h"
-#include "inet_ntop_cache.h"
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "buffer.h"
-#include "log.h"
-#include "array.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-/*
-PROXY_CONNECTION_FUNC(proxy_scgi_init) {
- return 1;
-}
-*/
-
-/*
-PROXY_CONNECTION_FUNC(proxy_scgi_cleanup) {
- return 1;
-}
-*/
-
-/**
- * add a key-value pair to the scgi-buffer
- */
-static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
- size_t len;
-
- if (!key || !val) return -1;
-
- len = key_len + val_len + 2;
-
- buffer_prepare_append(env, len);
-
- buffer_append_memory(env, key, key_len);
- env->ptr[env->used++] = '\0';
- buffer_append_memory(env, val, val_len);
- env->ptr[env->used++] = '\0';
-
- return 0;
-}
-
-static int proxy_scgi_get_env_scgi(server *srv, proxy_session *sess, buffer *env_headers) {
- connection *con = sess->remote_con;
- server_socket *srv_sock = con->srv_socket;
- plugin_data *p = sess->p;
- socklen_t our_addr_len;
- sock_addr our_addr;
- const char *s;
- char buf[32];
- int len;
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-#endif
-
- /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
-
- /* request.content_length < SSIZE_MAX, see request.c */
- if(con->request.content_length > 0) {
- len = LI_ltostr(buf, con->request.content_length);
- } else {
- buf[0] = '0';
- buf[1] = '\0';
- len = 1;
- }
- scgi_env_add(env_headers, CONST_STR_LEN("CONTENT_LENGTH"), buf, len);
- scgi_env_add(env_headers, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
-
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
-
- if (con->server_name->used) {
- size_t _len = con->server_name->used - 1;
- char *colon = strchr(con->server_name->ptr, ':');
- if (colon) _len = colon - con->server_name->ptr;
-
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, _len);
- } else {
-#ifdef HAVE_IPV6
- s = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1);
-#else
- s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
-#endif
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
- }
-
- scgi_env_add(env_headers, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
-
- len = LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
-#else
- ntohs(srv_sock->addr.ipv4.sin_port)
-#endif
- );
-
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_PORT"), buf, len);
-
- /* get the server-side of the connection to the client */
- our_addr_len = sizeof(our_addr);
-
- if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
- s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
- } else {
- s = inet_ntop_cache_get_ip(srv, &(our_addr));
- }
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
-
- len = LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
-#else
- ntohs(con->dst_addr.ipv4.sin_port)
-#endif
- );
-
- scgi_env_add(env_headers, CONST_STR_LEN("REMOTE_PORT"), buf, len);
-
- s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- scgi_env_add(env_headers, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
-
- if (!buffer_is_empty(con->authed_user)) {
- scgi_env_add(env_headers, CONST_STR_LEN("REMOTE_USER"),
- CONST_BUF_LEN(con->authed_user));
- }
-
- /*
- * 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)
- * For AUTHORIZER mode these headers should be omitted.
- */
-
- scgi_env_add(env_headers, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
-
- if (!buffer_is_empty(con->request.pathinfo)) {
- scgi_env_add(env_headers, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
-
- /* PATH_TRANSLATED is only defined if PATH_INFO is set */
-
- buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
- buffer_append_string_buffer(p->tmp_buf, con->request.pathinfo);
- scgi_env_add(env_headers, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->tmp_buf));
- } else {
- scgi_env_add(env_headers, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
- }
-
- /*
- * 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.
- * TODO: this code should be checked against cgi.fix_pathinfo php
- * parameter.
- */
-
- if (1) {
- scgi_env_add(env_headers, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
- scgi_env_add(env_headers, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
- }
-
- scgi_env_add(env_headers, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
-
- if (!buffer_is_equal(sess->request_uri, con->request.orig_uri)) {
- scgi_env_add(env_headers, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(sess->request_uri));
- }
- if (!buffer_is_empty(con->uri.query)) {
- scgi_env_add(env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
- } else {
- scgi_env_add(env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
- }
-
- s = get_http_method_name(con->request.http_method);
- scgi_env_add(env_headers, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
- scgi_env_add(env_headers, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
- s = get_http_version_name(con->request.http_version);
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
-
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- scgi_env_add(env_headers, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
- }
-#endif
-
- return 0;
-}
-
-/**
- * transform the HTTP-Request headers into CGI notation
- */
-static int proxy_scgi_get_env_request(server *srv, proxy_session *sess, buffer *env_headers) {
- connection *con = sess->remote_con;
- plugin_data *p = sess->p;
- size_t i;
-
- UNUSED(srv);
-
- /* the request header got already copied into the sess->request_headers for us
- * no extra filter is needed
- *
- * prepend a HTTP_ and uppercase the keys
- */
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
- size_t j;
-
- ds = (data_string *)sess->request_headers->data[i];
- if (ds->value->used == 0 || ds->key->used == 0) continue;
-
- buffer_reset(p->tmp_buf);
-
- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_"));
- p->tmp_buf->used--;
- }
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = ds->key->ptr[j];
- if (light_isalpha(c)) {
- /* upper-case */
- c = toupper(c);
- } else if (light_isdigit(c)) {
- /* copy */
- c = c;
- } else {
- c = '_';
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = c;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- scgi_env_add(env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
-
- for (i = 0; i < con->environment->used; i++) {
- data_string *ds;
- size_t j;
-
- ds = (data_string *)con->environment->data[i];
- if (ds->value->used == 0 || ds->key->used == 0) continue;
-
- buffer_reset(p->tmp_buf);
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = ds->key->ptr[j];
- if (light_isalpha(c)) {
- /* upper-case */
- c = toupper(c);
- } else {
- c = '_';
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = c;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- scgi_env_add(env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
-
- return 0;
-}
-
-PROXY_STREAM_ENCODER_FUNC(proxy_scgi_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- size_t headers_len = 0;
- buffer *len_buf;
- buffer *env_headers;
-
- UNUSED(in);
-
- /* get buffer to write headers length into */
- len_buf = chunkqueue_get_append_buffer(out);
-
- /* write SCGI request headers */
- env_headers = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(env_headers, 1024);
- proxy_scgi_get_env_scgi(srv, sess, env_headers);
- proxy_scgi_get_env_request(srv, sess, env_headers);
- headers_len = env_headers->used;
- out->bytes_in += headers_len;
-
- /* append "," after headers */
- buffer_append_memory(env_headers, CONST_STR_LEN(","));
- env_headers->used++; /* this is needed because the network will only write "used - 1" bytes */
- out->bytes_in++;
-
- /* prepend [headers_len]: */
- buffer_append_long(len_buf, headers_len);
- buffer_append_string_len(len_buf, CONST_STR_LEN(":"));
- out->bytes_in += len_buf->used - 1;
-
- return HANDLER_FINISHED;
-}
-
-/**
- * parse the HTTP response header
- */
-static handler_t proxy_scgi_parse_response_headers(proxy_session *sess, chunkqueue *in) {
- http_response_reset(sess->resp);
-
- /* http response parser. */
- switch(http_response_parse_cq(in, sess->resp)) {
- case PARSE_ERROR:
- /* bad gateway */
- http_response_reset(sess->resp);
- sess->have_response_headers = 1;
- sess->resp->status = 502;
- return HANDLER_ERROR;
- case PARSE_NEED_MORE:
- return HANDLER_GO_ON;
- case PARSE_SUCCESS:
- default:
- /* finished parsing response headers. */
- sess->have_response_headers = 1;
- return HANDLER_FINISHED;
- }
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_scgi_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- chunk *c;
-
- UNUSED(srv);
-
- if (in->first == NULL) {
- if ((sess->content_length >= 0 && sess->bytes_read == sess->content_length) || in->is_closed) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
- }
-
- /* parse response headers. */
- if (!sess->have_response_headers) {
- handler_t rc = proxy_scgi_parse_response_headers(sess, in);
- if (rc != HANDLER_FINISHED) return rc;
- }
-
- /* no chunked encoding, ok, perhaps a content-length ? */
-
- chunkqueue_remove_finished_chunks(in);
- for (c = in->first; c; c = c->next) {
- buffer *b;
-
- if (c->mem->used == 0) continue;
-
- out->bytes_in += c->mem->used - c->offset - 1;
- in->bytes_out += c->mem->used - c->offset - 1;
-
- sess->bytes_read += c->mem->used - c->offset - 1;
-
- if (c->offset == 0) {
- /* we are copying the whole buffer, just steal it */
-
- chunkqueue_steal_chunk(out, c);
- } else {
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1; /* marks is read */
- }
-
- if (sess->bytes_read == sess->content_length) {
- break;
- }
- }
-
- if (in->is_closed || sess->bytes_read == sess->content_length) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED; /* finished */
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * transform the content-stream into a valid HTTP-content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_scgi_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- int we_have = 0;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- /* encode all request content data into output queue. */
- we_have = chunkqueue_steal_all_chunks(out, in);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
-
- if (in->bytes_in == in->bytes_out && in->is_closed) {
- out->is_closed = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-INIT_FUNC(mod_proxy_backend_scgi_init) {
- mod_proxy_core_plugin_data *core_data;
- protocol_plugin_data *p;
-
- /* get the plugin_data of the core-plugin */
- core_data = plugin_get_config(srv, CORE_PLUGIN);
- if(!core_data) return NULL;
-
- p = calloc(1, sizeof(*p));
-
- /* define protocol handler callbacks */
- p->protocol = core_data->proxy_register_protocol("scgi");
-
- /*
- p->protocol->proxy_stream_init = proxy_scgi_init;
- p->protocol->proxy_stream_cleanup = proxy_scgi_cleanup;
- */
- p->protocol->proxy_stream_decoder = proxy_scgi_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_scgi_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_scgi_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_scgi_free) {
- protocol_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_backend_scgi_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_scgi_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_scgi");
-
- p->init = mod_proxy_backend_scgi_init;
- p->cleanup = mod_proxy_backend_scgi_free;
-
- p->data = NULL;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-
-
diff --git a/src/mod_proxy_core.c b/src/mod_proxy_core.c
deleted file mode 100644
index 31f884a7..00000000
--- a/src/mod_proxy_core.c
+++ /dev/null
@@ -1,2624 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <assert.h>
-#include <fcntl.h>
-#include "base.h"
-#include "sys-strings.h"
-
-#include "buffer.h"
-#include "array.h"
-#include "log.h"
-
-#include "plugin.h"
-#include "joblist.h"
-#include "sys-files.h"
-#include "inet_ntop_cache.h"
-#include "crc32.h"
-#include "configfile.h"
-#include "stat_cache.h"
-#include "buffer.h"
-#include "array.h"
-#include "log.h"
-#include "status_counter.h"
-
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-
-#define PROXY_CORE "proxy-core"
-#define CONFIG_PROXY_CORE_BALANCER PROXY_CORE ".balancer"
-#define CONFIG_PROXY_CORE_PROTOCOL PROXY_CORE ".protocol"
-#define CONFIG_PROXY_CORE_DEBUG PROXY_CORE ".debug"
-#define CONFIG_PROXY_CORE_MAX_KEEP_ALIVE PROXY_CORE ".max-keep-alive-requests"
-#define CONFIG_PROXY_CORE_BACKENDS PROXY_CORE ".backends"
-#define CONFIG_PROXY_CORE_REWRITE_REQUEST PROXY_CORE ".rewrite-request"
-#define CONFIG_PROXY_CORE_REWRITE_RESPONSE PROXY_CORE ".rewrite-response"
-#define CONFIG_PROXY_CORE_ALLOW_X_SENDFILE PROXY_CORE ".allow-x-sendfile"
-#define CONFIG_PROXY_CORE_ALLOW_X_REWRITE PROXY_CORE ".allow-x-rewrite"
-#define CONFIG_PROXY_CORE_MAX_POOL_SIZE PROXY_CORE ".max-pool-size"
-#define CONFIG_PROXY_CORE_CHECK_LOCAL PROXY_CORE ".check-local"
-#define CONFIG_PROXY_CORE_SPLIT_HOSTNAMES PROXY_CORE ".split-hostnames"
-#define CONFIG_PROXY_CORE_DISABLE_TIME PROXY_CORE ".disable-time"
-#define CONFIG_PROXY_CORE_MAX_BACKLOG_SIZE PROXY_CORE ".max-backlog-size"
-
-static int mod_proxy_wakeup_connections(server *srv, plugin_data *p, plugin_config *p_conf);
-
-static int array_insert_int(array *a, const char *key, int val) {
- data_integer *di;
-
- if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
- di = data_integer_init();
- }
-
- buffer_copy_string(di->key, key);
- di->value = val;
- array_insert_unique(a, (data_unset *)di);
-
- return 0;
-}
-
-static proxy_protocol *mod_proxy_core_register_protocol(const char *name) {
- proxy_protocol *protocol = proxy_protocol_init();
-
- protocol->name = buffer_init_string(name);
-
- proxy_protocols_register(protocol);
- return protocol;
-}
-
-INIT_FUNC(mod_proxy_core_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- proxy_protocols_init();
-
- p = calloc(1, sizeof(*p));
-
- /* create some backends as long as we don't have the config-parser */
-
- p->possible_balancers = array_init();
- array_insert_int(p->possible_balancers, "sqf", PROXY_BALANCE_SQF);
- array_insert_int(p->possible_balancers, "carp", PROXY_BALANCE_CARP);
- array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_RR);
- array_insert_int(p->possible_balancers, "static", PROXY_BALANCE_STATIC);
-
- p->proxy_register_protocol = mod_proxy_core_register_protocol;
-
- /* statistics counters. */
- p->request_count = status_counter_get_counter(CONST_STR_LEN(PROXY_CORE ".requests"));
-
- p->balance_buf = buffer_init();
- p->protocol_buf = buffer_init();
- p->replace_buf = buffer_init();
- p->backends_arr = array_init();
-
- p->tmp_buf = buffer_init();
-
-#if 0
- /**
- * create a small pool of session objects
- *
- * instead of creating new one each time,
- * cleanup old ones and put them into the pool
- *
- * 8 clean items should be enough at a time, destroy the other ones
- */
- p->session_pool = proxy_session_pool_init();
-#endif
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_core_free) {
- plugin_data *p = p_d;
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- proxy_backends_free(s->backends);
- proxy_backlog_free(s->backlog);
-
- proxy_rewrites_free(s->request_rewrites);
- proxy_rewrites_free(s->response_rewrites);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- array_free(p->possible_balancers);
- array_free(p->backends_arr);
-
- buffer_free(p->balance_buf);
- buffer_free(p->protocol_buf);
- buffer_free(p->replace_buf);
- buffer_free(p->tmp_buf);
-
-#if 0
- proxy_session_pool_free(p->session_pool);
-#endif
-
- free(p);
-
- proxy_protocols_free();
-
- return HANDLER_GO_ON;
-}
-
-static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
- data_unset *du;
- size_t j;
-
- if (NULL != (du = array_get_element(src, config_key, strlen(config_key)))) {
- data_array *keys = (data_array *)du;
-
- if (keys->type != TYPE_ARRAY) {
- ERROR("%s = <...>",
- config_key);
-
- return HANDLER_ERROR;
- }
-
- /*
- * proxy-core.rewrite-request = (
- * "_uri" => ( ... )
- * )
- */
-
- for (j = 0; j < keys->value->used; j++) {
- size_t k;
- data_array *headers = (data_array *)keys->value->data[j];
-
- /* keys->key should be "_uri" and the value a array of rewrite */
- if (headers->type != TYPE_ARRAY) {
- ERROR("%s = ( %s => <...> ) has to a array",
- config_key,
- SAFE_BUF_STR(headers->key));
-
- return HANDLER_ERROR;
- }
-
- if (headers->value->used > 1) {
- ERROR("%s = ( %s => <...> ) has to a array with only one element",
- config_key,
- SAFE_BUF_STR(headers->key));
-
- return HANDLER_ERROR;
-
- }
-
- for (k = 0; k < headers->value->used; k++) {
- data_string *rewrites = (data_string *)headers->value->data[k];
- proxy_rewrite *rw;
-
- /* keys->key should be "_uri" and the value a array of rewrite */
- if (rewrites->type != TYPE_STRING) {
- ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string",
- config_key,
- SAFE_BUF_STR(headers->key),
- SAFE_BUF_STR(rewrites->key));
-
- return HANDLER_ERROR;
- }
-
- rw = proxy_rewrite_init();
-
- if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
- return HANDLER_ERROR;
- }
- buffer_copy_string_buffer(rw->replace, rewrites->value);
- buffer_copy_string_buffer(rw->match, rewrites->key);
- buffer_copy_string_buffer(rw->header, headers->key);
-
- proxy_rewrites_add(dest, rw);
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static void mod_proxy_core_create_backend_stats(plugin_data *p, buffer *stat_basename, proxy_backend *backend) {
-#define COUNTER_NAME(b, x) \
- buffer_copy_string_buffer(b, stat_basename); \
- buffer_append_string_len(b, CONST_STR_LEN("\"")); \
- buffer_append_string_buffer(b, backend->name); \
- buffer_append_string_len(b, CONST_STR_LEN("\"." x));
-
- /* request count stat. */
- COUNTER_NAME(p->tmp_buf, "requests");
- backend->request_count = status_counter_get_counter(CONST_BUF_LEN(p->tmp_buf));
-
- /* load */
- COUNTER_NAME(p->tmp_buf, "load");
- backend->load = status_counter_get_counter(CONST_BUF_LEN(p->tmp_buf));
-
- /* pool size */
- COUNTER_NAME(p->tmp_buf, "pool_size");
- backend->pool_size = status_counter_get_counter(CONST_BUF_LEN(p->tmp_buf));
-
- COUNTER_NAME(p->tmp_buf, "requests_failed");
- backend->requests_failed = status_counter_get_counter(CONST_BUF_LEN(p->tmp_buf));
-#undef COUNTER_NAME
-}
-
-SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
- plugin_data *p = p_d;
- buffer *stat_basename;
- size_t i, j;
- int proxy_counter = 0;
-
- config_values_t cv[] = {
- { CONFIG_PROXY_CORE_BACKENDS, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { CONFIG_PROXY_CORE_DEBUG, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { CONFIG_PROXY_CORE_BALANCER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { CONFIG_PROXY_CORE_PROTOCOL, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { CONFIG_PROXY_CORE_ALLOW_X_SENDFILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { CONFIG_PROXY_CORE_ALLOW_X_REWRITE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { CONFIG_PROXY_CORE_MAX_POOL_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { CONFIG_PROXY_CORE_CHECK_LOCAL, "use $PHYSICAL[\"existing-path\"] =~ ... { ... } instead",
- T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
- { CONFIG_PROXY_CORE_MAX_KEEP_ALIVE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
- { CONFIG_PROXY_CORE_SPLIT_HOSTNAMES, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
- { CONFIG_PROXY_CORE_DISABLE_TIME, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
- { CONFIG_PROXY_CORE_MAX_BACKLOG_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- stat_basename = buffer_init();
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- array *ca;
- proxy_backend *backend;
-
- array_reset(p->backends_arr);
- buffer_reset(p->balance_buf);
- buffer_reset(p->protocol_buf);
-
- s = calloc(1, sizeof(plugin_config));
- s->debug = 0;
- s->balancer = PROXY_BALANCE_UNSET;
- s->protocol = NULL;
- s->backends = proxy_backends_init();
- s->backlog = proxy_backlog_init();
- s->response_rewrites = proxy_rewrites_init();
- s->request_rewrites = proxy_rewrites_init();
- s->check_local = 0;
- s->split_hostnames = 1;
- s->max_keep_alive_requests = 0;
- s->disable_time = 1;
- s->max_backlog_size = 4;
-
- cv[0].destination = p->backends_arr;
- cv[1].destination = &(s->debug);
- cv[2].destination = p->balance_buf; /* parse into a constant */
- cv[3].destination = p->protocol_buf; /* parse into a constant */
- cv[6].destination = &(s->allow_x_sendfile);
- cv[7].destination = &(s->allow_x_rewrite);
- cv[8].destination = &(s->max_pool_size);
- cv[10].destination = &(s->max_keep_alive_requests);
- cv[11].destination = &(s->split_hostnames);
- cv[12].destination = &(s->disable_time);
- cv[13].destination = &(s->max_backlog_size);
-
- buffer_reset(p->balance_buf);
-
- p->config_storage[i] = s;
- ca = ((data_config *)srv->config_context->data[i])->value;
-
- if (0 != config_insert_values_global(srv, ca, cv)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_is_empty(p->balance_buf)) {
- data_integer *di;
-
- if (NULL != (di = (data_integer *)array_get_element(p->possible_balancers, CONST_BUF_LEN(p->balance_buf)))) {
- s->balancer = di->value;
- } else {
- ERROR("proxy.balance has to be one of 'round-robin', 'carp', 'sqf', 'static': got %s", SAFE_BUF_STR(p->balance_buf));
- return HANDLER_ERROR;
- }
- }
-
- if (!buffer_is_empty(p->protocol_buf)) {
- proxy_protocol *protocol = NULL;
- if (NULL == (protocol = proxy_get_protocol(p->protocol_buf))) {
- ERROR("proxy.protocol has to be one of { %s } got %s, you might have to load 'mod_proxy_backend_%s'",
- proxy_available_protocols(),
- SAFE_BUF_STR(p->protocol_buf),
- SAFE_BUF_STR(p->protocol_buf)
- );
- return HANDLER_ERROR;
- }
- s->protocol = protocol;
- }
-
- if (p->backends_arr->used) {
- /* statistics base name. */
- buffer_copy_string_len(stat_basename, CONST_STR_LEN(PROXY_CORE "."));
- buffer_append_long(stat_basename, proxy_counter);
-
- /* backlog size stats */
- buffer_copy_string_buffer(p->tmp_buf, stat_basename);
- buffer_append_string_len(p->tmp_buf, CONST_STR_LEN(".backlogged"));
- s->backlog_size = status_counter_get_counter(CONST_BUF_LEN(p->tmp_buf));
-
- /* backends stats base name. */
- buffer_append_string_len(stat_basename, CONST_STR_LEN(".backends."));
-
- /* check if the backends have a valid host-name */
- for (j = 0; j < p->backends_arr->used; j++) {
- data_string *ds = (data_string *)p->backends_arr->data[j];
- backend = proxy_backend_init();
-
- /* save name of backend for config. */
- buffer_copy_string_buffer(backend->name, ds->value);
- /* the values should be ips or hostnames */
- if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
- return HANDLER_ERROR;
- }
-
- if (s->max_pool_size) {
- backend->pool->max_size = s->max_pool_size;
- }
-
- /* append backend to list of backends */
- proxy_backends_add(s->backends, backend);
-
- /* if there is more then one address in the pool, split them out into seperate backends */
- if (s->split_hostnames && backend->address_pool->used > 1) {
- proxy_address_pool *pool = backend->address_pool;
-
- /* change current backend's name to name of the first ip address in the pool. */
- buffer_copy_string_buffer(backend->name, pool->ptr[0]->name);
-
- /* setup stats */
- mod_proxy_core_create_backend_stats(p, stat_basename, backend);
-
- /* move all addresses from the pool into new backends, except for the first one */
- while (pool->used > 1) {
- /* remove last address from pool */
- proxy_address *address = pool->ptr[--(pool->used)];
-
- /* create new backend for address */
- backend = proxy_backend_init();
-
- /* set backend name to name of address */
- buffer_copy_string_buffer(backend->name, address->name);
-
- /* setup stats */
- mod_proxy_core_create_backend_stats(p, stat_basename, backend);
-
- /* add address to pool */
- proxy_address_pool_add(backend->address_pool, address);
-
- if (s->max_pool_size) {
- backend->pool->max_size = s->max_pool_size;
- }
-
- /* append backend to list of backends */
- proxy_backends_add(s->backends, backend);
- }
- } else {
- /* setup stats */
- mod_proxy_core_create_backend_stats(p, stat_basename, backend);
- }
- }
- /* counter number of "proxy-core.backends" groups */
- proxy_counter++;
- }
-
- if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
- return HANDLER_ERROR;
- }
-
- if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
- return HANDLER_ERROR;
- }
- }
-
- buffer_free(stat_basename);
-
- return HANDLER_GO_ON;
-}
-
-
-static proxy_session *proxy_session_init(void) {
- proxy_session *sess;
-
- sess = calloc(1, sizeof(*sess));
-
- sess->state = PROXY_STATE_UNSET;
- sess->request_uri = buffer_init();
- sess->request_headers = array_init();
- sess->env_headers = array_init();
-
- sess->resp = http_response_init();
-
- sess->recv = chunkqueue_init();
-
- sess->is_chunked = 0;
- sess->content_length = -1;
- sess->send_response_content = 1;
- sess->do_new_session = 0;
- sess->do_x_rewrite_backend = 0;
- sess->sticky_session = NULL;
-
- return sess;
-}
-
-static void proxy_session_reset(proxy_session *sess) {
- if (!sess) return;
-
- buffer_reset(sess->request_uri);
- array_reset(sess->request_headers);
- array_reset(sess->env_headers);
-
- http_response_reset(sess->resp);
- sess->p = NULL;
-
- chunkqueue_reset(sess->recv);
-
- sess->state = PROXY_STATE_UNSET;
-
- sess->is_chunked = 0;
- sess->send_response_content = 1;
-
- sess->bytes_read = 0;
- sess->connect_start_ts = 0;
- sess->content_length = -1;
- sess->internal_redirect_count = 0;
- sess->do_internal_redirect = 0;
- sess->is_closing = 0;
- sess->is_closed = 0;
- sess->is_request_finished = 0;
- sess->have_response_headers = 0;
-
- sess->do_new_session = 0;
- sess->do_x_rewrite_backend = 0;
- buffer_free(sess->sticky_session);
- sess->sticky_session = NULL;
-
- sess->remote_con = NULL;
- sess->proxy_con = NULL;
- sess->proxy_backend = NULL;
-}
-
-static void proxy_session_free(proxy_session *sess) {
- if (!sess) return;
-
- buffer_free(sess->request_uri);
- array_free(sess->request_headers);
- array_free(sess->env_headers);
-
- http_response_free(sess->resp);
- sess->p = NULL;
-
- chunkqueue_free(sess->recv);
-
- buffer_free(sess->sticky_session);
- free(sess);
-}
-
-/**
- * Copy decoded response content to client connection.
- */
-static int proxy_copy_response(server *srv, connection *con, proxy_session *sess) {
- chunk *c;
- int we_have = 0;
-
- UNUSED(srv);
-
- chunkqueue_remove_finished_chunks(sess->recv);
- /* copy the content to the next cq */
- for (c = sess->recv->first; c; c = c->next) {
- if (c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- sess->recv->bytes_out += we_have;
- if (sess->send_response_content) {
- con->send->bytes_in += we_have;
- /* X-Sendfile ignores the content-body */
- chunkqueue_steal_chunk(con->send, c);
- } else {
- /* discard the data */
- chunk_set_done(c);
- }
- }
- chunkqueue_remove_finished_chunks(sess->recv);
-
- if(sess->recv->is_closed && sess->send_response_content) {
- con->send->is_closed = 1;
- }
- return 0;
-}
-
-/**
- * Initialize protocol stream.
- *
- */
-static int proxy_stream_init(server *srv, proxy_session *sess) {
- proxy_protocol *protocol = (sess->proxy_backend) ? sess->proxy_backend->protocol : NULL;
- if(protocol && protocol->proxy_stream_init) {
- return (protocol->proxy_stream_init)(srv, sess->proxy_con);
- }
- return 1;
-}
-
-/**
- * Cleanup protocol state data.
- *
- */
-static int proxy_stream_cleanup(server *srv, proxy_session *sess) {
- proxy_protocol *protocol = (sess->proxy_backend) ? sess->proxy_backend->protocol : NULL;
- if(protocol && protocol->proxy_stream_cleanup) {
- return (protocol->proxy_stream_cleanup)(srv, sess->proxy_con);
- }
- return 1;
-}
-
-/**
- * decode the content for the protocol
- *
- * http might have chunk-encoding
- * fastcgi has the fastcgi wrapper code
- *
- * @param out chunkqueue for the plain content
- */
-
-static handler_t proxy_stream_decoder(server *srv, proxy_session *sess, chunkqueue *out) {
- proxy_protocol *protocol = (sess->proxy_backend) ? sess->proxy_backend->protocol : NULL;
- if(protocol && protocol->proxy_stream_decoder) {
- return (protocol->proxy_stream_decoder)(srv, sess, out);
- }
- ERROR("protocol '%s' is not supported yet", SAFE_BUF_STR(protocol->name));
- return HANDLER_ERROR;
-}
-
-/**
- * encode the content for the protocol
- *
- * @param in chunkqueue with the content to (no encoding)
- */
-static handler_t proxy_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in) {
- proxy_protocol *protocol = (sess->proxy_backend) ? sess->proxy_backend->protocol : NULL;
- if(protocol && protocol->proxy_stream_encoder) {
- return (protocol->proxy_stream_encoder)(srv, sess, in);
- }
- ERROR("protocol '%s' is not supported yet", SAFE_BUF_STR(protocol->name));
- return HANDLER_ERROR;
-}
-
-/**
- * encode the request for the protocol
- *
- * @param in chunkqueue with the content to (no encoding)
- * @param out chunkqueue for the encoded, protocol specific data
- */
-static handler_t proxy_encode_request_headers(server *srv, proxy_session *sess, chunkqueue *in) {
- proxy_protocol *protocol = (sess->proxy_backend) ? sess->proxy_backend->protocol : NULL;
- if(protocol && protocol->proxy_encode_request_headers) {
- /* reset proxy connection queues before we encode a new request.
- */
- chunkqueue_reset(sess->proxy_con->send);
- chunkqueue_reset(sess->proxy_con->recv);
- return (protocol->proxy_encode_request_headers)(srv, sess, in);
- }
-
- if (protocol == NULL) {
- ERROR("protocol is not set: %s", "");
- } else {
- ERROR("protocol '%s' is not supported yet", SAFE_BUF_STR(protocol->name));
- }
- return HANDLER_ERROR;
-}
-
-static handler_t proxy_handle_response_headers(server *srv, connection *con, plugin_data *p,
- proxy_session *sess, chunkqueue *out) {
- int have_content_length = 0;
- int do_x_rewrite = 0;
- size_t i;
-
- /* finished parsing http response headers from backend, now prepare http response headers
- * for client response.
- */
- sess->content_length = -1;
- con->http_status = sess->resp->status;
-
- /* copy the http-headers */
- for (i = 0; i < sess->resp->headers->used; i++) {
- const char *ign[] = { "Status", NULL };
- size_t j, k;
- data_string *ds;
-
- data_string *header = (data_string *)sess->resp->headers->data[i];
-
- /* some headers are ignored by default */
- for (j = 0; ign[j]; j++) {
- if (0 == strcasecmp(ign[j], header->key->ptr)) break;
- }
- if (ign[j]) continue;
-
- if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
- /* CGI/1.1 rev 03 - 7.2.1.2 */
- if (con->http_status == 0) con->http_status = 302;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
- have_content_length = 1;
-
- sess->content_length = strtol(header->value->ptr, NULL, 10);
-
- if (sess->content_length < 0) {
- return HANDLER_ERROR;
- }
- con->response.content_length = sess->content_length;
- /* don't save this header, other modules might change the content length. */
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
- 0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
- if (p->conf.allow_x_sendfile) {
- sess->send_response_content = 0;
- sess->do_internal_redirect = 1;
-
- /* don't try to rewrite this request through mod_proxy_core again */
- sess->internal_redirect_count = MAX_INTERNAL_REDIRECTS;
-
- buffer_copy_string_buffer(con->physical.path, header->value);
-
- /* as we want to support ETag and friends we set the physical path for the file
- * and hope mod_staticfile catches up */
- }
-
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-tempfile"))) {
- if (p->conf.allow_x_sendfile && !buffer_is_empty(header->value)) {
- stat_cache_entry *sce = NULL;
-
- if (HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
- chunk *c;
- sess->send_response_content = 0;
-
- if(sce->st.st_size > 0) {
- chunkqueue_append_file(con->send, header->value, 0, sce->st.st_size);
- con->send->bytes_in += sce->st.st_size;
- c = con->send->last;
- c->file.is_temp = 1;
- } else {
- if(unlink(BUF_STR(header->value)) < 0) {
- ERROR("Failed to delete empty tempfile: file=%s, error: %s", SAFE_BUF_STR(header->value), strerror(errno));
- }
- }
- con->response.content_length = sce->st.st_size;
- have_content_length = 1;
- con->send->is_closed = 1;
- } else {
- ERROR("Failed to send tempfile: file=%s, error: %s", SAFE_BUF_STR(header->value), strerror(errno));
- }
- }
-
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-URI"))) {
- if (p->conf.allow_x_rewrite) {
- do_x_rewrite = 1;
- buffer_copy_string_buffer(con->request.uri, header->value);
- }
-
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-Host"))) {
- if (p->conf.allow_x_rewrite) {
- do_x_rewrite = 1;
- buffer_copy_string_buffer(con->request.http_host, header->value);
- /* replace Host request header */
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Host")))) {
- buffer_copy_string_buffer(ds->value, header->value);
- } else {
- /* insert Host request header */
- if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
- ds = data_response_init();
- }
- buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
- buffer_copy_string_buffer(ds->value, header->value);
- array_insert_unique(con->request.headers, (data_unset *)ds);
- }
- }
-
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-Backend"))) {
- if (p->conf.allow_x_rewrite) {
- do_x_rewrite = 1;
- if (!sess->sticky_session) sess->sticky_session = buffer_init();
- buffer_copy_string_buffer(sess->sticky_session, header->value);
- sess->do_x_rewrite_backend = 1;
- }
-
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
- if (strstr(header->value->ptr, "chunked")) {
- sess->is_chunked = 1;
- }
- /* ignore the header */
- continue;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Connection"))) {
- if (strstr(header->value->ptr, "close")) {
- sess->is_closing = 1;
- }
- /* ignore the header */
- continue;
-
- }
-
- if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
- ds = data_response_init();
- }
-
-
- buffer_copy_string_buffer(ds->key, header->key);
-
-#ifdef HAVE_PCRE_H
- for (k = 0; k < p->conf.response_rewrites->used; k++) {
- proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
-
- if (buffer_is_equal(rw->header, header->key)) {
- int ret;
-
- if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
- switch (ret) {
- case PCRE_ERROR_NOMATCH:
- /* hmm, ok. no problem */
- buffer_append_string_buffer(ds->value, header->value);
- break;
- default:
- TRACE("oops, pcre_replace failed with: %d", ret);
- break;
- }
- } else {
- buffer_append_string_buffer(ds->value, p->replace_buf);
- }
-
- break;
- }
- }
-
- if (k == p->conf.response_rewrites->used) {
- buffer_copy_string_buffer(ds->value, header->value);
- }
-#else
- buffer_copy_string_buffer(ds->value, header->value);
-#endif
-
- array_insert_unique(con->response.headers, (data_unset *)ds);
- }
-
- if (do_x_rewrite) {
- sess->send_response_content = 0;
- sess->do_internal_redirect = 1;
- sess->do_new_session = 1;
- sess->is_chunked = 0;
- con->http_status = 0;
- sess->content_length = -1;
- con->response.content_length = -1;
-
- /* we are restarting the whole request, reset all the response headers */
- array_reset(con->response.headers);
-
- buffer_reset(con->physical.path);
-
- config_cond_cache_reset(srv, con);
- }
-
- /* we are finished decoding the response headers. */
- if(!out->is_closed) {
- /* We don't have all the response content try to enable chunked encoding. */
- /* does the client allow us to send chunked encoding ? */
- if (con->request.http_version == HTTP_VERSION_1_1 &&
- !have_content_length) {
- con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
- }
- }
-
- /* we might have part of the response content too */
- proxy_copy_response(srv, con, sess);
-
- return HANDLER_FINISHED; /* we have a full header */
-}
-
-/*
- * if there is data in the send queue enable FDEVENT_OUT & FDEVENT_IN.
- * else just enable FDEVENT_IN.
- */
-static int proxy_connection_enable_events(server *srv, proxy_connection *proxy_con) {
- int events = FDEVENT_IN;
- if (proxy_con->send->bytes_out < proxy_con->send->bytes_in) events |= FDEVENT_OUT;
- return fdevent_event_add(srv->ev, proxy_con->sock, events);
-}
-
-/**
- * encode/decode stream data from backend connection.
- *
- */
-static handler_t proxy_stream_encode_decode(server *srv, proxy_session *sess) {
- //proxy_connection *proxy_con = sess->proxy_con;
- connection *con = sess->remote_con;
-
- if (!sess->recv->is_closed) {
- /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
- switch (proxy_stream_decoder(srv, sess, sess->recv)) {
- case HANDLER_FINISHED:
- /* finished decoding reponse. */
- /* we are done, close the response content queue */
- sess->recv->is_closed = 1;
- break;
- case HANDLER_GO_ON:
- break;
- case HANDLER_ERROR:
- ERROR("%s", "stream decoder failed.");
- /* error */
- return HANDLER_ERROR;
- default:
- TRACE("stream-decoder: %s", "foo");
- break;
- }
- }
-
- /* encode request content. */
- switch(proxy_stream_encoder(srv, sess, con->recv)) {
- case HANDLER_FINISHED:
- /* finished encoding request content. */
- break;
- case HANDLER_GO_ON:
- break;
- case HANDLER_ERROR:
- ERROR("%s", "stream encoder failed.");
- /* error */
- return HANDLER_ERROR;
- default:
- TRACE("stream-encoder: %s", "foo");
- break;
- }
- chunkqueue_remove_finished_chunks(con->recv);
-
- if (!sess->is_closed) {
- /* enable FDEVENT_OUT if there is data to send. */
- proxy_connection_enable_events(srv, sess->proxy_con);
- }
-
- return HANDLER_GO_ON;
-}
-
-static handler_t proxy_connection_connect(proxy_connection *con) {
- int fd;
-#ifdef _WIN32
- int io_ctl = 1;
- int win_err = 0;
-#endif
-
- if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
- switch (errno) {
- case EMFILE:
- return HANDLER_WAIT_FOR_FD;
- default:
- ERROR("socket failed: %s (%d)", strerror(errno), errno);
- return HANDLER_ERROR;
- }
- }
-
-#ifdef O_NONBLOCK
- fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
-#elif defined _WIN32
- ioctlsocket(fd, FIONBIO, &io_ctl);
-#endif
-
- con->sock->fd = fd;
- con->sock->fde_ndx = -1;
- con->sock->type = IOSOCKET_TYPE_SOCKET;
-
- if (-1 == connect(fd, &(con->address->addr.plain), con->address->addrlen)) {
- switch(light_sock_errno()) {
- case EINPROGRESS:
- case EALREADY:
- case EINTR:
-#ifdef _WIN32
- case EWOULDBLOCK:
-#endif
- return HANDLER_WAIT_FOR_EVENT;
- default:
- closesocket(fd);
- con->sock->fd = -1;
-
- ERROR("connect(%s) failed: %s (%d)",
- SAFE_BUF_STR(con->address->name),
- strerror(errno), errno);
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * event-handler for idling connections
- *
- * unused (idling) keep-alive connections are not bound to a session
- * and need their own event-handler
- *
- * if the connection closes (we get a FDEVENT_IN), close our side too and
- * let the trigger-func handle the cleanup
- *
- * @see proxy_trigger
- */
-
-
-static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
- proxy_connection *proxy_con = ctx;
- char buf[4096];
-
- if (revents & FDEVENT_IN) {
- switch (proxy_con->state) {
- case PROXY_CONNECTION_STATE_IDLE:
- proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
-
- /* close + unregister have to be in the same call,
- * otherwise we get a events for a re-opened fd */
-
- sockread(proxy_con->sock->fd, buf, sizeof(buf));
-
- fdevent_event_del(srv->ev, proxy_con->sock);
-
- /* we have to notify the pool, that this connection is free now */
-
- break;
- case PROXY_CONNECTION_STATE_CLOSED:
- /* poll() is state-driven, we will get events as long as it isn't disabled
- * the close() above should disable the events too */
- ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
- break;
- default:
- ERROR("invalid connection state: %d, should be idle", proxy_con->state);
- break;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-
-/* don't call any proxy functions directly */
-static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
- proxy_session *sess = ctx;
- proxy_connection *proxy_con;
- connection *con;
- int call_append = 1;
-
- /**
- * we might receive a event for a connection that should be closed already
- */
-
- if (sess == NULL) {
- /**
- * race
- * the other fd of the connection might have been closed already
- * mod_proxy_connection_close_callback() frees the
- */
-
- ERROR("the session ctx is NULL: %p, expect a crash", (void*) sess);
- // FIXME: do not dereference an known NULL ???
- }
-
- proxy_con = sess->proxy_con;
- con = sess->remote_con;
-
- if (revents & FDEVENT_IN) {
- chunkqueue_remove_finished_chunks(proxy_con->recv);
- switch (srv->network_backend_read(srv, con, proxy_con->sock, proxy_con->recv)) {
- case NETWORK_STATUS_CONNECTION_CLOSE:
- /* a close here means we can't read/write any more data. */
- sess->is_closed = 1;
- proxy_con->send->is_closed = 1;
- proxy_con->recv->is_closed = 1;
- break;
- case NETWORK_STATUS_SUCCESS:
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- break;
- default:
- ERROR("%s", "oops, we failed to read");
- break;
- }
- }
-
- if (revents & FDEVENT_OUT) {
- fdevent_event_add(srv->ev, proxy_con->sock, FDEVENT_IN);
-
- switch (srv->network_backend_write(srv, con, proxy_con->sock, proxy_con->send)) {
- case NETWORK_STATUS_SUCCESS:
- break;
- case NETWORK_STATUS_WAIT_FOR_AIO_EVENT:
- call_append = 0; /* let the joblist-queue-handler call the connection again */
- break;
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- fdevent_event_add(srv->ev, proxy_con->sock, FDEVENT_IN | FDEVENT_OUT);
- break;
- case NETWORK_STATUS_CONNECTION_CLOSE:
- /* done mark the connection closed here only the send queue,
- * since there might be more data to read.
- */
- proxy_con->send->is_closed = 1;
- break;
- default:
- ERROR("%s", "oops, we failed to write");
- break;
- }
- chunkqueue_remove_finished_chunks(proxy_con->send);
- }
-
- if (revents & FDEVENT_HUP) {
- if (!(revents & FDEVENT_IN)) {
- /* if we only received the FDEVENT_HUP event, then there is no more data to read. */
- sess->is_closed = 1;
- proxy_con->recv->is_closed = 1;
- }
- /* can't write on a closed socket, so close the send queue. */
- proxy_con->send->is_closed = 1;
- }
-
- if (sess->is_closed) {
- sess->recv->is_closed = 1;
- fdevent_event_del(srv->ev, sess->proxy_con->sock);
- }
-
- /**
- * on NETWORK_STATUS_WAIT_FOR_AIO_EVENT we are not allowed to call the state-engine
- * the connection has to sleep until our disk-read is finished
- *
- * the joblist_append() will be called by the joblist_append_queue_handler in server.c
- */
- if (call_append) joblist_append(srv, con);
-
- return HANDLER_GO_ON;
-}
-
-/**
- * Cleanup backend proxy connection.
- */
-static int proxy_remove_backend_connection(server *srv, proxy_session *sess) {
-
- if(!sess->proxy_con) return -1;
-
- /* cleanup protocol stream */
- proxy_stream_cleanup(srv, sess);
-
- /* remove closed connection from pool. */
- proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
-
- /* update stats. */
- COUNTER_SET(sess->proxy_backend->pool_size, sess->proxy_backend->pool->used);
- COUNTER_DEC(sess->proxy_backend->load);
-
- /* the backend might have been disabled by a full connection pool, re-enable
- * if there is at least one active address.
- */
- if (sess->proxy_backend->disabled_addresses <= sess->proxy_backend->address_pool->used) {
- sess->proxy_backend->state = PROXY_BACKEND_STATE_ACTIVE;
- }
-
- if (sess->proxy_con->sock->fd != -1) {
- /* if we fail in connect() might not have a FD yet */
- fdevent_event_del(srv->ev, sess->proxy_con->sock);
- fdevent_unregister(srv->ev, sess->proxy_con->sock);
- }
-
- proxy_connection_free(sess->proxy_con);
- sess->proxy_con = NULL;
-
- return 0;
-}
-
-/**
- * Recycle backend proxy connection.
- *
- * 1. close the connection if keep-alive is disable
- * 2. or set the connection idling and wake up a backlogged request.
- *
- */
-static int proxy_recycle_backend_connection(server *srv, plugin_data *p, proxy_session *sess) {
- proxy_request *req;
- int reuse = 1;
-
- if (!sess) return HANDLER_GO_ON;
-
- if (sess->proxy_con) {
- COUNTER_INC(p->request_count);
- COUNTER_INC(sess->proxy_backend->request_count);
- COUNTER_DEC(sess->proxy_backend->load);
- switch (sess->proxy_con->state) {
- case PROXY_CONNECTION_STATE_CONNECTED:
- /*
- * Set the connection to idling if:
- *
- * 1. keep-alive was not disabled (sess->is_closing)
- * 2. backend connection is already closed (sess->is_closed)
- * 3. backend protocol finished parsing all data for this request. (sess->recv->is_closed)
- * 4. keep-alive request count hasn't reached max-keep-alive-requests
- */
- if (sess->is_closing || sess->is_closed) {
- reuse = 0;
- }
-
- sess->proxy_con->request_count++;
- if (p->conf.debug) TRACE("request_count=%d", sess->proxy_con->request_count);
- if (sess->proxy_con->request_count >= p->conf.max_keep_alive_requests) {
- reuse = 0;
- }
- if (reuse && sess->recv->is_closed) {
- sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
-
- /* make sure backend is active since we have a free connection. */
- sess->proxy_backend->state = PROXY_BACKEND_STATE_ACTIVE;
-
- /* don't ignore events as the FD is idle
- * we might get a HUP as the remote connection might close */
- fdevent_event_del(srv->ev, sess->proxy_con->sock);
- fdevent_unregister(srv->ev, sess->proxy_con->sock);
-
- fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
- fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
-
- break;
- }
-
- /* fall-through for non-keep-alive or response parsing didn't finish */
-
- case PROXY_CONNECTION_STATE_CLOSED:
- /* user terminated connection and proxy connection is still in CONNECTING mode.
- * this happens frequently when backends are slow
- */
- case PROXY_CONNECTION_STATE_CONNECTING:
- proxy_remove_backend_connection(srv, sess);
- case PROXY_CONNECTION_STATE_IDLE:
- default:
- break;
- }
- sess->proxy_con = NULL;
- }
-
- /* wake up a connection from the backlog */
- if ((req = proxy_backlog_shift(p->conf.backlog))) {
- connection *next_con = req->con;
-
- if (p->conf.debug) TRACE("wakeup a connection from backlog: con=%d", next_con->sock->fd);
- joblist_append(srv, next_con);
-
- COUNTER_DEC(p->conf.backlog_size);
- proxy_request_free(req);
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * push the session into the backlog
- *
- * @returns HANDLER_ERROR in case we reach the max-connect-retry limit
- */
-static handler_t mod_proxy_core_backlog_connection(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
- proxy_request *req;
-
- if (sess->sent_to_backlog >= p->conf.max_backlog_size) {
- return HANDLER_ERROR;
- }
-
- /* connection pool is full, queue the request for now */
- req = proxy_request_init();
- req->added_ts = srv->cur_ts;
- req->con = con;
-
- proxy_backlog_push(p->conf.backlog, req);
-
- COUNTER_INC(p->conf.backlog_size);
- sess->sent_to_backlog++;
-
- return HANDLER_GO_ON;
-}
-
-/**
- * build the request-header array and call the backend specific request formater
- * to fill the chunkqueue
- */
-static int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
- /* request line */
- const char *remote_ip;
- size_t i;
-
- remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- array_append_key_value(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
-
- /* http_host is NOT is just a pointer to a buffer
- * which is NULL if it is not set */
- if (con->request.http_host &&
- !buffer_is_empty(con->request.http_host)) {
- array_set_key_value(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
- }
- if (con->conf.is_ssl) {
- array_set_key_value(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
- } else {
- array_set_key_value(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
- }
-
- /* request header */
- for (i = 0; i < con->request.headers->used; i++) {
- data_string *ds;
- size_t k;
-
- ds = (data_string *)con->request.headers->data[i];
-
- if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
-
- if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
- if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
- if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Expect"))) continue;
-#ifdef HAVE_PCRE_H
- for (k = 0; k < p->conf.request_rewrites->used; k++) {
- proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
-
- if (buffer_is_equal(rw->header, ds->key)) {
- int ret;
-
- if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
- switch (ret) {
- case PCRE_ERROR_NOMATCH:
- /* hmm, ok. no problem */
- array_set_key_value(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
- break;
- default:
- TRACE("oops, pcre_replace failed with: %d", ret);
- break;
- }
- } else {
- array_set_key_value(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
- }
-
- break;
- }
- }
-
- if (k == p->conf.request_rewrites->used) {
- array_set_key_value(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
- }
-#else
- array_set_key_value(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
-#endif
- }
-
- /* populate sess->request_uri with the actually requested path
- * (con->request.uri). if we have pcre and there is a _uri request
- * rewrite, it will be overwritten later
- */
- buffer_copy_string_buffer(sess->request_uri, con->request.uri);
-
- /* check if we want to rewrite the uri */
-#ifdef HAVE_PCRE_H
- for (i = 0; i < p->conf.request_rewrites->used; i++) {
- proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
-
- if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
- int ret;
-
- if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
- switch (ret) {
- case PCRE_ERROR_NOMATCH:
- /* hmm, ok. no problem */
- buffer_copy_string_buffer(sess->request_uri, con->request.uri);
- break;
- default:
- TRACE("oops, pcre_replace failed with: %d", ret);
- break;
- }
- } else {
- buffer_copy_string_buffer(sess->request_uri, p->replace_buf);
- }
- } else if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_docroot"))) {
- int ret;
-
- if ((ret = pcre_replace(rw->regex, rw->replace, con->physical.doc_root, p->replace_buf)) < 0) {
- switch (ret) {
- case PCRE_ERROR_NOMATCH:
- /* hmm, ok. no problem */
- break;
- default:
- TRACE("oops, pcre_replace failed with: %d", ret);
- break;
- }
- } else {
- /* adjust DOCUMENT_ROOT */
- buffer_copy_string_buffer(con->physical.doc_root, p->replace_buf);
-
- /* adjust SCRIPT_FILENAME */
- buffer_copy_string_buffer(con->physical.path, p->replace_buf);
- buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
- }
- } else if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_pathinfo"))) {
- int ret;
-
- if ((ret = pcre_replace(rw->regex, rw->replace, con->uri.path, p->replace_buf)) < 0) {
- switch (ret) {
- case PCRE_ERROR_NOMATCH:
- /* hmm, ok. no problem */
- break;
- default:
- TRACE("oops, pcre_replace failed with: %d", ret);
- break;
- }
- } else {
- /* we matched, cool. */
- buffer_copy_string_buffer(con->request.pathinfo, p->replace_buf);
- }
- } else if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_scriptname"))) {
- int ret;
-
- if ((ret = pcre_replace(rw->regex, rw->replace, con->uri.path, p->replace_buf)) < 0) {
- switch (ret) {
- case PCRE_ERROR_NOMATCH:
- /* hmm, ok. no problem */
- break;
- default:
- TRACE("oops, pcre_replace failed with: %d", ret);
- break;
- }
- } else {
- /* we matched, cool. */
- buffer_copy_string_buffer(con->uri.path, p->replace_buf);
- }
-
- }
- }
-#endif
-
- proxy_encode_request_headers(srv, sess, con->recv);
-
- return 0;
-}
-
-/* we are event-driven
- *
- * the first entry is connect() call, if the doesn't need a event
- *
- * a bit boring
- * - connect (+ delayed connect)
- * - write header + content
- * - read header + content
- *
- * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
- * tell the core we are ready to stream out the content.
- * */
-static handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
- /* do we have a connection ? */
-
- if (p->conf.debug > 0)
- TRACE("proxy_state_engine: state=%d", sess->state);
-
- switch (sess->state) {
- case PROXY_STATE_UNSET:
- /* we are not started yet */
- sess->connect_start_ts = srv->cur_ts;
- switch(proxy_connection_connect(sess->proxy_con)) {
- case HANDLER_WAIT_FOR_EVENT:
- /* waiting on the connect call */
-
- fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
- fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
-
- sess->state = PROXY_STATE_CONNECTING;
- sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
- /**
- * if we are in
- *
- * connect(...) = -1 EINPROGRESS
- *
- * it might take ages until we get a response
- */
- sess->proxy_con->state_ts = srv->cur_ts;
- sess->proxy_con->proxy_sess = sess;
-
- /* if the client connection closes its end get notified */
- fdevent_event_add(srv->ev, con->sock, FDEVENT_HUP);
-
- return HANDLER_WAIT_FOR_EVENT;
- case HANDLER_GO_ON:
- /* we are connected */
- sess->state = PROXY_STATE_CONNECTED;
- sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
-
- /* initialize stream. */
- proxy_stream_init(srv, sess);
-
- fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
-
- break;
- case HANDLER_WAIT_FOR_FD:
- /* we have to come back later when we have a fd */
- return HANDLER_WAIT_FOR_FD;
- case HANDLER_ERROR:
- /* there is no-one on the other side */
- sess->proxy_con->address->disabled_until = srv->cur_ts + p->conf.disable_time;
-
- TRACE("connecting to address %s (%p) failed, disabling for %u sec",
- SAFE_BUF_STR(sess->proxy_con->address->name),
- (void*) sess->proxy_con->address,
- (unsigned int) p->conf.disable_time);
- COUNTER_INC(sess->proxy_backend->requests_failed);
-
- sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
- sess->proxy_backend->disabled_addresses++;
- /* if all addresses in address_pool are disabled, then disable this backend. */
-
- if (sess->proxy_backend->disabled_addresses == sess->proxy_backend->address_pool->used) {
- sess->proxy_backend->state = PROXY_BACKEND_STATE_DISABLED;
- }
- /* try another backend instead */
- return HANDLER_COMEBACK;
- default:
- /* not good, something failed */
- return HANDLER_ERROR;
-
- }
-
- /* fall through */
- case PROXY_STATE_CONNECTING:
- /* skip if already connected */
- if (sess->state == PROXY_STATE_CONNECTING) {
- int socket_error;
- socklen_t socket_error_len = sizeof(socket_error);
-
- fdevent_event_del(srv->ev, sess->proxy_con->sock);
-
- switch (sess->proxy_con->state) {
- case PROXY_CONNECTION_STATE_CONNECTING:
- if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- ERROR("getsockopt failed: %s", strerror(errno));
-
- return HANDLER_ERROR;
- }
- if (socket_error != 0) {
- switch (socket_error) {
- case ECONNREFUSED:
- /* there is no-one on the other side */
- sess->proxy_con->address->disabled_until = srv->cur_ts + p->conf.disable_time;
-
- TRACE("address %s refused us, disabling for %u sec", sess->proxy_con->address->name->ptr, (unsigned int) p->conf.disable_time);
- COUNTER_INC(sess->proxy_backend->requests_failed);
-
- break;
- case EHOSTUNREACH:
- /* there is no-one on the other side */
- sess->proxy_con->address->disabled_until = srv->cur_ts + p->conf.disable_time;
-
- TRACE("host %s is unreachable, disabling for %u sec", sess->proxy_con->address->name->ptr, (unsigned int) p->conf.disable_time);
- break;
- default:
- sess->proxy_con->address->disabled_until = srv->cur_ts + p->conf.disable_time;
-
- TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
-
- TRACE("connect to address %s failed and I don't know why, disabling for %u sec", sess->proxy_con->address->name->ptr, (unsigned int) p->conf.disable_time);
-
- break;
- }
-
- sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
- sess->proxy_backend->disabled_addresses++;
- /* if all addresses in address_pool are disabled, then disable this backend. */
- if (sess->proxy_backend->disabled_addresses == sess->proxy_backend->address_pool->used) {
- sess->proxy_backend->state = PROXY_BACKEND_STATE_DISABLED;
- }
- return HANDLER_COMEBACK;
- }
-
- sess->state = PROXY_STATE_CONNECTED;
- sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
-
- /* initialize stream. */
- proxy_stream_init(srv, sess);
-
- break;
- case PROXY_CONNECTION_STATE_CLOSED:
- /* looks like the connect() timed out */
- sess->proxy_con->address->disabled_until = srv->cur_ts + p->conf.disable_time;
- sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
-
- /* the connection */
- sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
-
- /* if all addresses in address_pool are disabled, then disable this backend. */
- sess->proxy_backend->disabled_addresses++;
-
- if (sess->proxy_backend->disabled_addresses == sess->proxy_backend->address_pool->used) {
- sess->proxy_backend->state = PROXY_BACKEND_STATE_DISABLED;
- }
- TRACE("connect(%s) to failed: trying another backed",
- SAFE_BUF_STR(sess->proxy_con->address->name));
- return HANDLER_COMEBACK;
- default:
- ERROR("invalid connection-state: %d", sess->proxy_con->state);
- break;
- }
- }
-
- /* fall through */
- case PROXY_STATE_CONNECTED:
-
- sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
-
- /* fall through */
- case PROXY_STATE_WRITE_REQUEST_HEADER:
- /* build the header */
- proxy_get_request_header(srv, con, p, sess);
-
- /* send the header together with the body */
- sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
-
- /* fall through */
- case PROXY_STATE_WRITE_REQUEST_BODY:
- /* do we have a content-body to send up to the backend ? */
-
- switch (proxy_stream_encode_decode(srv, sess)) {
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- /* some backends will send a response before all the request content has been written. */
- if (sess->is_closed || sess->have_response_headers) {
- chunk *c;
- if (sess->is_closed && !sess->have_response_headers) {
- if (sess->p->conf.debug) TRACE("%s", "connection to backend closed when sending request headers/content.");
- }
- if (con->recv->bytes_out < con->recv->bytes_in) {
- /* we have to consume all the request content data. */
- for (c = con->recv->first; c; c = c->next) {
- switch(c->type) {
- case MEM_CHUNK:
- c->offset = c->mem->used - 1;
- break;
- case FILE_CHUNK:
- c->offset = c->file.length;
- break;
- default:
- break;
- }
- }
- con->recv->bytes_out = con->recv->bytes_in;
- con->recv->is_closed = 1;
- }
- break;
- }
- return HANDLER_WAIT_FOR_EVENT;
- case HANDLER_ERROR:
- /* error */
- return HANDLER_ERROR;
- default:
- TRACE("stream-decoder: %s", "foo");
- break;
- }
-
- sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
- /* fall through */
- case PROXY_STATE_READ_RESPONSE_HEADER:
-
- /* decode/encode stream. */
- switch (proxy_stream_encode_decode(srv, sess)) {
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- if (!sess->proxy_con->recv->is_closed && !sess->have_response_headers) {
- return HANDLER_WAIT_FOR_EVENT;
- }
- break;
- case HANDLER_ERROR:
- /* error */
- return HANDLER_ERROR;
- default:
- TRACE("stream-decoder: %s", "foo");
- return HANDLER_ERROR;
- }
-
- if (sess->have_response_headers) {
- /* handle the parsed response headers. */
- switch (proxy_handle_response_headers(srv, con, p, sess, sess->recv)) {
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- break;
- case HANDLER_ERROR:
- /* bad gateway */
- con->http_status = 502;
- return HANDLER_FINISHED;
- default:
- ERROR("%s", "++ oops, something went wrong while parsing response headers");
- con->http_status = 500; /* Internal Server Error */
- return HANDLER_ERROR;
- }
- }
-
- if (!sess->is_closed && !sess->have_response_headers) {
- if (sess->proxy_con->recv->bytes_in == 0) {
- /* the connection went away before we got something back */
- if (p->conf.debug) TRACE("%s", "connection closed while reading the response headers");
-
- if (con->request.content_length <= 0) {
- /**
- * we might run into a 'race-condition'
- *
- * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
- * 2. new connection comes in, we use the idling connection [fd=14]
- * 3. we write(), successful [to fd=27]
- * 3. we read() ... and finally receive the close-event for the connection
- */
-
- return HANDLER_COMEBACK;
- } else {
- ERROR("%s", "request content length > 0 can't restart request.");
- }
- } else {
- ERROR("%s", "connection closed after reading part of the response headers.");
- }
-
- con->http_status = 500; /* Internal Server Error */
- return HANDLER_ERROR;
- } else if (sess->do_internal_redirect) {
- /* no more response data to process. do redirect now. */
- if (sess->recv->is_closed) {
- sess->state = PROXY_STATE_FINISHED;
- /* now it becomes tricky
- *
- * mod_staticfile should handle this file for us
- * con->mode = DIRECT is taking us out of the loop */
- con->mode = DIRECT;
- con->http_status = 0;
-
- return HANDLER_COMEBACK;
- } else {
- /* finish processing response data, so we can re-use backend connection. */
- sess->state = PROXY_STATE_READ_RESPONSE_BODY;
- }
- } else {
- con->file_started = 1;
- /* if Status: ... is not set, 200 is our default status-code */
- if (con->http_status == 0) con->http_status = 200;
-
- /* check if all the response content has been read/decoded. */
- if (sess->bytes_read == sess->content_length) {
- sess->is_request_finished = 1;
- /* close response content chunkqueue */
- sess->recv->is_closed = 1;
- }
- /* copy any response content we might have. */
- proxy_copy_response(srv, con, sess);
-
- sess->state = PROXY_STATE_READ_RESPONSE_BODY;
-
- /**
- * set the event to pass the content through to the server
- *
- * this triggers the event-handler
- * @see proxy_handle_fdevent
- */
-
- return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
- }
-
- if (sess->state != PROXY_STATE_READ_RESPONSE_BODY) break;
- case PROXY_STATE_READ_RESPONSE_BODY:
-
- switch (proxy_stream_encode_decode(srv, sess)) {
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- break;
- case HANDLER_ERROR:
- /* error */
- return HANDLER_ERROR;
- default:
- TRACE("stream-decoder: %s", "foo");
- break;
- }
-
- proxy_copy_response(srv, con, sess);
-
- if (!sess->proxy_con->recv->is_closed && !sess->is_request_finished) {
- return HANDLER_WAIT_FOR_EVENT;
- }
-
- if(sess->is_request_finished) {
- sess->recv->is_closed = 1;
- con->send->is_closed = 1;
- /* recycle proxy connection. */
- proxy_recycle_backend_connection(srv, p, sess);
-
- sess->state = PROXY_STATE_FINISHED;
-
- if (sess->do_internal_redirect) {
- /* now it becomes tricky
- *
- * mod_staticfile should handle this file for us
- * con->mode = DIRECT is taking us out of the loop */
- con->send->is_closed = 0;
- con->mode = DIRECT;
- con->http_status = 0;
-
- return HANDLER_COMEBACK;
- }
- }
-
- /* we wrote something into the the send-buffers,
- * call the connection-handler to push it to the client */
- joblist_append(srv, con);
-
- break;
- default:
- break;
- }
-
- return HANDLER_GO_ON;
-}
-
-static proxy_backend *proxy_find_backend(server *srv, connection *con, plugin_data *p, buffer *name) {
- size_t i;
-
- UNUSED(srv);
- UNUSED(con);
-
- for (i = 0; i < p->conf.backends->used; i++) {
- proxy_backend *backend = p->conf.backends->ptr[i];
-
- if (buffer_is_equal(backend->name, name)) {
- return backend;
- }
- }
-
- return NULL;
-}
-
-/**
- * choose an available backend
- *
- */
-static proxy_backend *proxy_backend_balancer(server *srv, connection *con, proxy_session *sess) {
- size_t i;
- plugin_data *p = sess->p;
- proxy_backends *backends = p->conf.backends;
- unsigned long last_max; /* for the HASH balancer */
- proxy_backend *backend = NULL, *cur_backend = NULL;
- int active_backends = 0, rand_ndx;
- size_t min_used;
-
- UNUSED(srv);
-
- /* if we only have one backend just return it. */
- if (backends->used == 1) {
- backend = backends->ptr[0];
-
- return backend->state == PROXY_BACKEND_STATE_ACTIVE ? backend : NULL;
- }
-
- /* frist try to select backend based on sticky session. */
- if (sess->sticky_session) {
- /* find backend */
- backend = proxy_find_backend(srv, con, p, sess->sticky_session);
- if (NULL != backend) return backend;
- }
-
- /* apply balancer algorithm to select backend. */
- switch(p->conf.balancer) {
- case PROXY_BALANCE_CARP:
- /* hash balancing */
-
- for (i = 0, last_max = ULONG_MAX; i < backends->used; i++) {
- unsigned long cur_max;
-
- cur_backend = backends->ptr[i];
-
- if (cur_backend->state != PROXY_BACKEND_STATE_ACTIVE) continue;
-
- cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
- generate_crc32c(CONST_BUF_LEN(cur_backend->name)) + /* we can cache this */
- generate_crc32c(CONST_BUF_LEN(con->uri.authority));
-#if 0
- TRACE("hash-election: %s - %s - %s: %ld",
- con->uri.path->ptr,
- cur_backend->name->ptr,
- con->uri.authority->ptr,
- cur_max);
-#endif
- if (backend == NULL || (cur_max > last_max)) {
- last_max = cur_max;
-
- backend = cur_backend;
- }
- }
-
- break;
- case PROXY_BALANCE_STATIC:
- /* static (only fail-over) */
-
- for (i = 0; i < backends->used; i++) {
- cur_backend = backends->ptr[i];
-
- if (cur_backend->state != PROXY_BACKEND_STATE_ACTIVE) continue;
-
- backend = cur_backend;
- break;
- }
-
- break;
- case PROXY_BALANCE_SQF:
- /* shortest-queue-first balancing */
-
- for (i = 0, min_used = SIZE_MAX; i < backends->used; i++) {
- cur_backend = backends->ptr[i];
-
- if (cur_backend->state != PROXY_BACKEND_STATE_ACTIVE) continue;
-
- /* the backend is up, use it */
- if (cur_backend->pool->used < min_used ) {
- backend = cur_backend;
- min_used = cur_backend->pool->used;
- }
- }
-
- break;
- case PROXY_BALANCE_UNSET: /* if not set, use round-robin as default */
- case PROXY_BALANCE_RR:
- /* round robin */
-
- /**
- * instead of real RoundRobin we just do a RandomSelect
- *
- * it is state-less and has the same distribution
- */
-
- active_backends = 0;
-
- for (i = 0; i < backends->used; i++) {
- cur_backend = backends->ptr[i];
-
- if (cur_backend->state != PROXY_BACKEND_STATE_ACTIVE) continue;
-
- active_backends++;
- }
-
- rand_ndx = (int) (1.0 * active_backends * rand()/(RAND_MAX));
-
- active_backends = 0;
- for (i = 0; i < backends->used; i++) {
- cur_backend = backends->ptr[i];
-
- if (cur_backend->state != PROXY_BACKEND_STATE_ACTIVE) continue;
-
- backend = cur_backend;
-
- if (rand_ndx == active_backends++) break;
- }
-
- break;
- }
-
- return backend;
-}
-
-/**
- * choose an available address from the address-pool
- *
- * the backend has different balancers
- */
-static proxy_address *proxy_address_balancer(server *srv, connection *con, proxy_session *sess) {
- size_t i;
- proxy_backend *backend = sess->proxy_backend;
- proxy_address_pool *address_pool = backend->address_pool;
- unsigned long last_max; /* for the HASH balancer */
- proxy_address *address = NULL, *cur_address = NULL;
- int active_addresses = 0, rand_ndx;
- size_t min_used;
-
- UNUSED(srv);
-
- /* if we only have one address just return it. */
- if (address_pool->used == 1) {
- address = address_pool->ptr[0];
-
- return address->state == PROXY_ADDRESS_STATE_ACTIVE ? address : NULL;
- }
-
- /* apply balancer algorithm to select address. */
- switch(backend->balancer) {
- case PROXY_BALANCE_CARP:
- /* hash balancing */
-
- for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
- unsigned long cur_max;
-
- cur_address = address_pool->ptr[i];
-
- if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
-
- cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
- generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
- generate_crc32c(CONST_BUF_LEN(con->uri.authority));
-#if 0
- TRACE("hash-election: %s - %s - %s: %ld",
- con->uri.path->ptr,
- cur_address->name->ptr,
- con->uri.authority->ptr,
- cur_max);
-#endif
- if (address == NULL || (cur_max > last_max)) {
- last_max = cur_max;
-
- address = cur_address;
- }
- }
-
- break;
- case PROXY_BALANCE_STATIC:
- /* static (only fail-over) */
-
- for (i = 0; i < address_pool->used; i++) {
- cur_address = address_pool->ptr[i];
-
- if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
-
- address = cur_address;
- break;
- }
-
- break;
- case PROXY_BALANCE_SQF:
- /* shortest-queue-first balancing */
-
- for (i = 0, min_used = SIZE_MAX; i < address_pool->used; i++) {
- cur_address = address_pool->ptr[i];
-
- if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
-
- /* the address is up, use it */
- if (cur_address->used < min_used ) {
- address = cur_address;
- min_used = cur_address->used;
- }
- }
-
- break;
- case PROXY_BALANCE_UNSET: /* if not set, use round-robin as default */
- case PROXY_BALANCE_RR:
- /* round robin */
-
- /**
- * instead of real RoundRobin we just do a RandomSelect
- *
- * it is state-less and has the same distribution
- */
-
- active_addresses = 0;
-
- for (i = 0; i < address_pool->used; i++) {
- cur_address = address_pool->ptr[i];
-
- if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
-
- active_addresses++;
- }
-
- rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
-
- active_addresses = 0;
- for (i = 0; i < address_pool->used; i++) {
- cur_address = address_pool->ptr[i];
-
- if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
-
- address = cur_address;
-
- if (rand_ndx == active_addresses++) break;
- }
-
- break;
- }
-
- return address;
-}
-
-static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- /* global defaults */
- PATCH_OPTION(balancer);
- PATCH_OPTION(debug);
- PATCH_OPTION(backends);
- PATCH_OPTION(backlog);
- PATCH_OPTION(backlog_size);
- PATCH_OPTION(protocol);
- PATCH_OPTION(request_rewrites);
- PATCH_OPTION(response_rewrites);
- PATCH_OPTION(allow_x_sendfile);
- PATCH_OPTION(allow_x_rewrite);
- PATCH_OPTION(max_pool_size);
- PATCH_OPTION(check_local);
- PATCH_OPTION(split_hostnames);
- PATCH_OPTION(max_keep_alive_requests);
- PATCH_OPTION(disable_time);
- PATCH_OPTION(max_backlog_size);
-
- /* 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_PROXY_CORE_BACKENDS))) {
- PATCH_OPTION(backends);
- PATCH_OPTION(backlog);
- PATCH_OPTION(backlog_size);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DEBUG))) {
- PATCH_OPTION(debug);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BALANCER))) {
- PATCH_OPTION(balancer);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_PROTOCOL))) {
- PATCH_OPTION(protocol);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
- PATCH_OPTION(request_rewrites);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
- PATCH_OPTION(response_rewrites);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_SENDFILE))) {
- PATCH_OPTION(allow_x_sendfile);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_REWRITE))) {
- PATCH_OPTION(allow_x_rewrite);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_MAX_POOL_SIZE))) {
- PATCH_OPTION(max_pool_size);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_CHECK_LOCAL))) {
- PATCH_OPTION(check_local);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_SPLIT_HOSTNAMES))) {
- PATCH_OPTION(split_hostnames);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_MAX_KEEP_ALIVE))) {
- PATCH_OPTION(max_keep_alive_requests);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DISABLE_TIME))) {
- PATCH_OPTION(disable_time);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_MAX_BACKLOG_SIZE))) {
- PATCH_OPTION(max_backlog_size);
- }
- }
- }
-
- return 0;
-}
-
-static int mod_proxy_core_check_match(server *srv, connection *con, plugin_data *p, int file_match) {
- proxy_session *sess = con->plugin_ctx[p->id];
- buffer *path;
-
- if (sess && !sess->do_new_session) {
- /* if this is the second round, sess is already prepared */
- return HANDLER_GO_ON;
- }
-
- /* check if we have a matching conditional for this request */
- mod_proxy_core_patch_connection(srv, con, p);
-
- /* no proxy backends to handle this request. */
- if (p->conf.backends->used == 0) return HANDLER_GO_ON;
-#if 0
- /* if check_local is enabled, then wait for file match. */
- if (file_match != p->conf.check_local) return HANDLER_GO_ON;
-#endif
- path = file_match ? con->physical.path : con->uri.path;
-#if 0
- if (buffer_is_empty(path)) return HANDLER_GO_ON;
-#endif
- if (sess && sess->do_x_rewrite_backend) {
- proxy_backend *backend;
- buffer *sticky_session = sess->sticky_session;
-
- sess->sticky_session = NULL;
- /* clear old session state */
- proxy_session_reset(sess);
-
- /* find backend */
- backend = proxy_find_backend(srv, con, p, sticky_session);
- if (backend == NULL) {
- backend = proxy_backend_init();
-
- backend->balancer = p->conf.balancer;
- backend->protocol = p->conf.protocol;
-
- buffer_copy_string_buffer(backend->name, sticky_session);
- /* check if the new backend has a valid backend-address */
- if (0 == proxy_address_pool_add_string(backend->address_pool, backend->name)) {
- if (p->conf.max_pool_size) {
- backend->pool->max_size = p->conf.max_pool_size;
- }
-
- proxy_backends_add(p->conf.backends, backend);
- } else {
- proxy_backend_free(backend);
- backend = NULL;
- }
- }
- /* no backend available. */
- if (NULL == backend) {
- buffer_free(sticky_session);
- return HANDLER_GO_ON;
- }
- sess->proxy_backend = backend;
- sess->sticky_session = sticky_session;
- } else if (sess) {
- proxy_session_reset(sess);
- }
-
- /* make sure we have a protocol. */
- if (p->conf.protocol == NULL) {
- con->http_status = 500; /* internal error */
- con->send->is_closed = 1;
-
- TRACE("proxy-core.backends is set, but proxy-core.protocol is not, can't handle '%s' for host '%s'",
- SAFE_BUF_STR(con->uri.path),
- SAFE_BUF_STR(con->uri.authority));
- return HANDLER_FINISHED;
- }
-
- if (!sess) {
- /* a session lives for a single request */
- sess = proxy_session_init();
- }
- /* make sure the state is correct. */
- sess->state = PROXY_STATE_UNSET;
-
- con->plugin_ctx[p->id] = sess;
- con->mode = p->id;
-
- if (con->conf.log_request_handling) {
- TRACE("handling it in mod_proxy_core: %s.path=%s",
- file_match ? "physical" : "uri", SAFE_BUF_STR(path));
- }
- sess->p = p;
- sess->remote_con = con;
-
- return HANDLER_FINISHED;
-}
-
-SUBREQUEST_FUNC(mod_proxy_core_match_url) {
- return mod_proxy_core_check_match(srv, con, p_d, 0);
-}
-
-SUBREQUEST_FUNC(mod_proxy_core_match_local_file) {
- return mod_proxy_core_check_match(srv, con, p_d, 1);
-}
-
-/**
- * end of a request
- */
-REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
- plugin_data *p = p_d;
- proxy_session *sess = con->plugin_ctx[p->id];
-
- if (!sess) return HANDLER_GO_ON;
-
- /* TODO: copy p->conf into proxy_session when request starts. */
- /* re-patch p->conf */
- mod_proxy_core_patch_connection(srv, con, p);
-
- if (p->conf.debug) TRACE("proxy_connection_reset (%d)", con->sock->fd);
-
- if (sess->proxy_con) {
- proxy_recycle_backend_connection(srv, p, sess);
- } else {
- /* if we have the connection in the backlog, remove it */
- if (0 == proxy_backlog_remove_connection(p->conf.backlog, con)) {
- COUNTER_DEC(p->conf.backlog_size);
- }
- }
-
- /* cleanup proxy session */
- proxy_session_free(sess);
-
- con->plugin_ctx[p->id] = NULL;
-
- return HANDLER_GO_ON;
-}
-
-CONNECTION_FUNC(mod_proxy_core_start_backend) {
- plugin_data *p = p_d;
- proxy_session *sess = con->plugin_ctx[p->id];
-
- if (p->id != con->mode) return HANDLER_GO_ON;
- if (!sess) return HANDLER_GO_ON;
-
- /* TODO: copy p->conf into proxy_session when request starts. */
- /* re-patch p->conf */
- mod_proxy_core_patch_connection(srv, con, p);
-
- /*
- * 0. build session
- * 1. get a proxy connection
- * 2. create the http-request header
- * 3. stream the content to the backend
- * 4. wait for http-response header
- * 5. decode the response + parse the response
- * 6. stream the response-content to the client
- * 7. session finished wait for request close
- * 8. kill session
- * */
-
- if (sess->do_internal_redirect) {
- if (sess->internal_redirect_count > MAX_INTERNAL_REDIRECTS) {
- /* we already handled this request and sent it to the static file handling */
-
- return HANDLER_GO_ON;
- }
- }
-
- switch (sess->state) {
- case PROXY_STATE_FINISHED:
- return HANDLER_GO_ON;
- case PROXY_STATE_CONNECTING:
- /* this connections has waited 10 seconds to connect to the backend
- * and didn't got a successful connection yet, sending timeout */
- if (srv->cur_ts - sess->connect_start_ts > 10) {
- con->http_status = 504; /* gateway timeout */
- con->send->is_closed = 1;
-
- if (sess->proxy_con) {
- TRACE("connect to backend timed out: %s", SAFE_BUF_STR(sess->proxy_con->address->name));
- /* if we are waiting for a proxy-connection right now, close it */
- proxy_remove_backend_connection(srv, sess);
- } else {
- TRACE("%s", "timed out when trying to connect to backend and don't have a connection.");
- }
-
- return HANDLER_FINISHED;
- }
- default:
- /* handle-request-timeout, */
-#if 0
- if (srv->cur_ts - con->request_start > 60) {
- TRACE("request runs longer than 60sec: current state: %d", sess->state);
- }
-#endif
- break;
- }
-
-
- /* if the WRITE fails from the start, restart the connection */
- while (1) {
- if (sess->proxy_con == NULL) {
- proxy_address *address = NULL;
-
- /**
- * ask the balancer for the next address and
- * check the connection pool if we have a connection open
- * for that address
- */
- if (NULL == (sess->proxy_backend = proxy_backend_balancer(srv, con, sess))) {
- if (p->conf.debug) TRACE("backlog: all backends are full or down, putting %s (%d) into the backlog, retry = %d",
- SAFE_BUF_STR(con->uri.path), con->sock->fd, sess->sent_to_backlog + 1);
-
- /* no backends available right now. */
- if (HANDLER_ERROR == mod_proxy_core_backlog_connection(srv, con, p, sess)) {
- con->http_status = 504; /* gateway timeout */
- con->send->is_closed = 1;
-
- TRACE("connecting backends timed out, retry limit reached: %d", sess->sent_to_backlog);
- return HANDLER_FINISHED;
- }
-
- /* no, not really an event,
- * we just want to block the outer loop from stepping forward
- *
- * the trigger will bring this connection back into the game
- */
- return HANDLER_WAIT_FOR_EVENT;
- }
-
- sess->proxy_backend->protocol = p->conf.protocol;
- sess->proxy_backend->balancer = p->conf.balancer;
-
- if (p->conf.debug && sess->proxy_backend) {
- TRACE("selected backend: %s, state: %d", SAFE_BUF_STR(sess->proxy_backend->name), sess->proxy_backend->state);
- }
-
- /**
- * ask the balancer for the next address and
- * check the connection pool if we have a connection open
- * for that address
- */
- if (NULL == (address = proxy_address_balancer(srv, con, sess))) {
- /* no addresses available for this backend right now. */
- sess->proxy_backend->state = PROXY_BACKEND_STATE_DISABLED; /* disable backend */
- TRACE("backlog: all addresses are down, putting %s (%d) into the backlog, retry = %d",
- SAFE_BUF_STR(con->uri.path), con->sock->fd, sess->sent_to_backlog + 1);
-
- if (HANDLER_ERROR == mod_proxy_core_backlog_connection(srv, con, p, sess)) {
- con->http_status = 504; /* gateway timeout */
- con->send->is_closed = 1;
-
- TRACE("connecting backends timed out, retry limit reached: %d", sess->sent_to_backlog);
- return HANDLER_FINISHED;
- }
-
- /* no, not really an event,
- * we just want to block the outer loop from stepping forward
- *
- * the trigger will bring this connection back into the game
- */
-
- return HANDLER_WAIT_FOR_EVENT;
- }
-
- if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
- sess->proxy_backend->pool, address, &(sess->proxy_con))) {
- /* all connections are busy. */
- sess->proxy_backend->state = PROXY_BACKEND_STATE_FULL;
-
- if (p->conf.debug) TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", SAFE_BUF_STR(con->uri.path), con->sock->fd);
- if (HANDLER_ERROR == mod_proxy_core_backlog_connection(srv, con, p, sess)) {
- con->http_status = 504; /* gateway timeout */
- con->send->is_closed = 1;
-
- TRACE("connecting backends timed out, retry limit reached: %d", sess->sent_to_backlog);
- return HANDLER_FINISHED;
- }
-
- /* no, not really an event,
- * we just want to block the outer loop from stepping forward
- *
- * the trigger will bring this connection back into the game
- */
- return HANDLER_WAIT_FOR_EVENT;
- }
- COUNTER_SET(sess->proxy_backend->pool_size, sess->proxy_backend->pool->used);
- COUNTER_INC(sess->proxy_backend->load);
-
- /* need to reset flags. */
- sess->is_closing = 0;
- sess->is_closed = 0;
- /* a fresh connection, we need address for it */
- if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
- sess->state = PROXY_STATE_UNSET;
- sess->bytes_read = 0;
- } else {
- /* we are already connected */
- sess->state = PROXY_STATE_CONNECTED;
-
- /* the connection was idling and using the fdevent_idle-handler
- * switch it back to the normal proxy-event-handler */
- fdevent_event_del(srv->ev, sess->proxy_con->sock);
- fdevent_unregister(srv->ev, sess->proxy_con->sock);
-
- fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
- fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
- }
- }
-
-
- switch (proxy_state_engine(srv, con, p, sess)) {
- case HANDLER_WAIT_FOR_EVENT:
- return HANDLER_WAIT_FOR_EVENT;
- case HANDLER_COMEBACK:
-#if 0
- TRACE("%s", "setting PROXY_STATE_FINISHED");
- sess->state = PROXY_STATE_FINISHED;
-#endif
- /* request finished do redirect. */
- if (sess->do_internal_redirect) {
- /* recycle proxy connection. */
- proxy_recycle_backend_connection(srv, p, sess);
- return HANDLER_COMEBACK;
- }
- /* restart the connection to the backend */
- if (p->conf.debug) TRACE("%s", "write failed, restarting request");
- proxy_remove_backend_connection(srv, sess);
- break;
- case HANDLER_WAIT_FOR_FD:
- return HANDLER_WAIT_FOR_FD;
- case HANDLER_GO_ON:
- return HANDLER_GO_ON;
- default:
- TRACE("state: %d (error)", sess->state);
- proxy_remove_backend_connection(srv, sess);
- /* only set 500 if not another error code is already set (like 502) */
- if (con->http_status < 500 || con->http_status > 599) {
- con->http_status = 500; /* Internal Server Error */
- }
- con->mode = DIRECT;
- return HANDLER_GO_ON;
- }
- }
-
- /* should not be reached */
- return HANDLER_ERROR;
-}
-
-CONNECTION_FUNC(mod_proxy_send_request_content) {
- plugin_data *p = p_d;
-
- if (p->id != con->mode) return HANDLER_GO_ON;
-
- /* read all the content before we start our backend */
- if (!con->recv->is_closed) {
- return HANDLER_GO_ON;
- }
-
- /* copy the chunks to our queue and call the state-engine to send it out */
- return mod_proxy_core_start_backend(srv, con, p_d);
-}
-
-/**
- * cleanup dead connections once a second
- *
- * the idling event-handler can't cleanup connections itself and has to wait until the
- * trigger cleans up
- */
-static int mod_proxy_wakeup_connections(server *srv, plugin_data *p, plugin_config *p_conf) {
- size_t i, j;
- proxy_request *req;
- int total_conns_available = 0, backends_available = 0;
- int woken_up;
-
- for (i = 0; i < p_conf->backends->used; i++) {
- proxy_backend *backend = p_conf->backends->ptr[i];
- proxy_connection_pool *pool = backend->pool;
- proxy_address_pool *address_pool = backend->address_pool;
- unsigned int conns_available = 0, addrs_disabled = 0;
- proxy_session *sess = NULL;
-
- conns_available = (pool->max_size - pool->used);
- for (j = 0; j < pool->used; ) {
- proxy_connection *proxy_con = pool->ptr[j];
-
- /* remove-con is removing the current con and moves the good connections to the left
- * no need to increment i */
- switch (proxy_con->state) {
- case PROXY_CONNECTION_STATE_CLOSED:
- proxy_connection_pool_remove_connection(backend->pool, proxy_con);
- COUNTER_SET(backend->pool_size, backend->pool->used);
-
- fdevent_event_del(srv->ev, proxy_con->sock);
- fdevent_unregister(srv->ev, proxy_con->sock);
-
- proxy_connection_free(proxy_con);
-
- conns_available++;
- break;
- case PROXY_CONNECTION_STATE_CONNECTING:
- /* how long are we in this state already ?
- *
- * if the connect() failed with EINPROGRESS we have to wait until we get a POLLOUT
- * if for some reason we don't get that in 4-5 seconds we have to kill the attempt
- *
- * */
-
- if (srv->cur_ts - proxy_con->state_ts < 5) {
- j++;
- break;
- }
-
- TRACE("connect(%s) timed out, closing backend connection",
- SAFE_BUF_STR(proxy_con->address->name));
-
- /** timed out
- *
- * we have to tell the proxy connection to try to connect another backend
- */
-
- proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
-
- sess = proxy_con->proxy_sess;
- joblist_append(srv, sess->remote_con);
-
- j++;
- break;
- case PROXY_CONNECTION_STATE_IDLE:
- conns_available++;
- default:
- j++;
- }
- }
-
- /* active the disabled addresses again */
- for (j = 0; j < address_pool->used; j++) {
- proxy_address *address = address_pool->ptr[j];
-
- if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
-
- if (srv->cur_ts > address->disabled_until) {
- address->disabled_until = 0;
- address->state = PROXY_ADDRESS_STATE_ACTIVE;
- } else {
- addrs_disabled++;
- }
- }
-
- total_conns_available += conns_available;
- backend->disabled_addresses = addrs_disabled;
- /* update backend's state */
- if (conns_available == 0) {
- /* connection pool is full and there are no idle connections. */
- backend->state = PROXY_BACKEND_STATE_FULL;
- } else if (addrs_disabled == address_pool->used) {
- /* all addresses are disabled. */
- backend->state = PROXY_BACKEND_STATE_DISABLED;
- } else {
- backend->state = PROXY_BACKEND_STATE_ACTIVE;
- backends_available++;
- }
- }
-
- /* no backends available can't wake any connections. */
- if (backends_available == 0) {
- /* all backends are full or disabled. */
- return 0;
- }
-
- /* wake up the connections from the backlog */
- for (woken_up = 0; woken_up < total_conns_available && (req = proxy_backlog_shift(p_conf->backlog)); woken_up++) {
- connection *con = req->con;
-
- if (p_conf->debug) TRACE("wakeup a connection from backlog: con=%d", con->sock->fd);
- joblist_append(srv, con);
-
- COUNTER_DEC(p->conf.backlog_size);
- proxy_request_free(req);
- }
-
- return woken_up;
-}
-
-TRIGGER_FUNC(mod_proxy_trigger) {
- plugin_data *p = p_d;
- size_t i;
-
- /**
- * walk through all the different address pools and check if they are still alive
- *
- * in case of connect() = -1 -> EINPROGRESS we might have trigger the state-engine
- */
- for (i = 0; i < srv->config_context->used; i++) {
- mod_proxy_wakeup_connections(srv, p, p->config_storage[i]);
- }
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_core_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_core_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_core");
-
- p->init = mod_proxy_core_init;
- p->cleanup = mod_proxy_core_free;
- p->set_defaults = mod_proxy_core_set_defaults;
- p->handle_physical = mod_proxy_core_match_url;
- p->handle_start_backend = mod_proxy_core_match_local_file;
- p->handle_send_request_content = mod_proxy_send_request_content;
- p->handle_read_response_content = mod_proxy_core_start_backend;
- p->connection_reset = mod_proxy_connection_close_callback;
- p->handle_connection_close = mod_proxy_connection_close_callback;
- p->handle_trigger = mod_proxy_trigger;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_proxy_core.h b/src/mod_proxy_core.h
deleted file mode 100644
index a3685539..00000000
--- a/src/mod_proxy_core.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifndef _MOD_PROXY_CORE_H_
-#define _MOD_PROXY_CORE_H_
-
-#include "plugin.h"
-
-#include "mod_proxy_core_pool.h"
-#include "mod_proxy_core_backend.h"
-#include "mod_proxy_core_backlog.h"
-#include "mod_proxy_core_rewrites.h"
-
-#include "buffer.h"
-#include "http_resp.h"
-#include "array.h"
-
-#define MAX_INTERNAL_REDIRECTS 8
-
-struct proxy_protocol;
-
-typedef struct {
- proxy_backends *backends;
-
- proxy_backlog *backlog;
- data_integer *backlog_size;
-
- proxy_rewrites *request_rewrites;
- proxy_rewrites *response_rewrites;
-
- unsigned short allow_x_sendfile;
- unsigned short allow_x_rewrite;
- unsigned short debug;
- unsigned short max_pool_size;
- unsigned short check_local;
- unsigned short split_hostnames;
- unsigned short max_keep_alive_requests;
- unsigned short disable_time;
- unsigned short max_backlog_size;
-
- proxy_balance_t balancer;
- struct proxy_protocol *protocol;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- array *possible_balancers;
- /*array *possible_protocols; */
- struct proxy_protocol *(*proxy_register_protocol) (const char *name); /* register new protocol */
-
- /* statistics counters. */
- data_integer *request_count;
-
- /* for parsing only */
- array *backends_arr;
- buffer *protocol_buf;
- buffer *balance_buf;
-
- buffer *replace_buf;
-
- buffer *tmp_buf; /** a temporary buffer, used by mod_proxy_backend_fastcgi */
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} mod_proxy_core_plugin_data;
-
-#define plugin_data mod_proxy_core_plugin_data
-
-typedef enum {
- PROXY_STATE_UNSET,
- PROXY_STATE_CONNECTING,
- PROXY_STATE_CONNECTED,
- PROXY_STATE_WRITE_REQUEST_HEADER,
- PROXY_STATE_WRITE_REQUEST_BODY,
- PROXY_STATE_READ_RESPONSE_HEADER,
- PROXY_STATE_READ_RESPONSE_BODY,
- PROXY_STATE_FINISHED
-} proxy_state_t;
-
-typedef struct proxy_session {
- proxy_connection *proxy_con;
- proxy_backend *proxy_backend;
-
- connection *remote_con;
-
- buffer *request_uri;
- array *request_headers; /** the con->request.headers without the hop-to-hop headers */
- array *env_headers; /** transformed request-headers for the backend */
-
- http_resp *resp; /** response http headers from backend. */
-
- plugin_data *p; /** used by proxy_xxx_get_request_chunk protocol callbacks */
-
- int is_chunked; /** is the incoming content chunked (for HTTP) */
- int is_closing; /** our connection will close when we are done */
- int is_closed; /** our connection closed. we might have to restart the request. */
- int have_response_headers; /** finished parsing response headers. */
- int is_request_finished; /** encoding/decoding this request is finished. */
- int send_response_content; /** 0 if we have to ignore the content-body */
- int do_internal_redirect; /** 1 if we do a internal redirect to the ->mode = DIRECT */
- int internal_redirect_count; /** protection against infinite loops */
- int do_new_session; /** 1 if we want a new proxy session can be created. */
- int do_x_rewrite_backend; /** 1 if we want to do custom backend balancing */
-
- buffer *sticky_session; /** holds name of backend for custom balancing or sticky sessions */
-
- /**
- * chunkqueues
- * - recv is the decoded response headers and content
- */
- chunkqueue *recv;
-
- off_t bytes_read;
- off_t content_length;
-
- proxy_state_t state;
-
- time_t connect_start_ts;
-
- int sent_to_backlog;
-} proxy_session;
-
-#endif
diff --git a/src/mod_proxy_core_address.c b/src/mod_proxy_core_address.c
deleted file mode 100644
index 0978c9d1..00000000
--- a/src/mod_proxy_core_address.c
+++ /dev/null
@@ -1,210 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-
-#include "log.h"
-#include "sys-socket.h"
-#include "mod_proxy_core_address.h"
-
-static proxy_address *proxy_address_init(void) {
- proxy_address *address;
-
- address = calloc(1, sizeof(*address));
-
- address->name = buffer_init();
- address->used = 0;
-
- return address;
-}
-
-static void proxy_address_free(proxy_address *address) {
- if (!address) return;
-
- buffer_free(address->name);
-
- free(address);
-}
-
-
-proxy_address_pool *proxy_address_pool_init(void) {
- proxy_address_pool *address_pool;
-
- address_pool = calloc(1, sizeof(*address_pool));
-
- return address_pool;
-}
-
-void proxy_address_pool_free(proxy_address_pool *address_pool) {
- if (!address_pool) return;
-
- ARRAY_STATIC_FREE(address_pool, proxy_address, element, proxy_address_free(element));
-
- free(address_pool);
-}
-
-void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
- size_t i;
-
- /* check if this address is already known */
-
- for (i = 0; i < address_pool->used; i++) {
- proxy_address *pool_address = address_pool->ptr[i];
-
- if (buffer_is_equal(address->name, pool_address->name)) {
- /* TRACE("%s is already in the address-pool", SAFE_BUF_STR(address->name)); */
-
- proxy_address_free(address);
-
- return;
- }
- }
-
- /* TRACE("adding %s to the address-pool", SAFE_BUF_STR(address->name)); */
-
- ARRAY_STATIC_PREPARE_APPEND(address_pool);
-
- address_pool->ptr[address_pool->used++] = address;
-}
-
-int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
- struct addrinfo *res = NULL, pref, *cur;
- int ret;
- buffer *hostname = NULL, *port = NULL;
- char *colon;
-
- pref.ai_flags = 0;
- pref.ai_family = PF_UNSPEC;
- pref.ai_socktype = SOCK_STREAM;
- pref.ai_protocol = 0;
- pref.ai_addrlen = 0;
- pref.ai_addr = NULL;
- pref.ai_canonname = NULL;
- pref.ai_next = NULL;
-
- /* check the address style
- *
- * unix:/tmp/socket
- * www.example.org
- * www.example.org:80
- * 127.0.0.1
- * 127.0.0.1:80
- * [::1]:80
- * [::1]
- */
-
- if (buffer_is_empty(name)) return -1;
-
- if (0 == strncmp(BUF_STR(name), "unix:", 5)) {
- /* a unix domain socket */
-#ifdef HAVE_SYS_UN_H
- proxy_address *a = proxy_address_init();
-
- /* setup AF_UNIX sockaddr */
- a->addr.un.sun_family = AF_UNIX;
- strcpy(a->addr.un.sun_path, BUF_STR(name) + 5);
- a->addrlen = sizeof(a->addr.un);
-/*
-#ifdef SUN_LEN
- a->addrlen = SUN_LEN(&(a->addr.un));
-#else
- a->addrlen = (name->used - 5) + sizeof(a->addr.un.sun_family);
-#endif
-*/
-
- a->state = PROXY_ADDRESS_STATE_ACTIVE;
- buffer_copy_string_buffer(a->name, name);
-
- proxy_address_pool_add(address_pool, a);
- return 0;
-#else
- ERROR("unix: scheme is not supported for %s", SAFE_BUF_STR(name));
- return -1;
-#endif
- } else if (name->ptr[0] == '[') {
- if (name->ptr[name->used - 1] == ']') {
- /* no port-number attached */
-
- hostname = buffer_init();
- buffer_copy_string_len(hostname, BUF_STR(name) + 1, name->used - 3);
- port = buffer_init_string("80");
- } else if (NULL != (colon = strrchr(BUF_STR(name), ':'))) {
- /* with port number */
-
- hostname = buffer_init();
- buffer_copy_string_len(hostname, BUF_STR(name) + 1, colon - BUF_STR(name) - 2);
- port = buffer_init();
- buffer_copy_string(port, colon + 1);
-
- } else {
- ERROR("this is neither [<ipv6-address>] nor [<ipv6-address>]:<port>: %s", SAFE_BUF_STR(name));
-
- return -1;
- }
- } else if (name->ptr[name->used - 1] != ']' &&
- NULL != (colon = strrchr(BUF_STR(name), ':'))) {
-
- hostname = buffer_init();
- buffer_copy_string_len(hostname, BUF_STR(name), colon - BUF_STR(name));
- port = buffer_init();
- buffer_copy_string(port, colon + 1);
- } else {
- /* no colon, just a IPv4 address or a domain name */
-
- hostname = buffer_init_string(BUF_STR(name));
- port = buffer_init_string("80");
- }
-
- /* TRACE("resolving %s on port %s", SAFE_BUF_STR(hostname), SAFE_BUF_STR(port)); */
-
- if (0 != (ret = getaddrinfo(BUF_STR(hostname), BUF_STR(port), &pref, &res))) {
- ERROR("getaddrinfo failed: %s", gai_strerror(ret));
-
- buffer_free(hostname);
- buffer_free(port);
-
- return -1;
- }
-
- buffer_free(hostname);
- buffer_free(port);
-
- for (cur = res; cur; cur = cur->ai_next) {
- proxy_address *a = proxy_address_init();
-
- memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
- a->addrlen = cur->ai_addrlen;
-
- a->state = PROXY_ADDRESS_STATE_ACTIVE;
- buffer_prepare_copy(a->name, 128);
-
- switch (cur->ai_family) {
-#ifdef HAVE_IPV6
- case AF_INET6:
- a->name->ptr[0] = '[';
- inet_ntop(cur->ai_family, &(a->addr.ipv6.sin6_addr), a->name->ptr + 1, a->name->size - 2);
- a->name->used = strlen(a->name->ptr) + 1;
- buffer_append_string_len(a->name, CONST_STR_LEN("]:"));
- buffer_append_long(a->name, ntohs(a->addr.ipv6.sin6_port));
- break;
-#endif
- case AF_INET:
- inet_ntop(cur->ai_family, &(a->addr.ipv4.sin_addr), a->name->ptr, a->name->size - 1);
- a->name->used = strlen(a->name->ptr) + 1;
-
- buffer_append_string_len(a->name, CONST_STR_LEN(":"));
- buffer_append_long(a->name, ntohs(a->addr.ipv4.sin_port));
- break;
- default:
- ERROR("unknown address-family: %d", cur->ai_family);
- return -1;
- }
-
-
- proxy_address_pool_add(address_pool, a);
- }
-
- freeaddrinfo(res);
-
- return 0;
-}
-
-
diff --git a/src/mod_proxy_core_address.h b/src/mod_proxy_core_address.h
deleted file mode 100644
index c7177ca7..00000000
--- a/src/mod_proxy_core_address.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _MOD_PROXY_CORE_ADDRESS_H_
-#define _MOD_PROXY_CORE_ADDRESS_H_
-
-#include <time.h>
-#include "buffer.h"
-#include "sys-socket.h"
-#include "array-static.h"
-
-typedef enum {
- PROXY_ADDRESS_STATE_UNSET,
- PROXY_ADDRESS_STATE_ACTIVE,
- PROXY_ADDRESS_STATE_DISABLED,
-} proxy_address_state_t;
-
-typedef struct {
- sock_addr addr;
- socklen_t addrlen;
-
- buffer *name; /* a inet_ntoa() prepresentation of the address */
-
- time_t last_used;
- time_t disabled_until;
-
- size_t used; /* count of connections currently using this address */
-
- proxy_address_state_t state;
-} proxy_address;
-
-ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
-
-proxy_address_pool *proxy_address_pool_init(void);
-void proxy_address_pool_free(proxy_address_pool *address_pool);
-void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
-int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
-
-#endif
diff --git a/src/mod_proxy_core_backend.c b/src/mod_proxy_core_backend.c
deleted file mode 100644
index 60648f6c..00000000
--- a/src/mod_proxy_core_backend.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <stdlib.h>
-
-#include "mod_proxy_core_backend.h"
-#include "mod_proxy_core_pool.h"
-#include "mod_proxy_core_address.h"
-
-proxy_backend *proxy_backend_init(void) {
- proxy_backend *backend;
-
- backend = calloc(1, sizeof(*backend));
- backend->pool = proxy_connection_pool_init();
- backend->address_pool = proxy_address_pool_init();
- backend->balancer = PROXY_BALANCE_RR;
- backend->name = buffer_init();
- backend->state = PROXY_BACKEND_STATE_ACTIVE;
-
- return backend;
-}
-
-void proxy_backend_free(proxy_backend *backend) {
- if (!backend) return;
-
- proxy_connection_pool_free(backend->pool);
- proxy_address_pool_free(backend->address_pool);
- buffer_free(backend->name);
-
- free(backend);
-}
-
-proxy_backends *proxy_backends_init(void) {
- proxy_backends *backends;
-
- backends = calloc(1, sizeof(*backends));
-
- return backends;
-}
-
-void proxy_backends_free(proxy_backends *backends) {
- if (!backends) return;
-
- ARRAY_STATIC_FREE(backends, proxy_backend, element, proxy_backend_free(element));
-
- free(backends);
-}
-
-void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
- ARRAY_STATIC_PREPARE_APPEND(backends);
-
- backends->ptr[backends->used++] = backend;
-}
diff --git a/src/mod_proxy_core_backend.h b/src/mod_proxy_core_backend.h
deleted file mode 100644
index b9fa1c33..00000000
--- a/src/mod_proxy_core_backend.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef _MOD_PROXY_CORE_BACKEND_H_
-#define _MOD_PROXY_CORE_BACKEND_H_
-
-#include "array-static.h"
-#include "array.h"
-#include "buffer.h"
-#include "mod_proxy_core_address.h"
-#include "mod_proxy_core_pool.h"
-#include "sys-socket.h"
-
-/**
- * a single DNS name might explode to several IP addresses
- *
- * url:
- * - http://foo.bar/suburl/
- * - https://foo.bar/suburl/
- * - unix:/tmp/socket
- * - tcp://foobar:1025/
- *
- * backend:
- * - scgi
- * - http
- * - fastcgi
- * - ajp13
- *
- * request-url-rewrite
- * response-url-rewrite
- */
-typedef enum {
- PROXY_BALANCE_UNSET,
- PROXY_BALANCE_SQF,
- PROXY_BALANCE_CARP,
- PROXY_BALANCE_RR,
- PROXY_BALANCE_STATIC
-} proxy_balance_t;
-
-typedef enum {
- PROXY_BACKEND_STATE_UNSET,
- PROXY_BACKEND_STATE_ACTIVE,
- PROXY_BACKEND_STATE_FULL,
- PROXY_BACKEND_STATE_DISABLED,
-} proxy_backend_state_t;
-
-typedef struct {
- buffer *name;
-
- proxy_connection_pool *pool; /* pool of active connections */
- int use_keepalive;
-
- proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
- unsigned int disabled_addresses; /* track how many addresses are disabled. */
- proxy_balance_t balancer; /* how to choose a address from the address-pool */
- struct proxy_protocol *protocol; /* protocol handler */
-
- proxy_backend_state_t state;
-
- /* statistics counters. */
- data_integer *request_count;
- data_integer *load;
- data_integer *pool_size;
- data_integer *requests_failed;
-} proxy_backend;
-
-ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
-
-proxy_backend *proxy_backend_init(void);
-void proxy_backend_free(proxy_backend *backend);
-
-proxy_backends *proxy_backends_init(void);
-void proxy_backends_free(proxy_backends *backends);
-void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
-
-#endif
-
diff --git a/src/mod_proxy_core_backlog.c b/src/mod_proxy_core_backlog.c
deleted file mode 100644
index 11a59a59..00000000
--- a/src/mod_proxy_core_backlog.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <stdlib.h>
-
-#include "mod_proxy_core_backlog.h"
-#include "array-static.h"
-
-proxy_backlog *proxy_backlog_init(void) {
- STRUCT_INIT(proxy_backlog, backlog);
-
- return backlog;
-}
-
-void proxy_backlog_free(proxy_backlog *backlog) {
- if (!backlog) return;
-
- free(backlog);
-}
-
-int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
- /* first entry */
- if (NULL == backlog->first) {
- backlog->first = backlog->last = req;
- } else {
- backlog->last->next = req;
- backlog->last = req;
- }
- backlog->length++;
-
- return 0;
-}
-
-/**
- * remove the first element from the backlog
- */
-proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
- proxy_request *req = NULL;
-
- if (!backlog->first) return req;
-
- backlog->length--;
-
- req = backlog->first;
-
- backlog->first = req->next;
-
- /* the backlog is empty */
- if (backlog->first == NULL) backlog->last = NULL;
-
- return req;
-}
-
-int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
- proxy_request *req = NULL;
-
- if (!backlog->first) return -1;
- if (!con) return -1;
-
- /* the first element is what we look for */
- if (backlog->first->con == con) {
- req = backlog->first;
-
- backlog->first = req->next;
- if (backlog->first == NULL) backlog->last = NULL;
-
- backlog->length--;
-
- proxy_request_free(req);
-
- return 0;
- }
-
-
- for (req = backlog->first; req && req->next; req = req->next) {
- proxy_request *cur;
-
- if (req->next->con != con) continue;
-
- backlog->length--;
- /* the next node is our searched connection */
-
- cur = req->next;
- req->next = cur->next;
-
- /* the next node is the last one, make the current the new last */
- if (cur == backlog->last) {
- backlog->last = req;
- }
- cur->next = NULL;
-
- proxy_request_free(cur);
-
- return 0;
- }
-
- return -1;
-}
-
-proxy_request *proxy_request_init(void) {
- STRUCT_INIT(proxy_request, request);
-
- return request;
-}
-
-void proxy_request_free(proxy_request *request) {
- if (!request) return;
-
- free(request);
-}
-
-
diff --git a/src/mod_proxy_core_backlog.h b/src/mod_proxy_core_backlog.h
deleted file mode 100644
index a59141f8..00000000
--- a/src/mod_proxy_core_backlog.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _MOD_PROXY_CORE_BACKLOG_H_
-#define _MOD_PROXY_CORE_BACKLOG_H_
-
-#include <sys/types.h>
-#ifndef _WIN32
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif
-
-typedef struct _proxy_request {
- void *con; /* a pointer to the client-connection, (type: connection) */
-
- time_t added_ts; /* when was the entry added (for timeout handling) */
-
- struct _proxy_request *next;
-} proxy_request;
-
-/**
- * a we can't get a connection from the pool, queue the request in the
- * request queue (FIFO)
- *
- * - the queue is infinite
- * - entries are removed after a timeout (status 504)
- */
-typedef struct {
- proxy_request *first; /* pull() does q->first = q->first->next */
- proxy_request *last; /* push() does q->last = r */
-
- size_t length;
-} proxy_backlog;
-
-proxy_backlog *proxy_backlog_init(void);
-void proxy_backlog_free(proxy_backlog *backlog);
-
-/**
- * append a request to the end
- *
- * @return 0 in success, -1 if full
- */
-int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
-
-/**
- * remove the first request from the backlog
- *
- * @return NULL if backlog is empty, the request otherwise
- */
-proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
-/**
- * remove the request with the connection 'con' from the backlog
- *
- * @return -1 if not found, 0 otherwise
- */
-int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
-
-proxy_request *proxy_request_init(void);
-void proxy_request_free(proxy_request *req);
-
-#endif
-
-
diff --git a/src/mod_proxy_core_pool.c b/src/mod_proxy_core_pool.c
deleted file mode 100644
index 65606fa1..00000000
--- a/src/mod_proxy_core_pool.c
+++ /dev/null
@@ -1,141 +0,0 @@
-
-#include <stdlib.h>
-
-#include "array-static.h"
-#include "sys-files.h"
-#include "log.h"
-#include "mod_proxy_core_pool.h"
-
-proxy_connection * proxy_connection_init(void) {
- proxy_connection *con;
-
- con = calloc(1, sizeof(*con));
-
- con->sock = iosocket_init();
-
- con->send = chunkqueue_init();
- con->recv = chunkqueue_init();
-
- return con;
-}
-
-void proxy_connection_free(proxy_connection *con) {
- if (!con) return;
-
- con->address->used--;
-
- iosocket_free(con->sock);
-
- chunkqueue_free(con->send);
- chunkqueue_free(con->recv);
-
- free(con);
-}
-
-proxy_connection_pool *proxy_connection_pool_init(void) {
- proxy_connection_pool *pool;
-
- pool = calloc(1, sizeof(*pool));
-
- /* default: max parallel connections to the backend
- *
- * this should match max-procs if we manage the procs ourself
- */
-
- pool->max_size = 1;
-
- return pool;
-}
-
-void proxy_connection_pool_free(proxy_connection_pool *pool) {
- size_t i;
-
- if (!pool) return;
-
- for (i = 0; i < pool->used; i++) {
- proxy_connection_free(pool->ptr[i]);
- }
-
- if (pool->size) free(pool->ptr);
-
- free(pool);
-}
-
-static void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
- ARRAY_STATIC_PREPARE_APPEND(pool);
-
- pool->ptr[pool->used++] = c;
-}
-
-/**
- * remove the connection from the pool
- *
- * usually called on conn-shutdown
- */
-int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
- size_t i;
-
- if (pool->used == 0) return -1; /* empty */
-
- for (i = 0; i < pool->used; i++) {
- if (pool->ptr[i] == c) {
- break;
- }
- }
-
- if (i == pool->used) return -1; /* not found */
-
- /**
- * move all elements one to the left
- *
- * if the last element is going to be removed, skip the loop
- */
- for (; i < pool->used - 1; i++) {
- pool->ptr[i] = pool->ptr[i + 1];
- }
-
- pool->used--;
-
- return 0;
-}
-
-proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
- proxy_connection *proxy_con = NULL;
- size_t i;
-
- /* search for a idling proxy connection with the given address */
- for (i = 0; i < pool->used; i++) {
- proxy_con = pool->ptr[i];
-
- if (proxy_con->address == address &&
- proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
- break;
- }
- }
-
- if (i == pool->used) {
- /* no idling connection found
- *
- * check if we can open another connection to this address
- */
-
- if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
-
- proxy_con = proxy_connection_init();
-
- proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
- proxy_con->address = address;
-
- proxy_connection_pool_add_connection(pool, proxy_con);
- } else {
- proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
- }
-
- /* inc. the use-counter of the address */
- proxy_con->address->used++;
-
- *rcon = proxy_con;
-
- return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
-}
-
diff --git a/src/mod_proxy_core_pool.h b/src/mod_proxy_core_pool.h
deleted file mode 100644
index 62040d16..00000000
--- a/src/mod_proxy_core_pool.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef _MOD_PROXY_CORE_POOL_H_
-#define _MOD_PROXY_CORE_POOL_H_
-
-#ifndef _WIN32
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif
-
-#include "iosocket.h"
-#include "array-static.h"
-#include "mod_proxy_core_address.h"
-#include "chunk.h"
-
-typedef enum {
- PROXY_CONNECTION_STATE_UNSET,
- PROXY_CONNECTION_STATE_CONNECTING,
- PROXY_CONNECTION_STATE_CONNECTED,
- PROXY_CONNECTION_STATE_IDLE,
- PROXY_CONNECTION_STATE_CLOSED,
-} proxy_connection_state_t;
-
-/**
- * a connection to a proxy backend
- *
- * the connection is independent of the incoming request to allow keep-alive
- */
-typedef struct {
- iosocket *sock;
-
- unsigned short request_count; /* used for max-keep-alive-requests */
- time_t last_read; /* timeout handling for keep-alive connections */
- time_t last_write;
-
- proxy_address *address; /* the struct sock_addr for the sock */
-
- struct proxy_protocol *protocol; /* protocol handler */
- void *protocol_data; /** protocol handler's state data for parsing response from backend. */
-
- chunkqueue *send; /* encoded stream data that needs to be send to backend server. */
- chunkqueue *recv; /* encoded stream data received form the backend that needs to be decoded. */
-
- proxy_connection_state_t state;
- time_t state_ts;
-
- void *proxy_sess; /** we are used by this proxy session right now */
-} proxy_connection;
-
-ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
-
-typedef enum {
- PROXY_CONNECTIONPOOL_UNSET,
- PROXY_CONNECTIONPOOL_FULL,
- PROXY_CONNECTIONPOOL_GOT_CONNECTION,
-} proxy_connection_pool_t;
-
-proxy_connection_pool *proxy_connection_pool_init(void);
-void proxy_connection_pool_free(proxy_connection_pool *pool);
-
-proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
-int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
-
-proxy_connection * proxy_connection_init(void);
-void proxy_connection_free(proxy_connection *pool);
-
-#endif
-
-
diff --git a/src/mod_proxy_core_protocol.c b/src/mod_proxy_core_protocol.c
deleted file mode 100644
index 66513df5..00000000
--- a/src/mod_proxy_core_protocol.c
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <stdlib.h>
-
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-
-static proxy_protocols *protocols = NULL;
-static buffer *protocol_names = NULL;
-
-proxy_protocol *proxy_protocol_init(void) {
- proxy_protocol *protocol;
-
- protocol = calloc(1, sizeof(*protocol));
-
- return protocol;
-}
-
-void proxy_protocol_free(proxy_protocol *protocol) {
- if (!protocol) return;
-
- buffer_free(protocol->name);
-
- free(protocol);
-}
-
-void proxy_protocols_init(void) {
- if(protocols) return;
- protocols = calloc(1, sizeof(*protocols));
- protocol_names = buffer_init();
-}
-
-void proxy_protocols_free(void) {
- if(!protocols) return;
- ARRAY_STATIC_FREE(protocols, proxy_protocol, element, proxy_protocol_free(element));
-
- free(protocols);
- buffer_free(protocol_names);
-}
-
-void proxy_protocols_register(proxy_protocol *protocol) {
- if(!protocols) return;
- ARRAY_STATIC_PREPARE_APPEND(protocols);
-
- protocols->ptr[protocols->used++] = protocol;
-
- /* append protocol name to list of names. */
- if(!buffer_is_empty(protocol_names)) {
- buffer_append_string_len(protocol_names, CONST_STR_LEN(", '"));
- } else {
- buffer_append_string_len(protocol_names, CONST_STR_LEN("'"));
- }
- buffer_append_string(protocol_names, BUF_STR(protocol->name));
- buffer_append_string_len(protocol_names, CONST_STR_LEN("'"));
-}
-
-proxy_protocol *proxy_get_protocol(buffer *name) {
- if(!protocols) return NULL;
-
- FOREACH(protocols, proxy_protocol, element, if(buffer_is_equal(element->name,name)) return element; );
-
- return NULL;
-}
-
-const char *proxy_available_protocols() {
- return BUF_STR(protocol_names);
-}
-
diff --git a/src/mod_proxy_core_protocol.h b/src/mod_proxy_core_protocol.h
deleted file mode 100644
index e846089f..00000000
--- a/src/mod_proxy_core_protocol.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _MOD_PROXY_CORE_PROTOCOL_H_
-#define _MOD_PROXY_CORE_PROTOCOL_H_
-
-#include "base.h"
-#include "array-static.h"
-#include "buffer.h"
-
-#define PROXY_CONNECTION_FUNC(x) \
- static int x(server *srv, proxy_connection *proxy_con)
-
-#define PROXY_STREAM_DECODER_FUNC(x) \
- static handler_t x(server *srv, proxy_session *sess, chunkqueue *out)
-
-#define PROXY_STREAM_ENCODER_FUNC(x) \
- static handler_t x(server *srv, proxy_session *sess, chunkqueue *in)
-
-typedef struct proxy_protocol {
- buffer *name;
-
- int (*proxy_stream_init) (server *srv, proxy_connection *proxy_con);
- int (*proxy_stream_cleanup) (server *srv, proxy_connection *proxy_con);
- handler_t (*proxy_stream_decoder) (server *srv, proxy_session *sess, chunkqueue *out);
- handler_t (*proxy_stream_encoder) (server *srv, proxy_session *sess, chunkqueue *in);
- handler_t (*proxy_encode_request_headers) (server *srv, proxy_session *sess, chunkqueue *in);
-
-} proxy_protocol;
-
-ARRAY_STATIC_DEF(proxy_protocols, proxy_protocol, );
-
-proxy_protocol *proxy_protocol_init(void);
-void proxy_protocol_free(proxy_protocol *protocol);
-
-void proxy_protocols_init(void);
-void proxy_protocols_free(void);
-void proxy_protocols_register(proxy_protocol *protocol);
-proxy_protocol *proxy_get_protocol(buffer *name);
-const char *proxy_available_protocols(void);
-
-#endif
-
diff --git a/src/mod_proxy_core_rewrites.c b/src/mod_proxy_core_rewrites.c
deleted file mode 100644
index 234f8068..00000000
--- a/src/mod_proxy_core_rewrites.c
+++ /dev/null
@@ -1,127 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "mod_proxy_core_rewrites.h"
-#include "log.h"
-
-proxy_rewrite *proxy_rewrite_init(void) {
- STRUCT_INIT(proxy_rewrite, rewrite);
-
- rewrite->header = buffer_init();
- rewrite->match = buffer_init();
- rewrite->replace = buffer_init();
-
- return rewrite;
-
-}
-void proxy_rewrite_free(proxy_rewrite *rewrite) {
- if (!rewrite) return;
-#ifdef HAVE_PCRE_H
- if (rewrite->regex) pcre_free(rewrite->regex);
-#endif
-
- buffer_free(rewrite->header);
- buffer_free(rewrite->match);
- buffer_free(rewrite->replace);
-
- free(rewrite);
-}
-
-int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
- const char *errptr;
- int erroff;
-
-#ifdef HAVE_PCRE_H
- if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
- 0, &errptr, &erroff, NULL))) {
-
- TRACE("regex compilation for %s failed at %s", SAFE_BUF_STR(regex), errptr);
-
- return -1;
- }
-#endif
-
- return 0;
-}
-
-
-proxy_rewrites *proxy_rewrites_init(void) {
- STRUCT_INIT(proxy_rewrites, rewrites);
-
- return rewrites;
-}
-
-void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
- ARRAY_STATIC_PREPARE_APPEND(rewrites);
-
- rewrites->ptr[rewrites->used++] = rewrite;
-}
-
-void proxy_rewrites_free(proxy_rewrites *rewrites) {
- if (!rewrites) return;
-
- ARRAY_STATIC_FREE(rewrites, proxy_rewrite, rewrite, proxy_rewrite_free(rewrite));
-
- free(rewrites);
-}
-
-int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
-#ifdef HAVE_PCRE_H
- const char *pattern = replace->ptr;
- size_t pattern_len = replace->used - 1;
-
-# define N 10
- int ovec[N * 3];
- int n;
-
- if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
- if (n != PCRE_ERROR_NOMATCH) {
- return n;
- }
- } else {
- const char **list;
- size_t start, end;
- size_t k;
-
- /* it matched */
- pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
-
- /* search for $[0-9] */
-
- buffer_reset(result);
-
- start = 0; end = pattern_len;
- for (k = 0; k < pattern_len; k++) {
- if ((pattern[k] == '$') &&
- isdigit((unsigned char)pattern[k + 1])) {
- /* got one */
-
- size_t num = pattern[k + 1] - '0';
-
- end = k;
-
- buffer_append_string_len(result, pattern + start, end - start);
-
- /* n is always > 0 */
- if (num < (size_t)n) {
- buffer_append_string(result, list[num]);
- }
-
- k++;
- start = k + 1;
- }
- }
-
- buffer_append_string_len(result, pattern + start, pattern_len - start);
-
- pcre_free(list);
- }
-
- return n;
-#else
- return -1;
-#endif
-}
-
-
diff --git a/src/mod_proxy_core_rewrites.h b/src/mod_proxy_core_rewrites.h
deleted file mode 100644
index bd7cc21a..00000000
--- a/src/mod_proxy_core_rewrites.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _MOD_PROXY_CORE_REWRITES_H_
-#define _MOD_PROXY_CORE_REWRITES_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_PCRE_H
-#include <pcre.h>
-#endif
-#include "array-static.h"
-#include "buffer.h"
-
-#ifndef HAVE_PCRE_H
-#define pcre void
-#endif
-
-typedef struct {
- buffer *header;
-
- pcre *regex; /* regex compiled from the <match> */
-
- buffer *match;
- buffer *replace;
-} proxy_rewrite;
-
-ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
-
-proxy_rewrite *proxy_rewrite_init(void);
-void proxy_rewrite_free(proxy_rewrite *rewrite);
-int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
-
-proxy_rewrites *proxy_rewrites_init(void);
-void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
-void proxy_rewrites_free(proxy_rewrites *rewrites);
-
-int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result);
-
-#endif
-
diff --git a/src/mod_redirect.c b/src/mod_redirect.c
deleted file mode 100644
index ed09f8dc..00000000
--- a/src/mod_redirect.c
+++ /dev/null
@@ -1,229 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-#include "response.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-typedef struct {
- pcre_keyvalue_buffer *redirect;
- data_config *context; /* to which apply me */
-
- unsigned short redirect_code;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
- buffer *match_buf;
- buffer *location;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-INIT_FUNC(mod_redirect_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->match_buf = buffer_init();
- p->location = buffer_init();
-
- return p;
-}
-
-FREE_FUNC(mod_redirect_free) {
- plugin_data *p = p_d;
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- pcre_keyvalue_buffer_free(s->redirect);
-
- free(s);
- }
- free(p->config_storage);
- }
-
-
- buffer_free(p->match_buf);
- buffer_free(p->location);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
- plugin_data *p = p_d;
- data_unset *du;
- 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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- size_t j;
- array *ca;
- data_array *da = NULL;
-
- s = calloc(1, sizeof(plugin_config));
- s->redirect = pcre_keyvalue_buffer_init();
-
- cv[0].destination = s->redirect;
- cv[1].destination = &(s->redirect_code);
-
- p->config_storage[i] = s;
- ca = ((data_config *)srv->config_context->data[i])->value;
-
- if (0 != config_insert_values_global(srv, ca, cv)) {
- return HANDLER_ERROR;
- }
-
- if (NULL == (du = array_get_element(ca, CONST_STR_LEN("url.redirect")))) {
- /* no url.redirect defined */
- continue;
- }
-
- if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "unexpected type for key: ", "url.redirect", "array of strings");
-
- return HANDLER_ERROR;
- }
-
- da = (data_array *)du;
-
- for (j = 0; j < da->value->used; j++) {
- if (da->value->data[j]->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ",
- "url.redirect",
- "[", da->value->data[j]->key, "](string)");
-
- return HANDLER_ERROR;
- }
-
- if (0 != pcre_keyvalue_buffer_append(s->redirect,
- ((data_string *)(da->value->data[j]))->key->ptr,
- ((data_string *)(da->value->data[j]))->value->ptr)) {
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "pcre-compile failed for", da->value->data[j]->key);
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-#ifdef HAVE_PCRE_H
-static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(redirect);
- PATCH_OPTION(redirect_code);
-
- /* 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.redirect"))) {
- PATCH_OPTION(redirect);
- p->conf.context = dc;
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.redirect-code"))) {
- PATCH_OPTION(redirect_code);
- }
- }
- }
-
- return 0;
-}
-#endif
-static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
-#ifdef HAVE_PCRE_H
- plugin_data *p = p_data;
- int i;
-
- /*
- * REWRITE URL
- *
- * e.g. redirect /base/ to /index.php?section=base
- *
- */
-
- mod_redirect_patch_connection(srv, con, p);
-
- buffer_copy_string_buffer(p->match_buf, con->request.uri);
- i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
-
- if (i >= 0) {
- response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
-
- con->http_status = p->conf.redirect_code > 99 && p->conf.redirect_code < 1000 ? p->conf.redirect_code : 301;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
- }
- else if (i != PCRE_ERROR_NOMATCH) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "execution error while matching", i);
- }
-#undef N
-
-#else
- UNUSED(srv);
- UNUSED(con);
- UNUSED(p_data);
-#endif
-
- return HANDLER_GO_ON;
-}
-
-
-LI_EXPORT int mod_redirect_plugin_init(plugin *p);
-LI_EXPORT int mod_redirect_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("redirect");
-
- p->init = mod_redirect_init;
- p->handle_uri_clean = mod_redirect_uri_handler;
- p->set_defaults = mod_redirect_set_defaults;
- p->cleanup = mod_redirect_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
deleted file mode 100644
index 94609300..00000000
--- a/src/mod_rewrite.c
+++ /dev/null
@@ -1,337 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-typedef struct {
- pcre_keyvalue_buffer *rewrite;
- buffer *once;
- data_config *context; /* to which apply me */
-} plugin_config;
-
-typedef struct {
- enum { REWRITE_STATE_UNSET, REWRITE_STATE_FINISHED} state;
- int loops;
-} handler_ctx;
-
-typedef struct {
- PLUGIN_DATA;
- buffer *match_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-static handler_ctx * handler_ctx_init() {
- 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) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->match_buf = buffer_init();
-
- return p;
-}
-
-FREE_FUNC(mod_rewrite_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->match_buf);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- pcre_keyvalue_buffer_free(s->rewrite);
- buffer_free(s->once);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-static handler_t parse_config_entry(server *UNUSED_PARAM(srv), plugin_config *s, array *ca, const char *option, size_t option_len, int once) {
- data_unset *du;
-
- if (NULL != (du = array_get_element(ca, option, option_len))) {
- data_array *da = (data_array *)du;
- size_t j;
-
- if (du->type != TYPE_ARRAY) {
- ERROR("unexpected type (%d) for key %s, expected 'array of strings'",
- du->type, option);
-
- return HANDLER_ERROR;
- }
-
- da = (data_array *)du;
-
- for (j = 0; j < da->value->used; j++) {
- if (da->value->data[j]->type != TYPE_STRING) {
- ERROR("unexpected type (%d) for value of %s[%s], expected 'string'",
- da->value->data[j]->type, option,
- SAFE_BUF_STR(da->value->data[j]->key));
-
- return HANDLER_ERROR;
- }
-
- if (0 != pcre_keyvalue_buffer_append(s->rewrite,
- ((data_string *)(da->value->data[j]))->key->ptr,
- ((data_string *)(da->value->data[j]))->value->ptr)) {
-#ifdef HAVE_PCRE_H
- ERROR("pcre-compile failed for: %s", SAFE_BUF_STR(da->value->data[j]->key));
-#else
- ERROR("pcre support is missing, please install libpcre and the headers%s", "");
-#endif
- }
-
- if (once) {
- buffer_append_string_len(s->once, CONST_STR_LEN("1"));
- } else {
- buffer_append_string_len(s->once, CONST_STR_LEN("0"));
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
- plugin_data *p = p_d;
- 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 */
-
- /* old names, still supported
- *
- * url.rewrite remapped to url.rewrite-once
- * url.rewrite-final is url.rewrite-once
- *
- */
- { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- /* 0 */
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
- array *ca;
-
- s = calloc(1, sizeof(plugin_config));
- s->rewrite = pcre_keyvalue_buffer_init();
- s->once = buffer_init();
-
- p->config_storage[i] = s;
- ca = ((data_config *)srv->config_context->data[i])->value;
-
- if (0 != config_insert_values_global(srv, ca, cv)) {
- return HANDLER_ERROR;
- }
-
- if (HANDLER_GO_ON != parse_config_entry(srv, s, ca, CONST_STR_LEN("url.rewrite-once"), 1)) return HANDLER_ERROR;
- if (HANDLER_GO_ON != parse_config_entry(srv, s, ca, CONST_STR_LEN("url.rewrite-final"), 1)) return HANDLER_ERROR;
- if (HANDLER_GO_ON != parse_config_entry(srv, s, ca, CONST_STR_LEN("url.rewrite"), 1)) return HANDLER_ERROR;
- if (HANDLER_GO_ON != parse_config_entry(srv, s, ca, CONST_STR_LEN("url.rewrite-repeat"), 0)) return HANDLER_ERROR;
- }
-
- return HANDLER_GO_ON;
-}
-#ifdef HAVE_PCRE_H
-static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
- p->conf.rewrite = s->rewrite;
- p->conf.once = s->once;
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- if (COMP_HTTP_URL == dc->comp) continue;
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
- p->conf.rewrite = s->rewrite;
- p->conf.once = s->once;
- p->conf.context = dc;
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
- p->conf.rewrite = s->rewrite;
- p->conf.once = s->once;
- p->conf.context = dc;
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
- p->conf.rewrite = s->rewrite;
- p->conf.once = s->once;
- p->conf.context = dc;
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
- p->conf.rewrite = s->rewrite;
- p->conf.once = s->once;
- p->conf.context = dc;
- }
- }
- }
-
- return 0;
-}
-#endif
-URIHANDLER_FUNC(mod_rewrite_con_reset) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (con->plugin_ctx[p->id]) {
- handler_ctx_free(con->plugin_ctx[p->id]);
- con->plugin_ctx[p->id] = NULL;
- }
-
- return HANDLER_GO_ON;
-}
-
-URIHANDLER_FUNC(mod_rewrite_uri_handler) {
-#ifdef HAVE_PCRE_H
- plugin_data *p = p_d;
- int i;
- handler_ctx *hctx = NULL;
-
- /*
- * REWRITE URL
- *
- * e.g. rewrite /base/ to /index.php?section=base
- *
- */
-
- if (con->plugin_ctx[p->id]) {
- hctx = con->plugin_ctx[p->id];
-
- if (hctx->loops++ > 100) {
- ERROR("ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request after %d loops at %s",
- hctx->loops, SAFE_BUF_STR(con->request.uri));
-
- con->http_status = 500;
-
- return HANDLER_FINISHED;
- }
-
- if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
- }
-
- mod_rewrite_patch_connection(srv, con, p);
-
- if (!p->conf.rewrite) return HANDLER_GO_ON;
-
- buffer_copy_string_buffer(p->match_buf, con->request.uri);
- i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
-
- if (i >= 0) {
- if (!hctx) {
- hctx = handler_ctx_init();
-
- con->plugin_ctx[p->id] = hctx;
- }
-
- if (p->conf.once->ptr[i] == '1')
- hctx->state = REWRITE_STATE_FINISHED;
-
- /* looks like we finished the rewrite
- *
- * start the uri-splitting again
- * */
-
- if (con->request.uri->used == 0 ||
- con->request.uri->ptr[0] != '/') {
- con->http_status = 500;
-
- ERROR("url.rewrite contains a regex for '%s' which leads to a URI without a leading slash: %s",
- SAFE_BUF_STR(p->match_buf), SAFE_BUF_STR(con->request.uri));
-
- return HANDLER_FINISHED;
- }
-
- return HANDLER_COMEBACK;
- } else if (i != PCRE_ERROR_NOMATCH) {
- ERROR("execution error while matching '%s' against '%s': %d",
- SAFE_BUF_STR(p->match_buf), SAFE_BUF_STR(con->request.uri), i);
- con->http_status = 500;
-
- return HANDLER_FINISHED;
- }
-#undef N
-
-#else
- UNUSED(srv);
- UNUSED(con);
- UNUSED(p_d);
-#endif
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_rewrite_plugin_init(plugin *p);
-LI_EXPORT 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->set_defaults = mod_rewrite_set_defaults;
- p->cleanup = mod_rewrite_free;
- p->connection_reset = mod_rewrite_con_reset;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
deleted file mode 100644
index f7e4fad1..00000000
--- a/src/mod_rrdtool.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <sys/types.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
-#include "server.h"
-#include "connections.h"
-#include "response.h"
-#include "connections.h"
-#include "log.h"
-
-#include "plugin.h"
-#ifdef HAVE_FORK
-/* no need for waitpid if we don't have fork */
-#include <sys/wait.h>
-#endif
-
-#include "sys-files.h"
-#include "sys-process.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;
-
- int rrdtool_running;
-
- plugin_config **config_storage;
- plugin_config conf;
-} plugin_data;
-
-INIT_FUNC(mod_rrd_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->resp = buffer_init();
- p->cmd = buffer_init();
-
- return p;
-}
-
-FREE_FUNC(mod_rrd_free) {
- plugin_data *p = p_d;
- size_t i;
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- buffer_free(s->path_rrdtool_bin);
- buffer_free(s->path_rrd);
-
- free(s);
- }
- }
- buffer_free(p->cmd);
- buffer_free(p->resp);
-
- free(p->config_storage);
-
- if (p->rrdtool_pid) {
- int status;
- close(p->read_fd);
- close(p->write_fd);
-#ifdef HAVE_FORK
- /* collect status */
- waitpid(p->rrdtool_pid, &status, 0);
-#endif
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-static int mod_rrd_create_pipe(server *srv, plugin_data *p) {
-#ifdef HAVE_FORK
- pid_t pid;
-
- int to_rrdtool_fds[2];
- int from_rrdtool_fds[2];
- 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;
- }
-
- /* fork, execve */
- switch (pid = fork()) {
- case 0: {
- /* child */
- char **args;
- int argc;
- int i = 0;
- char *dash = "-";
-
- /* move stdout to from_rrdtool_fd[1] */
- dup2(from_rrdtool_fds[1], STDOUT_FILENO);
- close(from_rrdtool_fds[1]);
- /* not needed */
- close(from_rrdtool_fds[0]);
-
- /* move the stdin to to_rrdtool_fd[0] */
- dup2(to_rrdtool_fds[0], STDIN_FILENO);
- close(to_rrdtool_fds[0]);
- /* not needed */
- close(to_rrdtool_fds[1]);
-
- /* set up args */
- argc = 3;
- args = malloc(sizeof(*args) * argc);
- i = 0;
-
- args[i++] = p->conf.path_rrdtool_bin->ptr;
- args[i++] = dash;
- args[i++] = NULL;
-
- /* we don't need the client socket */
- for (i = 3; i < 256; i++) {
- close(i);
- }
-
- /* exec the cgi */
- execv(args[0], args);
-
- /* */
- SEGFAULT("spawing '%s' failed: %s", args[0], strerror(errno));
-
- break;
- }
- case -1:
- /* error */
- ERROR("fork failed: %s", strerror(errno));
- break;
- default: {
- /* father */
-
- close(from_rrdtool_fds[1]);
- close(to_rrdtool_fds[0]);
-
- /* register PID and wait for them asyncronously */
- p->write_fd = to_rrdtool_fds[1];
- p->read_fd = from_rrdtool_fds[0];
- p->rrdtool_pid = pid;
-
-#ifdef FD_CLOEXEC
- fcntl(p->write_fd, F_SETFD, FD_CLOEXEC);
- fcntl(p->read_fd, F_SETFD, FD_CLOEXEC);
-#endif
-
- break;
- }
- }
-
- return 0;
-#else
- return -1;
-#endif
-}
-
-/* read/write wrappers to catch EINTR */
-
-/* write to blocking socket; blocks until all data is sent, write returns 0 or an error (apart from EINTR) occurs. */
-static ssize_t safe_write(int fd, const void *buf, size_t count) {
- ssize_t res, sum = 0;
-
- for (;;) {
- res = write(fd, buf, count);
- if (res >= 0) {
- sum += res;
- /* do not try again if res == 0 */
- if (res == 0 || (size_t) res == count) return sum;
- count -= res;
- buf = (const char*) buf + res;
- continue;
- }
- switch (errno) {
- case EINTR:
- continue;
- default:
- return -1;
- }
- }
-}
-
-/* this assumes we get enough data on a successful read */
-static ssize_t safe_read(int fd, void *buf, size_t count) {
- ssize_t res;
-
- for (;;) {
- res = read(fd, buf, count);
- if (res >= 0) return res;
- switch (errno) {
- case EINTR:
- continue;
- default:
- return -1;
- }
- }
-}
-
-static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
- struct stat st;
- int r ;
-
- /* check if DB already exists */
- if (0 == stat(s->path_rrd->ptr, &st)) {
- /* check if it is plain file */
- if (!S_ISREG(st.st_mode)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "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 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "rrdtool-write: failed", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- buffer_prepare_copy(p->resp, 4096);
- if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "rrdtool-read: failed", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- p->resp->used = r;
-
- if (p->resp->ptr[0] != 'O' ||
- p->resp->ptr[1] != 'K') {
- log_error_write(srv, __FILE__, __LINE__, "sbb",
- "rrdtool-response:", p->cmd, p->resp);
-
- return HANDLER_ERROR;
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(path_rrdtool_bin);
- PATCH_OPTION(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_OPTION(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;
-}
-
-SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
- { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->path_rrdtool_bin = buffer_init();
- s->path_rrd = buffer_init();
- s->requests = 0;
- s->bytes_written = 0;
- s->bytes_read = 0;
-
- cv[0].destination = s->path_rrdtool_bin;
- cv[1].destination = s->path_rrd;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
- /* path_rrdtool_bin is a global option */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "rrdtool.binary can only be set as a global option.");
-
- return HANDLER_ERROR;
- }
-
- }
-
- p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
- p->rrdtool_running = 0;
-
- /* check for dir */
-
- if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "rrdtool.binary has to be set");
- return HANDLER_ERROR;
- }
-
- /* open the pipe to rrdtool */
- if (mod_rrd_create_pipe(srv, p)) {
- return HANDLER_ERROR;
- }
-
- p->rrdtool_running = 1;
-
- return HANDLER_GO_ON;
-}
-
-TRIGGER_FUNC(mod_rrd_trigger) {
- plugin_data *p = p_d;
- size_t i;
-
- if (!p->rrdtool_running) return HANDLER_GO_ON;
- if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
- int r;
-
- if (buffer_is_empty(s->path_rrd)) continue;
-
- /* write the data down every minute */
-
- if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
-
- buffer_copy_string_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_off_t(p->cmd, s->bytes_read);
- buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
- buffer_append_off_t(p->cmd, s->bytes_written);
- buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
- buffer_append_long(p->cmd, s->requests);
- buffer_append_string_len(p->cmd, CONST_STR_LEN("\n"));
-
- if (-1 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
- p->rrdtool_running = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "rrdtool-write: failed", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- buffer_prepare_copy(p->resp, 4096);
- if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) {
- p->rrdtool_running = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "rrdtool-read: failed", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- p->resp->used = r;
-
- if (p->resp->ptr[0] != 'O' ||
- p->resp->ptr[1] != 'K') {
- /* don't fail on this error if we just started (graceful restart, the old one might have just updated too) */
- if (!(strstr(p->resp->ptr, "(minimum one second step)") && (srv->cur_ts - srv->startup_ts < 3))) {
- p->rrdtool_running = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "sbb",
- "rrdtool-response:", p->cmd, p->resp);
-
- return HANDLER_ERROR;
- }
- }
- s->requests = 0;
- s->bytes_written = 0;
- s->bytes_read = 0;
- }
-
- return HANDLER_GO_ON;
-}
-
-REQUESTDONE_FUNC(mod_rrd_account) {
- plugin_data *p = p_d;
-
- mod_rrd_patch_connection(srv, con, p);
-
- *(p->conf.requests_ptr) += 1;
- *(p->conf.bytes_written_ptr) += con->bytes_written;
- *(p->conf.bytes_read_ptr) += con->bytes_read;
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_rrdtool_plugin_init(plugin *p);
-LI_EXPORT 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_response_done = mod_rrd_account;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
deleted file mode 100644
index a5d2b663..00000000
--- a/src/mod_secure_download.c
+++ /dev/null
@@ -1,351 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-
-typedef li_MD5_CTX MD5_CTX;
-#define MD5_Init li_MD5_Init
-#define MD5_Update li_MD5_Update
-#define MD5_Final li_MD5_Final
-
-#endif
-
-#define HASHLEN 16
-typedef unsigned char HASH[HASHLEN];
-#define HASHHEXLEN 32
-typedef char HASHHEX[HASHHEXLEN+1];
-#ifdef USE_OPENSSL
-#define IN const
-#else
-#define IN
-#endif
-#define OUT
-
-
-/* plugin config for all request/connections */
-
-typedef struct {
- buffer *doc_root;
- buffer *secret;
- buffer *uri_prefix;
-
- unsigned int timeout;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- buffer *md5;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-/* init the plugin data */
-INIT_FUNC(mod_secdownload_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->md5 = buffer_init();
-
- 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];
-
- buffer_free(s->secret);
- buffer_free(s->doc_root);
- buffer_free(s->uri_prefix);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->md5);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->secret = buffer_init();
- s->doc_root = buffer_init();
- s->uri_prefix = buffer_init();
- s->timeout = 60;
-
- cv[0].destination = s->secret;
- cv[1].destination = s->doc_root;
- cv[2].destination = s->uri_prefix;
- cv[3].destination = &(s->timeout);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * checks if the supplied string is a MD5 string
- *
- * @param str a possible MD5 string
- * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
- */
-
-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;
-}
-
-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_OPTION(secret);
- PATCH_OPTION(doc_root);
- PATCH_OPTION(uri_prefix);
- PATCH_OPTION(timeout);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
- PATCH_OPTION(secret);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
- PATCH_OPTION(doc_root);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
- PATCH_OPTION(uri_prefix);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
- PATCH_OPTION(timeout);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_secdownload_uri_handler) {
- plugin_data *p = p_d;
- MD5_CTX Md5Ctx;
- HASH HA1;
- const char *rel_uri, *ts_str, *md5_str;
- time_t ts = 0;
- size_t i;
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_secdownload_patch_connection(srv, con, p);
-
- if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
-
- if (buffer_is_empty(p->conf.secret)) {
- ERROR("secdownload.secret has to be set: %s", "");
-
- return HANDLER_ERROR;
- }
-
- if (buffer_is_empty(p->conf.doc_root)) {
- ERROR("secdownload.document-root has to be set: %s", "");
-
- return HANDLER_ERROR;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- handling %s in mod_secdownload", SAFE_BUF_STR(con->uri.path));
- }
-
- /*
- * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
- */
-
- if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) {
- if (con->conf.log_request_handling) {
- TRACE("prefix '%s' didn't matched the url: %s", SAFE_BUF_STR(p->conf.uri_prefix), SAFE_BUF_STR(con->uri.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
-
- if (!is_hex_len(md5_str, 32)) {
- if (con->conf.log_request_handling) {
- TRACE("expected a 32-char hex-val as md5-hash: %s", SAFE_BUF_STR(con->uri.path));
- }
-
- return HANDLER_GO_ON;
- }
- if (*(md5_str + 32) != '/') {
- if (con->conf.log_request_handling) {
- TRACE("missing a / after the md5-hash: %s", SAFE_BUF_STR(con->uri.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- ts_str = md5_str + 32 + 1;
-
- if (!is_hex_len(ts_str, 8)) {
- if (con->conf.log_request_handling) {
- TRACE("expected a 8-char hex-val after md5-hash: %s", SAFE_BUF_STR(con->uri.path));
- }
-
- return HANDLER_GO_ON;
- }
- if (*(ts_str + 8) != '/') {
- if (con->conf.log_request_handling) {
- TRACE("missing a / after the timestamp: %s", SAFE_BUF_STR(con->uri.path));
- }
-
- 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) ) {
- if (con->conf.log_request_handling) {
- TRACE("timestamp is too old: %ld, timeout: %d", (long int) ts, p->conf.timeout);
- }
-
- /* "Gone" as the url will never be valid again instead of "408 - Timeout" where the request may be repeated */
- con->http_status = 410;
-
- return HANDLER_FINISHED;
- }
-
- rel_uri = ts_str + 8;
-
- /* checking MD5
- *
- * <secret><rel-path><timestamp-hex>
- */
-
- buffer_copy_string_buffer(p->md5, p->conf.secret);
- buffer_append_string(p->md5, rel_uri);
- buffer_append_string_len(p->md5, ts_str, 8);
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
- MD5_Final(HA1, &Md5Ctx);
-
- buffer_copy_string_hex(p->md5, (char *)HA1, 16);
-
- if (0 != strncasecmp(md5_str, p->md5->ptr, 32)) {
- con->http_status = 403;
-
- TRACE("MD5 didn't matched: %s == %s", md5_str, SAFE_BUF_STR(p->md5));
-
- return HANDLER_FINISHED;
- }
-
- /* starting with the last / we should have relative-path to the docroot
- */
-
- buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
- buffer_copy_string(con->physical.rel_path, rel_uri);
- buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
- buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
-
- if (con->conf.log_request_handling) {
- TRACE("MD5 matched, timestamp is ok, sending %s", SAFE_BUF_STR(con->physical.path));
- }
-
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_secdownload_plugin_init(plugin *p);
-LI_EXPORT int mod_secdownload_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("secdownload");
-
- p->init = mod_secdownload_init;
- p->handle_physical = mod_secdownload_uri_handler;
- p->set_defaults = mod_secdownload_set_defaults;
- p->cleanup = mod_secdownload_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_setenv.c b/src/mod_setenv.c
deleted file mode 100644
index 026adb16..00000000
--- a/src/mod_setenv.c
+++ /dev/null
@@ -1,254 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "response.h"
-
-/* plugin config for all request/connections */
-
-typedef struct {
- int handled; /* make sure that we only apply the headers once */
-} handler_ctx;
-
-typedef struct {
- array *request_header;
- array *response_header;
-
- array *environment;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-static handler_ctx * handler_ctx_init() {
- 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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_setenv_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- array_free(s->request_header);
- array_free(s->response_header);
- array_free(s->environment);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->request_header = array_init();
- s->response_header = array_init();
- s->environment = array_init();
-
- cv[0].destination = s->request_header;
- cv[1].destination = s->response_header;
- cv[2].destination = s->environment;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(request_header);
- PATCH_OPTION(response_header);
- PATCH_OPTION(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_OPTION(request_header);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
- PATCH_OPTION(response_header);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
- PATCH_OPTION(environment);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_setenv_uri_handler) {
- plugin_data *p = p_d;
- size_t k;
- handler_ctx *hctx;
-
- mod_setenv_patch_connection(srv, con, p);
-
- if (p->conf.request_header->used == 0 &&
- p->conf.environment->used == 0 &&
- p->conf.response_header->used == 0) {
- return HANDLER_GO_ON;
- }
-
- 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;
-
- for (k = 0; k < p->conf.request_header->used; k++) {
- data_string *ds = (data_string *)p->conf.request_header->data[k];
- data_string *ds_dst;
-
- if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
- ds_dst = data_string_init();
- }
-
- buffer_copy_string_buffer(ds_dst->key, ds->key);
- buffer_copy_string_buffer(ds_dst->value, ds->value);
-
- array_insert_unique(con->request.headers, (data_unset *)ds_dst);
- }
-
- for (k = 0; k < p->conf.environment->used; k++) {
- data_string *ds = (data_string *)p->conf.environment->data[k];
- data_string *ds_dst;
-
- if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
- ds_dst = data_string_init();
- }
-
- buffer_copy_string_buffer(ds_dst->key, ds->key);
- buffer_copy_string_buffer(ds_dst->value, ds->value);
-
- array_insert_unique(con->environment, (data_unset *)ds_dst);
- }
-
- for (k = 0; k < p->conf.response_header->used; k++) {
- data_string *ds = (data_string *)p->conf.response_header->data[k];
-
- response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-REQUESTDONE_FUNC(mod_setenv_reset) {
- 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 */
-
-LI_EXPORT int mod_setenv_plugin_init(plugin *p);
-LI_EXPORT 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_start_backend = mod_setenv_uri_handler;
- 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/src/mod_simple_vhost.c b/src/mod_simple_vhost.c
deleted file mode 100644
index eb100e1b..00000000
--- a/src/mod_simple_vhost.c
+++ /dev/null
@@ -1,282 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "stat_cache.h"
-
-#include "plugin.h"
-
-#include "sys-files.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->doc_root = buffer_init();
-
- return p;
-}
-
-FREE_FUNC(mod_simple_vhost_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- buffer_free(s->document_root);
- buffer_free(s->default_host);
- buffer_free(s->server_root);
-
- buffer_free(s->docroot_cache_key);
- buffer_free(s->docroot_cache_value);
- buffer_free(s->docroot_cache_servername);
-
- free(s);
- }
-
- free(p->config_storage);
- }
-
- buffer_free(p->doc_root);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
-
- s->server_root = buffer_init();
- s->default_host = buffer_init();
- s->document_root = buffer_init();
-
- s->docroot_cache_key = buffer_init();
- s->docroot_cache_value = buffer_init();
- s->docroot_cache_servername = buffer_init();
-
- s->debug = 0;
-
- cv[0].destination = s->server_root;
- cv[1].destination = s->default_host;
- cv[2].destination = s->document_root;
- cv[3].destination = &(s->debug);
-
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
- stat_cache_entry *sce = NULL;
-
- buffer_prepare_copy(out, 128);
-
- if (p->conf.server_root->used) {
- buffer_copy_string_buffer(out, p->conf.server_root);
-
- if (host->used) {
- /* a hostname has to start with a alpha-numerical character
- * and must not contain a slash "/"
- */
- char *dp;
-
- PATHNAME_APPEND_SLASH(out);
-
- if (NULL == (dp = strchr(host->ptr, ':'))) {
- buffer_append_string_buffer(out, host);
- } else {
- buffer_append_string_len(out, host->ptr, dp - host->ptr);
- }
- }
- PATHNAME_APPEND_SLASH(out);
-
- if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
- buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
- } else {
- buffer_append_string_buffer(out, p->conf.document_root);
- PATHNAME_APPEND_SLASH(out);
- }
- } else {
- buffer_copy_string_buffer(out, con->conf.document_root);
- PATHNAME_APPEND_SLASH(out);
- }
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), out);
- }
- return -1;
- } else if (!S_ISDIR(sce->st.st_mode)) {
- return -1;
- }
-
- return 0;
-}
-
-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_OPTION(server_root);
- PATCH_OPTION(default_host);
- PATCH_OPTION(document_root);
-
- PATCH_OPTION(docroot_cache_key);
- PATCH_OPTION(docroot_cache_value);
- PATCH_OPTION(docroot_cache_servername);
-
- PATCH_OPTION(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_OPTION(server_root);
- PATCH_OPTION(docroot_cache_key);
- PATCH_OPTION(docroot_cache_value);
- PATCH_OPTION(docroot_cache_servername);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
- PATCH_OPTION(default_host);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
- PATCH_OPTION(document_root);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
- PATCH_OPTION(debug);
- }
- }
- }
-
- return 0;
-}
-
-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);
-
- if (p->conf.docroot_cache_key->used &&
- con->uri.authority->used &&
- buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
- /* cache hit */
- buffer_copy_string_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
- buffer_copy_string_buffer(con->server_name, p->conf.docroot_cache_servername);
- } else {
- /* build document-root */
- if ((con->uri.authority->used == 0) ||
- build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
- /* not found, fallback the default-host */
- if (build_doc_root(srv, con, p,
- p->doc_root,
- p->conf.default_host)) {
- return HANDLER_GO_ON;
- } else {
- buffer_copy_string_buffer(con->server_name, p->conf.default_host);
- }
- } else {
- buffer_copy_string_buffer(con->server_name, con->uri.authority);
- }
-
- /* copy to cache */
- buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
- buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
- buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
-
- buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
- }
-
- return HANDLER_GO_ON;
-}
-
-
-LI_EXPORT int mod_simple_vhost_plugin_init(plugin *p);
-LI_EXPORT int mod_simple_vhost_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("simple_vhost");
-
- p->init = mod_simple_vhost_init;
- p->set_defaults = mod_simple_vhost_set_defaults;
- p->handle_docroot = mod_simple_vhost_docroot;
- p->cleanup = mod_simple_vhost_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_skeleton.c b/src/mod_skeleton.c
deleted file mode 100644
index d79b08e9..00000000
--- a/src/mod_skeleton.c
+++ /dev/null
@@ -1,207 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/**
- * this is a skeleton for a lighttpd plugin
- *
- * just replaces every occurance of 'skeleton' by your plugin name
- *
- * e.g. in vim:
- *
- * :%s/skeleton/myhandler/
- *
- */
-
-
-
-/* plugin config for all request/connections */
-
-typedef struct {
- array *match;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- buffer *match_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-typedef struct {
- size_t foo;
-} handler_ctx;
-
-static handler_ctx * handler_ctx_init() {
- handler_ctx * hctx;
-
- hctx = calloc(1, sizeof(*hctx));
-
- return hctx;
-}
-
-static void handler_ctx_free(handler_ctx *hctx) {
-
- free(hctx);
-}
-
-/* init the plugin data */
-INIT_FUNC(mod_skeleton_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->match_buf = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_skeleton_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- array_free(s->match);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->match_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->match = array_init();
-
- cv[0].destination = s->match;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(match);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
- PATCH_OPTION(match);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_skeleton_uri_handler) {
- plugin_data *p = p_d;
- int s_len;
- size_t k, i;
-
- UNUSED(srv);
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_skeleton_patch_connection(srv, con, p);
-
- s_len = con->uri.path->used - 1;
-
- for (k = 0; k < p->conf.match->used; k++) {
- data_string *ds = (data_string *)p->conf.match->data[k];
- int ct_len = ds->value->used - 1;
-
- if (ct_len > s_len) continue;
- if (ds->value->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
-
- return HANDLER_FINISHED;
- }
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-int mod_skeleton_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("skeleton");
-
- p->init = mod_skeleton_init;
- p->handle_uri_clean = mod_skeleton_uri_handler;
- p->set_defaults = mod_skeleton_set_defaults;
- p->cleanup = mod_skeleton_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_sql_vhost_core.c b/src/mod_sql_vhost_core.c
deleted file mode 100644
index 8cef1c8b..00000000
--- a/src/mod_sql_vhost_core.c
+++ /dev/null
@@ -1,384 +0,0 @@
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "plugin.h"
-#include "log.h"
-#include "sys-files.h"
-
-#include "stat_cache.h"
-
-#include "mod_sql_vhost_core.h"
-
-#define plugin_data mod_sql_vhost_core_plugin_data
-#define plugin_config mod_sql_vhost_core_plugin_config
-
-typedef struct {
- buffer *docroot;
- time_t added_ts;
-
- time_t ttl;
-} cached_vhost;
-
-/* init the plugin data */
-INIT_FUNC(mod_sql_vhost_core_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->docroot = buffer_init();
- p->host = buffer_init();
-
- return p;
-}
-
-/* cleanup the plugin data */
-SERVER_FUNC(mod_sql_vhost_core_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;
-
- buffer_free(s->db);
- buffer_free(s->user);
- buffer_free(s->pass);
- buffer_free(s->sock);
- buffer_free(s->backend);
- buffer_free(s->hostname);
- buffer_free(s->select_vhost);
-#ifdef HAVE_GLIB_H
- g_hash_table_destroy(s->vhost_table);
-#endif
-
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->docroot);
- buffer_free(p->host);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-#ifdef HAVE_GLIB_H
-#if 0
-static cached_vhost *cached_vhost_init(void) {
- cached_vhost *vhost;
-
- vhost = g_new0(cached_vhost, 1);
-
- return vhost;
-}
-#endif
-
-static void cached_vhost_free(cached_vhost *vhost) {
- if (!vhost) return;
-
- if (vhost->docroot) buffer_free(vhost->docroot);
-
- g_free(vhost);
-}
-
-static void cached_vhost_free_hash(gpointer vhost) {
- cached_vhost_free(vhost);
-}
-
-static uint buffer_hash(gconstpointer key) {
- buffer *b = (buffer *)key;
-
- return g_str_hash(b->ptr);
-}
-
-static gboolean buffer_hash_equal(gconstpointer _a, gconstpointer _b) {
- buffer *a = (buffer *)_a;
- buffer *b = (buffer *)_b;
-
- return buffer_is_equal(a, b);
-}
-
-static void buffer_hash_free(gpointer d) {
- buffer *b = d;
-
- buffer_free(b);
-}
-#endif
-
-#define CONFIG_CACHE_TTL "sql-vhost.cache-ttl"
-#define CONFIG_DEBUG "sql-vhost.debug"
-
-/* set configuration values */
-SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
- plugin_data *p = p_d;
-
- size_t i = 0;
-
- config_values_t cv[] = {
- { "sql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
- { "sql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
- { "sql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
- { "sql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
- { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
- { "sql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
- { "sql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
- { "sql-vhost.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
-
- /* backward compat */
- { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
- { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
- { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
- { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
- { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
- { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
- { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
-
- { CONFIG_CACHE_TTL, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 15 * 60 */
- { CONFIG_DEBUG, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 15 * 60 */
-
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->db = buffer_init();
- s->user = buffer_init();
- s->pass = buffer_init();
- s->sock = buffer_init();
- s->hostname = buffer_init();
- s->backend = buffer_init();
- s->port = 0; /* default port for mysql */
- s->select_vhost = buffer_init();
- s->backend_data = NULL;
-#ifdef HAVE_GLIB_H
- s->vhost_table = g_hash_table_new_full(buffer_hash, buffer_hash_equal, buffer_hash_free, cached_vhost_free_hash);
-#endif
- s->cache_ttl = 60;
- s->debug = 0;
-
- cv[0].destination = s->db;
- cv[1].destination = s->user;
- cv[2].destination = s->pass;
- cv[3].destination = s->sock;
- cv[4].destination = s->select_vhost;
- cv[5].destination = s->hostname;
- cv[6].destination = &(s->port);
- cv[7].destination = s->backend;
-
- /* backend compat */
- cv[8].destination = cv[0].destination;
- cv[9].destination = cv[1].destination;
- cv[10].destination = cv[2].destination;
- cv[11].destination = cv[3].destination;
- cv[12].destination = cv[4].destination;
- cv[13].destination = cv[5].destination;
- cv[14].destination = cv[6].destination;
-
- cv[15].destination = &(s->cache_ttl);
- cv[16].destination = &(s->debug);
-
- p->config_storage[i] = s;
-
- if (config_insert_values_global(srv,
- ((data_config *)srv->config_context->data[i])->value,
- cv)) return HANDLER_ERROR;
-
- /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
- }
-
- return HANDLER_GO_ON;
-}
-
-static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(backend_data);
- PATCH_OPTION(get_vhost);
-#ifdef HAVE_GLIB_H
- PATCH_OPTION(vhost_table);
-#endif
- PATCH_OPTION(cache_ttl);
- PATCH_OPTION(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;
-
- if (s->backend_data) {
- PATCH_OPTION(backend_data);
- PATCH_OPTION(get_vhost);
-#ifdef HAVE_GLIB_H
- PATCH_OPTION(vhost_table);
-#endif
- }
-
- 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_CACHE_TTL))) {
- PATCH_OPTION(cache_ttl);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DEBUG))) {
- PATCH_OPTION(debug);
- }
- }
- }
-
- return 0;
-}
-
-/* handle document root request
- *
- * glib: if available we cache the entries
- *
- * */
-CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
- plugin_data *p = p_d;
- stat_cache_entry *sce;
-#ifdef HAVE_GLIB_H
- cached_vhost *vhost = NULL;
-#endif
-
- /* no host specified? */
- if (!con->uri.authority->used) return HANDLER_GO_ON;
-
- mod_sql_vhost_core_patch_connection(srv, con, p);
-
- /* do we have backend ? */
- if (!p->conf.get_vhost) return HANDLER_GO_ON;
-
-#ifdef HAVE_GLIB_H
- if (p->conf.cache_ttl == 0 || /* 1. we don't cache */
- NULL == (vhost = g_hash_table_lookup(p->conf.vhost_table, con->uri.authority)) || /* 2. check if the host is already known */
- srv->cur_ts - vhost->added_ts >= p->conf.cache_ttl
- ) { /* 3. the cache value is old */
- /* ask the backend for the data */
- if (p->conf.debug) TRACE("cache-miss for %s", SAFE_BUF_STR(con->uri.authority));
-
- if (HANDLER_GO_ON != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
- return HANDLER_GO_ON;
- }
-
- if (p->conf.cache_ttl > 0) {
- /* check if the cache-ttl is > 0, otherwise we would always trash the cache-entry */
- if (vhost) {
- if (p->conf.debug) TRACE("refreshing %s: %s", SAFE_BUF_STR(con->uri.authority), SAFE_BUF_STR(p->docroot));
- buffer_copy_string_buffer(vhost->docroot, p->docroot);
- vhost->added_ts = srv->cur_ts;
- } else {
- buffer *key;
-
- vhost = g_new0(cached_vhost, 1);
- vhost->docroot = buffer_init_buffer(p->docroot);
- vhost->added_ts = srv->cur_ts;
- vhost->ttl = p->conf.cache_ttl;
-
- key = buffer_init_buffer(con->uri.authority);
-
- if (p->conf.debug) TRACE("adding %s: %s", SAFE_BUF_STR(key), SAFE_BUF_STR(vhost->docroot));
-
- g_hash_table_insert(p->conf.vhost_table, key, vhost);
-
- g_assert(g_hash_table_lookup(p->conf.vhost_table, key));
- }
- }
- } else {
- if (p->conf.debug) TRACE("cache-hit for %s: %s", SAFE_BUF_STR(vhost->docroot), SAFE_BUF_STR(con->uri.authority));
-
- buffer_copy_string_buffer(p->docroot, vhost->docroot);
- }
-#else
- if (HANDLER_GO_ON != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
- return HANDLER_GO_ON;
- }
-#endif
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
- ERROR("stat_cache_get_entry(%s) failed: %s", SAFE_BUF_STR(p->docroot), strerror(errno));
-
- return HANDLER_GO_ON;
- }
- if (!S_ISDIR(sce->st.st_mode)) {
- ERROR("%s is not a dir", SAFE_BUF_STR(p->docroot));
-
- return HANDLER_GO_ON;
- }
-
- buffer_copy_string_buffer(con->server_name, p->host);
- buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
-
- return HANDLER_GO_ON;
-}
-
-#if 0
-#ifdef HAVE_GLIB_H
-static gboolean cached_vhost_remove_expired(gpointer _key, gpointer _val, gpointer data) {
-// buffer *key = _key;
- cached_vhost *val = _val;
- server *srv = data;
- UNUSED(_key);
-
- return (srv->cur_ts - val->added_ts > val->ttl);
-}
-#endif
-
-TRIGGER_FUNC(mod_sql_vhost_core_trigger) {
- plugin_data *p = p_d;
- size_t i;
-
- /* test once every 10 seconds */
- if (srv->cur_ts % 10 != 0) return HANDLER_GO_ON;
-
-#ifdef HAVE_GLIB_H
- /* cleanup all caches */
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (s->vhost_table) {
- g_hash_table_foreach_remove(s->vhost_table, cached_vhost_remove_expired, srv);
- }
- }
-#endif
-
- return HANDLER_GO_ON;
-}
-#endif
-
-/* this function is called at dlopen() time and inits the callbacks */
-LI_EXPORT int mod_sql_vhost_core_plugin_init(plugin *p);
-LI_EXPORT int mod_sql_vhost_core_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_sql_vhost_core");
-
- p->init = mod_sql_vhost_core_init;
- p->cleanup = mod_sql_vhost_core_cleanup;
-
- p->set_defaults = mod_sql_vhost_core_set_defaults;
- p->handle_docroot = mod_sql_vhost_core_handle_docroot;
-
- return 0;
-}
-
diff --git a/src/mod_sql_vhost_core.h b/src/mod_sql_vhost_core.h
deleted file mode 100644
index 2d70f62d..00000000
--- a/src/mod_sql_vhost_core.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _MOD_SQL_VHOST_CORE_H_
-#define _MOD_SQL_VHOST_CORE_H_
-
-#include "buffer.h"
-#include "plugin.h"
-
-#ifdef HAVE_GLIB_H
-#include <glib.h>
-#endif
-
-#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
- (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
-
-#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
-
-#define SQLVHOST_BACKEND_GETVHOST(name) \
- SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
-
-#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
- SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
-
-typedef struct {
- buffer *db;
- buffer *user;
- buffer *pass;
- buffer *sock;
-
- buffer *hostname;
- unsigned short port;
-
- buffer *backend;
- void *backend_data;
-
- buffer *select_vhost;
-
- unsigned short cache_ttl;
- unsigned short debug;
-
-#ifdef HAVE_GLIB_H
- GHashTable *vhost_table;
-#endif
-
- SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
-} mod_sql_vhost_core_plugin_config;
-
-/* global plugin data */
-typedef struct {
- PLUGIN_DATA;
-
- buffer *docroot;
- buffer *host;
-
- mod_sql_vhost_core_plugin_config **config_storage;
-
- mod_sql_vhost_core_plugin_config conf;
-} mod_sql_vhost_core_plugin_data;
-
-
-
-#endif
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
deleted file mode 100644
index 91370e01..00000000
--- a/src/mod_ssi.c
+++ /dev/null
@@ -1,1095 +0,0 @@
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "stat_cache.h"
-
-#include "plugin.h"
-#include "stream.h"
-
-#include "response.h"
-
-#include "mod_ssi.h"
-
-#include "inet_ntop_cache.h"
-
-#include "sys-socket.h"
-#include "sys-strings.h"
-#include "sys-files.h"
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-
-#ifdef HAVE_FORK
-#include <sys/wait.h>
-#endif
-
-#ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h>
-#endif
-
-/* init the plugin data */
-INIT_FUNC(mod_ssi_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- 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];
-
- array_free(s->ssi_extension);
- buffer_free(s->content_type);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- array_free(p->ssi_vars);
- array_free(p->ssi_cgi_env);
-#ifdef HAVE_PCRE_H
- pcre_free(p->ssi_regex);
-#endif
- 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;
-#ifdef HAVE_PCRE_H
- const char *errptr;
- int erroff;
-#endif
-
- config_values_t cv[] = {
- { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "ssi.content-type", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->ssi_extension = array_init();
- s->content_type = buffer_init();
-
- cv[0].destination = s->ssi_extension;
- cv[1].destination = s->content_type;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
-#ifdef HAVE_PCRE_H
- /* allow 2 params */
- if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "ssi: pcre ",
- erroff, errptr);
- return HANDLER_ERROR;
- }
-#else
- log_error_write(srv, __FILE__, __LINE__, "s",
- "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
- return HANDLER_ERROR;
-#endif
-
- return HANDLER_GO_ON;
-}
-
-static int ssi_env_add(array *env, const char *key, const char *val) {
- data_string *ds;
-
- if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
- ds = data_string_init();
- }
- buffer_copy_string(ds->key, key);
- buffer_copy_string(ds->value, val);
-
- array_insert_unique(env, (data_unset *)ds);
-
- return 0;
-}
-
-/**
- *
- * the next two functions are take from fcgi.c
- *
- */
-
-static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
- size_t i;
-
- for (i = 0; i < con->request.headers->used; i++) {
- data_string *ds;
-
- ds = (data_string *)con->request.headers->data[i];
-
- if (ds->value->used && ds->key->used) {
- size_t j;
- buffer_reset(srv->tmp_buf);
-
- /* don't forward the Authorization: Header */
- if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
- continue;
- }
-
- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
- srv->tmp_buf->used--;
- }
-
- buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = '_';
- if (light_isalpha(ds->key->ptr[j])) {
- /* upper-case */
- c = ds->key->ptr[j] & ~32;
- } else if (light_isdigit(ds->key->ptr[j])) {
- /* copy */
- c = ds->key->ptr[j];
- }
- srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
- }
- srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
-
- ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
- }
- }
-
- return 0;
-}
-
-static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
- char buf[32];
-
- server_socket *srv_sock = con->srv_socket;
-
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-#endif
-
-#define CONST_STRING(x) \
- x
-
- array_reset(p->ssi_cgi_env);
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
-#ifdef HAVE_IPV6
- inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1)
-#else
- inet_ntoa(srv_sock->addr.ipv4.sin_addr)
-#endif
- );
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
-
- LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
-#else
- ntohs(srv_sock->addr.ipv4.sin_port)
-#endif
- );
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
- inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
- if (con->authed_user->used) {
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
- con->authed_user->ptr);
- }
-
- if (con->request.content_length > 0) {
- /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
-
- /* request.content_length < SSIZE_MAX, see request.c */
- LI_ltostr(buf, con->request.content_length);
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
- }
-
- /*
- * 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)
- */
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_NAME"), con->uri.path->ptr);
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), "");
-
- /*
- * 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.
- * TODO: this code should be checked against cgi.fix_pathinfo php
- * parameter.
- */
-
- if (con->request.pathinfo->used) {
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
- }
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
-
- ssi_env_add_request_headers(srv, con, p);
-
- return 0;
-}
-
-static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
- const char **l, size_t n) {
- size_t i, ssicmd = 0;
- char buf[255];
- buffer *b = NULL;
-
- 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 } 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 },
-
- { NULL, SSI_UNSET }
- };
-
- for (i = 0; ssicmds[i].var; i++) {
- if (0 == strcmp(l[1], ssicmds[i].var)) {
- ssicmd = ssicmds[i].type;
- break;
- }
- }
-
- switch(ssicmd) {
- case SSI_ECHO: {
- /* echo */
- int var = 0, enc = 0;
- const char *var_val = NULL;
- stat_cache_entry *sce = NULL;
-
- 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 } 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 },
-
- { NULL, SSI_ECHO_UNSET }
- };
-
- 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: unknow 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;
- }
-
- stat_cache_get_entry(srv, con, con->physical.path, &sce);
-
- switch(var) {
- case SSI_ECHO_USER_NAME: {
- struct passwd *pw;
-
- b = chunkqueue_get_append_buffer(con->send);
-#ifdef HAVE_PWD_H
- if (NULL == (pw = getpwuid(sce->st.st_uid))) {
- buffer_copy_long(b, sce->st.st_uid);
- } else {
- buffer_copy_string(b, pw->pw_name);
- }
-#else
- buffer_copy_long(b, sce->st.st_uid);
-#endif
- break;
- }
- case SSI_ECHO_LAST_MODIFIED: {
- time_t t = sce->st.st_mtime;
-
- b = chunkqueue_get_append_buffer(con->send);
- if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
- } else {
- buffer_copy_string(b, buf);
- }
- break;
- }
- case SSI_ECHO_DATE_LOCAL: {
- time_t t = time(NULL);
-
- b = chunkqueue_get_append_buffer(con->send);
- if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
- } else {
- buffer_copy_string(b, buf);
- }
- break;
- }
- case SSI_ECHO_DATE_GMT: {
- time_t t = time(NULL);
-
- b = chunkqueue_get_append_buffer(con->send);
- if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
- } else {
- buffer_copy_string(b, buf);
- }
- break;
- }
- case SSI_ECHO_DOCUMENT_NAME: {
- char *sl;
-
- b = chunkqueue_get_append_buffer(con->send);
- if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
- buffer_copy_string_buffer(b, con->physical.path);
- } else {
- buffer_copy_string(b, sl + 1);
- }
- break;
- }
- case SSI_ECHO_DOCUMENT_URI: {
- b = chunkqueue_get_append_buffer(con->send);
- buffer_copy_string_buffer(b, con->uri.path);
- break;
- }
- default: {
- data_string *ds;
- /* check if it is a cgi-var */
-
- b = chunkqueue_get_append_buffer(con->send);
-
- if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val, strlen(var_val)))) {
- buffer_copy_string_buffer(b, ds->value);
- } else {
- buffer_copy_string_len(b, 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 st;
- 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: unknow 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);
- buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
- buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
- } else {
- /* virtual */
-
- if (virt_path[0] == '/') {
- buffer_copy_string(p->stat_fn, virt_path);
- } else {
- /* there is always a / */
- sl = strrchr(con->uri.path->ptr, '/');
-
- buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
- buffer_append_string(p->stat_fn, virt_path);
- }
-
- buffer_urldecode_path(p->stat_fn);
- buffer_path_simplify(srv->tmp_buf, p->stat_fn);
-
- /* we have an uri */
-
- buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
- buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
- }
-
- if (0 == stat(p->stat_fn->ptr, &st)) {
- time_t t = st.st_mtime;
-
- switch (ssicmd) {
- case SSI_FSIZE:
- b = chunkqueue_get_append_buffer(con->send);
- if (p->sizefmt) {
- int j = 0;
- const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
-
- off_t s = st.st_size;
-
- for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
-
- buffer_copy_off_t(b, s);
- buffer_append_string(b, abr[j]);
- } else {
- buffer_copy_off_t(b, st.st_size);
- }
- break;
- case SSI_FLASTMOD:
- b = chunkqueue_get_append_buffer(con->send);
- if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
- buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
- } else {
- buffer_copy_string(b, buf);
- }
- break;
- case SSI_INCLUDE:
- chunkqueue_append_file(con->send, p->stat_fn, 0, st.st_size);
- 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: unknow attribute for ",
- l[1], l[i]);
- }
- }
-
- if (p->if_is_false) break;
-
- if (key && val) {
- data_string *ds;
-
- if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
- ds = data_string_init();
- }
- buffer_copy_string(ds->key, key);
- buffer_copy_string(ds->value, val);
-
- array_insert_unique(p->ssi_vars, (data_unset *)ds);
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: var and value have to be set in",
- l[0], l[1]);
- }
- 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], "abbrev")) {
- p->sizefmt = 0;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sssss",
- "ssi: unknow value for attribute '",
- l[i],
- "' for ",
- l[1], l[i+1]);
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
- l[1], l[i]);
- }
- }
- break;
- case SSI_PRINTENV:
- if (p->if_is_false) break;
-
- b = chunkqueue_get_append_buffer(con->send);
- buffer_copy_string_len(b, CONST_STR_LEN("<pre>"));
- for (i = 0; i < p->ssi_vars->used; i++) {
- data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
-
- buffer_append_string_buffer(b, ds->key);
- buffer_append_string_len(b, CONST_STR_LEN(": "));
- buffer_append_string_buffer(b, ds->value);
- buffer_append_string_len(b, CONST_STR_LEN("<br />"));
-
- }
- buffer_append_string_len(b, CONST_STR_LEN("</pre>"));
-
- break;
- case SSI_EXEC: {
-#ifndef _WIN32
-
- const char *cmd = NULL;
- pid_t pid;
- int from_exec_fds[2];
-
- for (i = 2; i < n; i += 2) {
- if (0 == strcmp(l[i], "cmd")) {
- cmd = l[i+1];
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
- l[1], l[i]);
- }
- }
-
- if (p->if_is_false) break;
-
- /* create a return pipe and send output to the html-page
- *
- * as exec is assumed evil it is implemented synchronously
- */
-
- if (!cmd) break;
-
- if (pipe(from_exec_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "pipe failed: ", strerror(errno));
- return -1;
- }
-
- /* fork, execve */
- switch (pid = fork()) {
- case 0: {
- /* move stdout to from_rrdtool_fd[1] */
- close(STDOUT_FILENO);
- dup2(from_exec_fds[1], STDOUT_FILENO);
- close(from_exec_fds[1]);
- /* not needed */
- close(from_exec_fds[0]);
-
- /* close stdin */
- close(STDIN_FILENO);
-
- execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
-
- /* */
- SEGFAULT("spawing '%s' failed: %s", cmd, strerror(errno));
- break;
- }
- case -1:
- /* error */
- log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
- break;
- default: {
- /* father */
- int status;
- ssize_t r;
-
- close(from_exec_fds[1]);
-
- /* wait for the client to end */
- if (-1 == waitpid(pid, &status, 0)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
- } else if (WIFEXITED(status)) {
- int toread;
- /* read everything from client and paste it into the output */
-
- while(1) {
- if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected end-of-file (perhaps the ssi-exec process died)");
- return -1;
- }
-
- if (toread > 0) {
- b = chunkqueue_get_append_buffer(con->send);
-
- buffer_prepare_copy(b, toread + 1);
-
- if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
- /* read failed */
- break;
- } else {
- b->used = r;
- b->ptr[b->used++] = '\0';
- }
- } else {
- break;
- }
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
- }
- close(from_exec_fds[0]);
-
- break;
- }
- }
-#else
- return -1;
-#endif
-
- break;
- }
- case SSI_IF: {
- const char *expr = NULL;
-
- for (i = 2; i < n; i += 2) {
- if (0 == strcmp(l[i], "expr")) {
- expr = l[i+1];
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
- 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: unknow 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;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "ssi: unknow ssi-command:",
- l[1]);
- break;
- }
-
- return 0;
-
-}
-
-static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
- stream s;
-#ifdef HAVE_PCRE_H
- int i, n;
-
-#define N 10
- int ovec[N * 3];
-#endif
-
- /* get a stream to the file */
-
- array_reset(p->ssi_vars);
- array_reset(p->ssi_cgi_env);
- buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z"));
- p->sizefmt = 0;
- build_ssi_cgi_vars(srv, con, p);
- p->if_is_false = 0;
-
- if (-1 == stream_open(&s, con->physical.path)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "stream-open: ", con->physical.path);
- return -1;
- }
-
-
- /**
- * <!--#element attribute=value attribute=value ... -->
- *
- * 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.
- *
- */
-#ifdef HAVE_PCRE_H
- for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
- const char **l;
- /* take everything from last offset to current match pos */
-
- if (!p->if_is_false) chunkqueue_append_file(con->send, con->physical.path, i, ovec[0] - i);
-
- pcre_get_substring_list(s.start, ovec, n, &l);
- process_ssi_stmt(srv, con, p, l, n);
- pcre_free_substring_list(l);
- }
-
- switch(n) {
- case PCRE_ERROR_NOMATCH:
- /* copy everything/the rest */
- chunkqueue_append_file(con->send, con->physical.path, i, s.size - i);
-
- break;
- default:
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "execution error while matching: ", n);
- break;
- }
-#endif
-
-
- stream_close(&s);
-
- con->file_started = 1;
- con->send->is_closed = 1;
-
- if (p->conf.content_type->used <= 1) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- } else {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type));
- }
-
- /* reset physical.path */
- buffer_reset(con->physical.path);
-
- return 0;
-}
-
-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_OPTION(ssi_extension);
- PATCH_OPTION(content_type);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
- PATCH_OPTION(ssi_extension);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.content-type"))) {
- PATCH_OPTION(content_type);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_ssi_physical_path) {
- plugin_data *p = p_d;
- size_t k;
-
- if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
- mod_ssi_patch_connection(srv, con, p);
-
- for (k = 0; k < p->conf.ssi_extension->used; k++) {
- data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
-
- if (ds->value->used == 0) continue;
-
- if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
- /* handle ssi-request */
-
- if (mod_ssi_handle_request(srv, con, p)) {
- /* on error */
- con->http_status = 500;
- }
-
- return HANDLER_FINISHED;
- }
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_ssi_plugin_init(plugin *p);
-LI_EXPORT 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_start_backend = mod_ssi_physical_path;
- p->set_defaults = mod_ssi_set_defaults;
- p->cleanup = mod_ssi_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_ssi.h b/src/mod_ssi.h
deleted file mode 100644
index 241e8320..00000000
--- a/src/mod_ssi.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _MOD_SSI_H_
-#define _MOD_SSI_H_
-
-#include "base.h"
-#include "buffer.h"
-#include "array.h"
-
-#include "plugin.h"
-
-#ifdef HAVE_PCRE_H
-#include <pcre.h>
-#endif
-
-/* plugin config for all request/connections */
-
-typedef struct {
- array *ssi_extension;
- buffer *content_type;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
-#ifdef HAVE_PCRE_H
- pcre *ssi_regex;
-#endif
- buffer *timefmt;
- int sizefmt;
-
- buffer *stat_fn;
-
- array *ssi_vars;
- array *ssi_cgi_env;
-
- int if_level, if_is_false_level, if_is_false, if_is_false_endif;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
-
-#endif
diff --git a/src/mod_ssi_expr.c b/src/mod_ssi_expr.c
deleted file mode 100644
index 0766e50d..00000000
--- a/src/mod_ssi_expr.c
+++ /dev/null
@@ -1,325 +0,0 @@
-#include <ctype.h>
-#include <string.h>
-
-#include "mod_ssi.h"
-#include "mod_ssi_expr.h"
-#include "mod_ssi_exprparser.h"
-
-#include "buffer.h"
-#include "log.h"
-
-typedef struct {
- const char *input;
- size_t offset;
- size_t size;
-
- int line_pos;
-
- int in_key;
- int in_brace;
- int in_cond;
-} ssi_tokenizer_t;
-
-ssi_val_t *ssi_val_init() {
- ssi_val_t *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 B->str->used > 1 ? 1 : 0;
- } else {
- return B->bo;
- }
-}
-
-static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p,
- ssi_tokenizer_t *t, int *token_id, buffer *token) {
- int tid = 0;
- size_t i;
-
- UNUSED(con);
-
- for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
- char c = t->input[t->offset];
- data_string *ds;
-
- switch (c) {
- case '=':
- 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++);
-
- buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
- }
-
- tid = TK_VALUE;
-
- if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, CONST_BUF_LEN(token)))) {
- buffer_copy_string_buffer(token, ds->value);
- } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, CONST_BUF_LEN(token)))) {
- buffer_copy_string_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, plugin_data *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 );
- 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/src/mod_ssi_expr.h b/src/mod_ssi_expr.h
deleted file mode 100644
index 2d3ae8bb..00000000
--- a/src/mod_ssi_expr.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _MOD_SSI_EXPR_H_
-#define _MOD_SSI_EXPR_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 ssi_val_free(ssi_val_t *s);
-
-#endif
diff --git a/src/mod_ssi_exprparser.y b/src/mod_ssi_exprparser.y
deleted file mode 100644
index ffaafd05..00000000
--- a/src/mod_ssi_exprparser.y
+++ /dev/null
@@ -1,122 +0,0 @@
-%token_prefix TK_
-%token_type {buffer *}
-%extra_argument {ssi_ctx_t *ctx}
-%name ssiexprparser
-
-%include {
-#include <assert.h>
-#include <string.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "mod_ssi_expr.h"
-#include "buffer.h"
-}
-
-%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/src/mod_staticfile.c b/src/mod_staticfile.c
deleted file mode 100644
index 1be1d594..00000000
--- a/src/mod_staticfile.c
+++ /dev/null
@@ -1,552 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "stat_cache.h"
-#include "etag.h"
-#include "response.h"
-
-#include "sys-files.h"
-#include "sys-strings.h"
-
-#include "http_req_range.h"
-/**
- * this is a staticfile for a lighttpd plugin
- *
- */
-
-
-
-/* plugin config for all request/connections */
-
-typedef struct {
- array *exclude_ext;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- buffer *range_buf;
-
- http_req_range *ranges;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-/* init the plugin data */
-INIT_FUNC(mod_staticfile_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->range_buf = buffer_init();
-
- p->ranges = http_request_range_init();
-
- return p;
-}
-
-/* destroy the plugin data */
-FREE_FUNC(mod_staticfile_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- array_free(s->exclude_ext);
-
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->range_buf);
-
- http_request_range_free(p->ranges);
-
- 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 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->exclude_ext = array_init();
-
- cv[0].destination = s->exclude_ext;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(exclude_ext);
-
- /* 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_OPTION(exclude_ext);
- }
- }
- }
-
- return 0;
-}
-
-static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
- int multipart = 0;
- char *boundary = "fkj49sn38dcn3";
- data_string *ds;
- stat_cache_entry *sce = NULL;
- buffer *content_type = NULL;
- buffer *range = NULL;
- http_req_range *ranges, *r;
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Range")))) {
- range = ds->value;
- } else {
- /* we don't have a Range header */
-
- return -1;
- }
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- SEGFAULT("stat_cache_get_entry(%s) returned %d", SAFE_BUF_STR(con->physical.path), HANDLER_ERROR);
- }
-
- con->response.content_length = 0;
-
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("Content-Type")))) {
- content_type = ds->value;
- }
-
- /* start the range-header parser
- * bytes=<num> */
-
- ranges = p->ranges;
- http_request_range_reset(ranges);
- switch (http_request_range_parse(range, ranges)) {
- case PARSE_ERROR:
- return -1; /* no range valid Range Header */
- case PARSE_SUCCESS:
- break;
- default:
- TRACE("%s", "foobar");
- return -1;
- }
-
- if (ranges->next) {
- multipart = 1;
- }
-
- /* patch the '-1' */
- for (r = ranges; r; r = r->next) {
- if (r->start == -1) {
- /* -<end>
- *
- * the last <end> bytes */
- r->start = sce->st.st_size - r->end;
- r->end = sce->st.st_size - 1;
- }
- if (r->end == -1) {
- /* <start>-
- * all but the first <start> bytes */
-
- r->end = sce->st.st_size - 1;
- }
-
- if (r->end > sce->st.st_size - 1) {
- /* RFC 2616 - 14.35.1
- *
- * if last-byte-pos not present or > size-of-file
- * take the size-of-file
- *
- * */
- r->end = sce->st.st_size - 1;
- }
-
- if (r->start > sce->st.st_size - 1) {
- /* RFC 2616 - 14.35.1
- *
- * if first-byte-pos > file-size, 416
- */
-
- con->http_status = 416;
- return -1;
- }
-
- if (r->start > r->end) {
- /* RFC 2616 - 14.35.1
- *
- * if last-byte-pos is present, it has to be >= first-byte-pos
- *
- * invalid ranges have to be handle as no Range specified
- * */
-
- return -1;
- }
- }
-
- if (r) {
- /* we ran into an range violation */
- return -1;
- }
-
- if (multipart) {
- buffer *b;
- for (r = ranges; r; r = r->next) {
- /* write boundary-header */
-
- b = chunkqueue_get_append_buffer(con->send);
-
- buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));
- buffer_append_string(b, boundary);
-
- /* write Content-Range */
- buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));
- buffer_append_off_t(b, r->start);
- buffer_append_string_len(b, CONST_STR_LEN("-"));
- buffer_append_off_t(b, r->end);
- buffer_append_string_len(b, CONST_STR_LEN("/"));
- buffer_append_off_t(b, sce->st.st_size);
-
- 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 += b->used - 1;
- con->send->bytes_in += b->used - 1;
-
- chunkqueue_append_file(con->send, con->physical.path, r->start, r->end - r->start + 1);
- con->response.content_length += r->end - r->start + 1;
- con->send->bytes_in += r->end - r->start + 1;
- }
-
- /* add boundary end */
- b = chunkqueue_get_append_buffer(con->send);
-
- buffer_copy_string_len(b, "\r\n--", 4);
- buffer_append_string(b, boundary);
- buffer_append_string_len(b, "--\r\n", 4);
-
- con->response.content_length += b->used - 1;
- con->send->bytes_in += b->used - 1;
-
- /* set header-fields */
-
- buffer_copy_string_len(p->range_buf, CONST_STR_LEN("multipart/byteranges; boundary="));
- buffer_append_string(p->range_buf, boundary);
-
- /* overwrite content-type */
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
-
- } else {
- r = ranges;
-
- chunkqueue_append_file(con->send, con->physical.path, r->start, r->end - r->start + 1);
- con->response.content_length += r->end - r->start + 1;
- con->send->bytes_in += r->end - r->start + 1;
-
- buffer_copy_string_len(p->range_buf, CONST_STR_LEN("bytes "));
- buffer_append_off_t(p->range_buf, r->start);
- buffer_append_string_len(p->range_buf, CONST_STR_LEN("-"));
- buffer_append_off_t(p->range_buf, r->end);
- buffer_append_string_len(p->range_buf, CONST_STR_LEN("/"));
- buffer_append_off_t(p->range_buf, sce->st.st_size);
-
- response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
- }
-
- /* ok, the file is set-up */
- return 0;
-}
-
-URIHANDLER_FUNC(mod_staticfile_subrequest) {
- plugin_data *p = p_d;
- size_t k;
- int s_len;
- stat_cache_entry *sce = NULL;
- buffer *mtime;
- data_string *ds;
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "checking file for static file");
- }
-
-
- /* someone else has done a decision for us */
- if (con->http_status != 0) return HANDLER_GO_ON;
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
- if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
- /* someone else has handled this request */
- if (con->mode != DIRECT) return HANDLER_GO_ON;
-
- /* 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 (con->conf.log_request_handling) {
- TRACE("-- %s", "handling file as static file");
- }
-
-
- s_len = con->uri.path->used - 1;
-
- /* ignore certain extensions */
- for (k = 0; k < p->conf.exclude_ext->used; k++) {
- ds = (data_string *)p->conf.exclude_ext->data[k];
-
- if (ds->value->used == 0) continue;
-
- if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
- if (con->conf.log_request_handling) {
- TRACE("'%s' matched exclude(%s), sending 403",
- SAFE_BUF_STR(con->physical.path),
- SAFE_BUF_STR(ds->value));
- }
-
- con->http_status = 403;
-
- return HANDLER_FINISHED;
- }
- }
-
-
- 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) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
- log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
- }
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- }
-#endif
- if (!S_ISREG(sce->st.st_mode)) {
- con->http_status = 404;
-
- if (con->conf.log_file_not_found) {
- log_error_write(srv, __FILE__, __LINE__, "sbsb",
- "not a regular file:", con->uri.path,
- "->", sce->name);
- }
-
- return HANDLER_FINISHED;
- }
-
- /* mod_compress might set several parameters directly; don't overwrite them */
-
- /* set response content-type, if not set already */
-
- if (NULL == array_get_element(con->response.headers, CONST_STR_LEN("Content-Type"))) {
- if (buffer_is_empty(sce->content_type)) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream"));
- } else {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
- }
- }
-
- if (NULL == array_get_element(con->response.headers, CONST_STR_LEN("ETag"))) {
- /* generate e-tag */
- etag_mutate(con->physical.etag, sce->etag);
-
- response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
- }
- if (con->conf.range_requests) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
- }
-
- /* prepare header */
- if (NULL == (ds = (data_string *)array_get_element(con->response.headers, CONST_STR_LEN("Last-Modified")))) {
- mtime = strftime_cache_get(srv, sce->st.st_mtime);
- response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
- } else {
- mtime = ds->value;
- }
-
- if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
- return HANDLER_FINISHED;
- } else if (con->conf.range_requests &&
- NULL != array_get_element(con->request.headers, CONST_STR_LEN("Range"))) {
- int do_range_request = 1;
- /* check if we have a conditional GET */
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("If-Range")))) {
- /* if the value is the same as our ETag, we do a Range-request,
- * otherwise a full 200 */
-
- if (!buffer_is_equal(ds->value, con->physical.etag)) {
- do_range_request = 0;
- }
- }
-
- if (do_range_request) {
- /* content prepared, I'm done */
- con->send->is_closed = 1;
-
- if (0 == http_response_parse_range(srv, con, p)) {
- con->http_status = 206;
- }
- return HANDLER_FINISHED;
- }
- }
-
- /* if we are still here, prepare body */
-
- /* we add it here for all requests
- * the HEAD request will drop it afterwards again
- */
- chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
-
- con->send->is_closed = 1;
- con->send->bytes_in = sce->st.st_size;
-
- return HANDLER_FINISHED;
-}
-
-/**
- * mark all the content as read
- */
-CONNECTION_FUNC(mod_staticfile_dev_null) {
- chunk *c;
- chunkqueue *in = con->recv;
-
- UNUSED(srv);
- UNUSED(p_d);
-
- if (con->mode != DIRECT) return HANDLER_GO_ON;
-
- /* there is nothing that we have to send out anymore */
- if (in->bytes_in == in->bytes_out &&
- in->is_closed) return HANDLER_GO_ON;
-
- for (c = in->first; in->bytes_out < in->bytes_in; c = c->next) {
- off_t weWant = in->bytes_in - in->bytes_out;
- off_t weHave = 0;
-
- /* we announce toWrite octects
- * now take all the request_content chunk that we need to fill this request
- */
-
- switch (c->type) {
- case FILE_CHUNK:
- weHave = c->file.length - c->offset;
-
- if (weHave > weWant) weHave = weWant;
-
- c->offset += weHave;
- in->bytes_out += weHave;
-
- break;
- case MEM_CHUNK:
- /* append to the buffer */
- weHave = c->mem->used - 1 - c->offset;
-
- if (weHave > weWant) weHave = weWant;
-
- c->offset += weHave;
- in->bytes_out += weHave;
-
- break;
- default:
- break;
- }
- }
-
- return HANDLER_GO_ON;
-
-}
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_staticfile_plugin_init(plugin *p);
-LI_EXPORT 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_start_backend = mod_staticfile_subrequest;
- p->handle_send_request_content = mod_staticfile_dev_null;
- p->set_defaults = mod_staticfile_set_defaults;
- p->cleanup = mod_staticfile_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_status.c b/src/mod_status.c
deleted file mode 100644
index 459db41c..00000000
--- a/src/mod_status.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined.
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <sys/types.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <stdio.h>
-
-#include "server.h"
-#include "connections.h"
-#include "response.h"
-#include "connections.h"
-#include "log.h"
-#include "status_counter.h"
-#include "network_backends.h"
-
-#include "plugin.h"
-
-#include "inet_ntop_cache.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 *tmp_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-INIT_FUNC(mod_status_init) {
- plugin_data *p;
- size_t i;
-
- UNUSED(srv);
-
- 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->tmp_buf = 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->tmp_buf);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- buffer_free(s->status_url);
- buffer_free(s->statistics_url);
- buffer_free(s->config_url);
-
- free(s);
- }
- free(p->config_storage);
- }
-
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-SETDEFAULTS_FUNC(mod_status_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->config_url = buffer_init();
- s->status_url = buffer_init();
- s->sort = 1;
- s->statistics_url = buffer_init();
-
- cv[0].destination = s->status_url;
- cv[1].destination = s->config_url;
- cv[2].destination = &(s->sort);
- cv[3].destination = s->statistics_url;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-
-
-static int mod_status_row_append(buffer *b, const char *key, const char *value) {
- buffer_append_string_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;
- size_t j;
- double avg;
- char multiplier = '\0';
- char buf[128];
- time_t ts;
-
- int days, hours, mins, seconds;
-
- b = chunkqueue_get_append_buffer(con->send);
-
- 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 (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</h1>"));
-
- buffer_append_string_len(b, CONST_STR_LEN("<table class=\"status\" id=\"status\" summary=\"Server Status\">"));
- buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">"));
- buffer_append_string_buffer(b, con->uri.authority);
- buffer_append_string_len(b, CONST_STR_LEN("</span> (<span id=\"host_name\">"));
- buffer_append_string_buffer(b, con->server_name);
- buffer_append_string_len(b, CONST_STR_LEN("</span>)</td></tr>\n"));
- buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">"));
-
- ts = srv->cur_ts - srv->startup_ts;
-
- days = ts / (60 * 60 * 24);
- ts %= (60 * 60 * 24);
-
- hours = ts / (60 * 60);
- ts %= (60 * 60);
-
- mins = ts / (60);
- ts %= (60);
-
- seconds = ts;
-
- if (days) {
- buffer_append_long(b, days);
- buffer_append_string_len(b, CONST_STR_LEN(" days "));
- }
-
- if (hours) {
- buffer_append_long(b, hours);
- buffer_append_string_len(b, CONST_STR_LEN(" hours "));
- }
-
- if (mins) {
- buffer_append_long(b, mins);
- buffer_append_string_len(b, CONST_STR_LEN(" min "));
- }
-
- buffer_append_long(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, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", 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\" ><span id=\"requests\">"));
- avg = p->abs_requests;
-
- mod_status_get_multiplier(&avg, &multiplier, 1000);
-
- buffer_append_long(b, avg);
- buffer_append_string_len(b, CONST_STR_LEN("</span> <span id=\"requests_mult\">"));
- if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- buffer_append_string_len(b, CONST_STR_LEN("</span>req</td></tr>\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">"));
- avg = p->abs_traffic_out;
-
- mod_status_get_multiplier(&avg, &multiplier, 1024);
-
- sprintf(buf, "%.2f", avg);
- buffer_append_string(b, buf);
- buffer_append_string_len(b, CONST_STR_LEN("</span> <span id=\"traffic_mult\">"));
- if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- buffer_append_string_len(b, CONST_STR_LEN("</span>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\"><span id=\"requests_avg\">"));
- avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
-
- mod_status_get_multiplier(&avg, &multiplier, 1000);
-
- buffer_append_long(b, avg);
- buffer_append_string_len(b, CONST_STR_LEN("</span> <span id=\"requests_avg_mult\">"));
- if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- buffer_append_string_len(b, CONST_STR_LEN("</span>req/s</td></tr>\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">"));
- avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
-
- mod_status_get_multiplier(&avg, &multiplier, 1024);
-
- sprintf(buf, "%.2f", avg);
- buffer_append_string(b, buf);
- buffer_append_string_len(b, CONST_STR_LEN("</span> <span id=\"traffic_avg_mult\">"));
- if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- buffer_append_string_len(b, CONST_STR_LEN("</span>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\"><span id=\"requests_sliding_avg\">"));
-
- mod_status_get_multiplier(&avg, &multiplier, 1000);
-
- buffer_append_long(b, avg);
- buffer_append_string_len(b, CONST_STR_LEN("</span> <span id=\"requests_sliding_avg_mult\">"));
- if (multiplier) buffer_append_string_len(b, &multiplier, 1);
-
- buffer_append_string_len(b, CONST_STR_LEN("</span>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\"><span id=\"requests_sliding_traffic\">"));
-
- mod_status_get_multiplier(&avg, &multiplier, 1024);
-
- sprintf(buf, "%.2f", avg);
- buffer_append_string(b, buf);
- buffer_append_string_len(b, CONST_STR_LEN("</span> <span id=\"requests_sliding_traffic_mult\">"));
- if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- buffer_append_string_len(b, CONST_STR_LEN("</span>byte/s</td></tr>\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN("</table>\n"));
-
-
- buffer_append_string_len(b, CONST_STR_LEN("<hr />\n<pre><b>legend</b>\n"));
- buffer_append_string_len(b, CONST_STR_LEN(". = connect, C = close, E = hard error\n"));
- buffer_append_string_len(b, CONST_STR_LEN("r = read, R = read-POST, W = write, h = handle-request\n"));
- buffer_append_string_len(b, CONST_STR_LEN("q = request-start, Q = request-end\n"));
- buffer_append_string_len(b, CONST_STR_LEN("s = response-start, S = response-end\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN("<strong><span id=\"connections\">"));
- buffer_append_long(b, srv->conns->used);
- buffer_append_string_len(b, CONST_STR_LEN("</span> connections</strong>\n"));
-
- for (j = 0; j < srv->conns->used; j++) {
- connection *c = srv->conns->ptr[j];
- const char *state = connection_get_short_state(c->state);
-
- 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</pre><hr />\n<h2>Connections</h2>\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN("<table class=\"status\" summary=\"Current connections\" id=\"clients\">\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 ip\">"));
-
- buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
-
- buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int bytes_read\">"));
-
- if (c->request.content_length != -1) {
- buffer_append_long(b, c->recv->bytes_in);
- buffer_append_string_len(b, CONST_STR_LEN("/"));
- buffer_append_long(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 bytes_written\">"));
-
- buffer_append_off_t(b, c->send_raw->bytes_out);
- buffer_append_string_len(b, CONST_STR_LEN("/"));
- buffer_append_off_t(b, c->send_raw->bytes_in);
-
- buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string state\">"));
-
- buffer_append_string(b, connection_get_state(c->state));
-
- buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int time\">"));
-
- buffer_append_long(b, srv->cur_ts - c->request_start);
-
- buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string host\">"));
-
- if (buffer_is_empty(c->server_name)) {
- buffer_append_string_buffer(b, c->uri.authority);
- }
- else {
- buffer_append_string_buffer(b, c->server_name);
- }
-
- buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string uri\">"));
-
- if (!buffer_is_empty(c->uri.path)) {
- buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
- }
-
- if (!buffer_is_empty(c->uri.query)) {
- buffer_append_string_len(b, CONST_STR_LEN("?"));
- buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.query), ENCODING_HTML);
- }
-
- if (!buffer_is_empty(c->request.orig_uri)) {
- buffer_append_string_len(b, CONST_STR_LEN(" ("));
- buffer_append_string_encoded(b, CONST_BUF_LEN(c->request.orig_uri), ENCODING_HTML);
- buffer_append_string_len(b, CONST_STR_LEN(")"));
- }
- buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string file\">"));
-
- 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"
-
- " </body>\n"
- "</html>\n"
- ));
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- con->send->bytes_in += b->used-1;
-
- 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;
- double avg;
- time_t ts;
- size_t j;
- unsigned int k;
- unsigned int l;
-
- b = chunkqueue_get_append_buffer(con->send);
-
- /* output total number of requests */
- buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: "));
- avg = p->abs_requests;
- buffer_append_long(b, avg);
- 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;
- buffer_append_long(b, avg);
- 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_long(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_long(b, srv->conns->used);
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
- buffer_append_long(b, srv->conns->size - srv->conns->used);
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- /* output traffic */
- buffer_append_string_len(b, CONST_STR_LEN("Traffic: "));
- avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
- buffer_append_long(b, avg);
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- /* output traffic 5s */
- buffer_append_string_len(b, CONST_STR_LEN("Traffic5s: "));
- for (j = 0, avg = 0; j < 5; j++) {
- avg += p->mod_5s_traffic_out[j];
- }
- avg /= 5;
- buffer_append_long(b, avg);
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- /* output scoreboard */
- buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: "));
- for (k = 0; k < srv->conns->used; k++) {
- connection *c = srv->conns->ptr[k];
- const char *state = connection_get_short_state(c->state);
- buffer_append_string_len(b, state, 1);
- }
- for (l = 0; l < srv->conns->size - srv->conns->used; l++) {
- buffer_append_string_len(b, CONST_STR_LEN("_"));
- }
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- /* set text/plain output */
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
- con->send->bytes_in += b->used-1;
-
- return 0;
-}
-
-static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
- buffer *b;
- size_t i;
- array *st = status_counter_get_array();
-
- UNUSED(p_d);
-
- if (0 == st->used) {
- /* we have nothing to send */
- con->http_status = 204;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
- }
-
- b = chunkqueue_get_append_buffer(con->send);
-
- 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_long(b, ((data_integer *)(st->data[ndx]))->value);
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
- }
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
-
- con->http_status = 200;
- con->send->bytes_in += b->used-1;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
-}
-
-
-static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
-
- if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
- mod_status_handle_server_status_text(srv, con, p_d);
- } else {
- mod_status_handle_server_status_html(srv, con, p_d);
- }
-
- con->http_status = 200;
- con->send->is_closed = 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, *tmp_buf = p->tmp_buf;
- size_t i;
- const fdevent_handler_info_t *handler;
- const network_backend_info_t *backend;
-
- b = chunkqueue_get_append_buffer(con->send);
-
- BUFFER_COPY_STRING_CONST(b,
- "<?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>" PACKAGE_NAME " " PACKAGE_VERSION "</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", fdevent_get_handler_info_by_type(srv->event_handler)->name);
- buffer_reset(tmp_buf);
- for (handler = fdevent_get_handlers(); handler->name; handler++) {
- if (handler->init) {
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("+ "));
- } else {
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("- "));
- }
-
- buffer_append_string(tmp_buf, handler->name);
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("<br />"));
- }
- mod_status_row_append(b, "Supported fd-Event-Handlers", tmp_buf->ptr);
-
- mod_status_row_append(b, "Network-Backend", network_get_backend_info_by_type(srv->network_backend)->name);
- buffer_reset(tmp_buf);
- for (backend = network_get_backends(); backend->name; backend++) {
- if (backend->write_handler) {
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("+ "));
- } else {
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("- "));
- }
-
- buffer_append_string(tmp_buf, backend->name);
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("<br />"));
- }
-#ifdef USE_MMAP
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("+ (mmap)<br />"));
-#else
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("- (mmap)<br />"));
-#endif
- mod_status_row_append(b, "Supported Network-Backends", tmp_buf->ptr);
-
- mod_status_header_append(b, "Config-File-Settings");
-
- buffer_reset(tmp_buf);
- for (i = 0; i < srv->plugins.used; i++) {
- plugin **ps = srv->plugins.ptr;
-
- plugin *pl = ps[i];
-
- if (i == 0) {
- buffer_copy_string_buffer(tmp_buf, pl->name);
- } else {
- buffer_append_string_len(tmp_buf, CONST_STR_LEN("<br />"));
- buffer_append_string_buffer(tmp_buf, pl->name);
- }
- }
-
- mod_status_row_append(b, "Loaded Modules", tmp_buf->ptr);
-
- buffer_append_string_len(b, CONST_STR_LEN(" </table>\n"));
-
- buffer_append_string_len(b, CONST_STR_LEN(
- " </body>\n"
- "</html>\n"
- ));
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
-
- con->http_status = 200;
- con->send->bytes_in += b->used-1;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
-}
-
-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_OPTION(status_url);
- PATCH_OPTION(config_url);
- PATCH_OPTION(sort);
- PATCH_OPTION(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_OPTION(status_url);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
- PATCH_OPTION(config_url);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
- PATCH_OPTION(sort);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
- PATCH_OPTION(statistics_url);
- }
- }
- }
-
- return 0;
-}
-
-static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
-
- mod_status_patch_connection(srv, con, p);
-
- if (!buffer_is_empty(p->conf.status_url) &&
- buffer_is_equal(p->conf.status_url, con->uri.path)) {
- return mod_status_handle_server_status(srv, con, p_d);
- } else if (!buffer_is_empty(p->conf.config_url) &&
- buffer_is_equal(p->conf.config_url, con->uri.path)) {
- return mod_status_handle_server_config(srv, con, p_d);
- } else if (!buffer_is_empty(p->conf.statistics_url) &&
- 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;
-}
-
-LI_EXPORT int mod_status_plugin_init(plugin *p);
-LI_EXPORT 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_response_done = mod_status_account;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c
deleted file mode 100644
index 2ef3b49f..00000000
--- a/src/mod_trigger_b4_dl.c
+++ /dev/null
@@ -1,589 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-#include "response.h"
-#include "inet_ntop_cache.h"
-
-#if defined(HAVE_GDBM_H)
-#include <gdbm.h>
-#endif
-
-#if defined(HAVE_PCRE_H)
-#include <pcre.h>
-#endif
-
-#if defined(HAVE_MEMCACHE_H)
-#include <memcache.h>
-#endif
-
-/**
- * this is a trigger_b4_dl for a lighttpd plugin
- *
- */
-
-/* plugin config for all request/connections */
-
-typedef struct {
- buffer *db_filename;
-
- buffer *trigger_url;
- buffer *download_url;
- buffer *deny_url;
-
- array *mc_hosts;
- buffer *mc_namespace;
-#if defined(HAVE_PCRE_H)
- pcre *trigger_regex;
- pcre *download_regex;
-#endif
-#if defined(HAVE_GDBM_H)
- GDBM_FILE db;
-#endif
-
-#if defined(HAVE_MEMCACHE_H)
- struct memcache *mc;
-#endif
-
- unsigned short trigger_timeout;
- unsigned short debug;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
-} plugin_data;
-
-/* init the plugin data */
-INIT_FUNC(mod_trigger_b4_dl_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_trigger_b4_dl_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- buffer_free(s->db_filename);
- buffer_free(s->download_url);
- buffer_free(s->trigger_url);
- buffer_free(s->deny_url);
-
- buffer_free(s->mc_namespace);
- array_free(s->mc_hosts);
-
-#if defined(HAVE_PCRE_H)
- if (s->trigger_regex) pcre_free(s->trigger_regex);
- if (s->download_regex) pcre_free(s->download_regex);
-#endif
-#if defined(HAVE_GDBM_H)
- if (s->db) gdbm_close(s->db);
-#endif
-#if defined(HAVE_MEMCACHE_H)
- if (s->mc) mc_free(s->mc);
-#endif
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-#if defined(HAVE_PCRE_H)
- const char *errptr;
- int erroff;
-#endif
-
- s = calloc(1, sizeof(plugin_config));
- s->db_filename = buffer_init();
- s->download_url = buffer_init();
- 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, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-#if defined(HAVE_GDBM_H)
- if (!buffer_is_empty(s->db_filename)) {
- if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "gdbm-open failed");
- return HANDLER_ERROR;
- }
- }
-#endif
-#if defined(HAVE_PCRE_H)
- if (!buffer_is_empty(s->download_url)) {
- if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
- 0, &errptr, &erroff, NULL))) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "compiling regex for download-url failed:",
- s->download_url, "pos:", erroff);
- return HANDLER_ERROR;
- }
- }
-
- if (!buffer_is_empty(s->trigger_url)) {
- if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
- 0, &errptr, &erroff, NULL))) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "compiling regex for trigger-url failed:",
- s->trigger_url, "pos:", erroff);
-
- return HANDLER_ERROR;
- }
- }
-#endif
-
- if (s->mc_hosts->used) {
-#if defined(HAVE_MEMCACHE_H)
- size_t k;
- s->mc = mc_new();
-
- for (k = 0; k < s->mc_hosts->used; k++) {
- data_string *ds = (data_string *)s->mc_hosts->data[k];
-
- if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "connection to host failed:",
- ds->value);
-
- 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
- }
-
-
-#if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
- log_error_write(srv, __FILE__, __LINE__, "s",
- "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
- return HANDLER_ERROR;
-#endif
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(db);
-#endif
-#if defined(HAVE_PCRE_H)
- PATCH_OPTION(download_regex);
- PATCH_OPTION(trigger_regex);
-#endif
- PATCH_OPTION(trigger_timeout);
- PATCH_OPTION(deny_url);
- PATCH_OPTION(mc_namespace);
- PATCH_OPTION(debug);
-#if defined(HAVE_MEMCACHE_H)
- PATCH_OPTION(mc);
-#endif
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
-#if defined(HAVE_PCRE_H)
- PATCH_OPTION(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_OPTION(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_OPTION(db);
-#endif
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
- PATCH_OPTION(trigger_timeout);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
- PATCH_OPTION(debug);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
- PATCH_OPTION(deny_url);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
- PATCH_OPTION(mc_namespace);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
-#if defined(HAVE_MEMCACHE_H)
- PATCH_OPTION(mc);
-#endif
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
- plugin_data *p = p_d;
- const char *remote_ip;
- data_string *ds;
-
-#if defined(HAVE_PCRE_H)
- int n;
-# define N 10
- int ovec[N * 3];
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_trigger_b4_dl_patch_connection(srv, con, p);
-
- if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
-
-# if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
- return HANDLER_GO_ON;
-# elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
- if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
- if (p->conf.db && p->conf.mc) {
- /* can't decide which one */
-
- return HANDLER_GO_ON;
- }
-# elif defined(HAVE_GDBM_H)
- if (!p->conf.db) return HANDLER_GO_ON;
-# else
- if (!p->conf.mc) return HANDLER_GO_ON;
-# endif
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("X-Forwarded-For")))) {
- /* X-Forwarded-For contains the ip behind the proxy */
-
- remote_ip = ds->value->ptr;
-
- /* memcache can't handle spaces */
- } else {
- remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- }
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
- }
-
- /* check if URL is a trigger -> insert IP into DB */
- if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
- if (n != PCRE_ERROR_NOMATCH) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "execution error while matching:", n);
-
- return HANDLER_ERROR;
- }
- } else {
-# 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(HAVE_MEMCACHE_H)
- if (p->conf.mc) {
- size_t i;
- buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
- buffer_append_string(p->tmp_buf, remote_ip);
-
- for (i = 0; i < p->tmp_buf->used - 1; i++) {
- if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
- }
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
- }
-
- if (0 != mc_set(p->conf.mc,
- CONST_BUF_LEN(p->tmp_buf),
- (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, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
- if (n != PCRE_ERROR_NOMATCH) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "execution error while matching: ", n);
- return HANDLER_ERROR;
- }
- } else {
- /* 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 */
-
- response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
-
- con->http_status = 307;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
- }
-
- last_hit = *(time_t *)(val.dptr);
-
- free(val.dptr);
-
- if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
- /* found, but timeout, redirect */
-
- response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
- con->http_status = 307;
- con->send->is_closed = 1;
-
- if (p->conf.db) {
- if (0 != gdbm_delete(p->conf.db, key)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "delete failed");
- }
- }
-
- return HANDLER_FINISHED;
- }
-
- val.dptr = (char *)&(srv->cur_ts);
- val.dsize = sizeof(srv->cur_ts);
-
- if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "insert failed");
- }
- }
-# endif
-
-# if defined(HAVE_MEMCACHE_H)
- if (p->conf.mc) {
- void *r;
- size_t i;
-
- buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
- buffer_append_string(p->tmp_buf, remote_ip);
-
- for (i = 0; i < p->tmp_buf->used - 1; i++) {
- if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
- }
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
- }
-
- /**
- *
- * memcached is do expiration for us, as long as we can fetch it every thing is ok
- * and the timestamp is updated
- *
- */
- if (NULL == (r = mc_aget(p->conf.mc,
- CONST_BUF_LEN(p->tmp_buf)
- ))) {
-
- response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
-
- con->http_status = 307;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
- }
-
- free(r);
-
- /* set a new timeout */
- if (0 != mc_set(p->conf.mc,
- CONST_BUF_LEN(p->tmp_buf),
- (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
- p->conf.trigger_timeout, 0)) {
- 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);
-
- last_hit = *(time_t *)(val.dptr);
-
- free(val.dptr);
-
- if (srv->cur_ts - last_hit > s->trigger_timeout) {
- gdbm_delete(s->db, key);
- }
-
- okey = key;
- }
- if (okey.dptr) free(okey.dptr);
-
- /* reorg once a day */
- if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
- }
- return HANDLER_GO_ON;
-}
-#endif
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_trigger_b4_dl_plugin_init(plugin *p);
-LI_EXPORT 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/src/mod_uploadprogress.c b/src/mod_uploadprogress.c
deleted file mode 100644
index 56423680..00000000
--- a/src/mod_uploadprogress.c
+++ /dev/null
@@ -1,638 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "response.h"
-#include "stat_cache.h"
-
-#define CONFIG_UPLOAD_PROGRESS_URL "upload-progress.progress-url"
-#define CONFIG_UPLOAD_PROGRESS_TIMEOUT "upload-progress.remove-timeout"
-#define CONFIG_UPLOAD_PROGRESS_DEBUG "upload-progress.debug"
-
-/**
- * uploadprogress for lighttpd
- *
- * Initial: Jan Kneschke <jan@kneschke.de>
- * Timeout+Status addon: Bjoern Kalkbrenner <terminar@cyberphoria.org> [20070112]
- *
- * the timeout is used to keep in the status information intact even if the parent
- * connection is gone already
- */
-
-typedef struct {
- buffer *tracking_id;
- connection *con;
-
- time_t timeout;
- int status;
- off_t size;
-} 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;
- unsigned short debug;
- unsigned short remove_timeout;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
-
- connection_map *con_map;
-
- buffer *tmp_buf; /** used as temporary buffer for extracting the tracking id */
-
- 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->tracking_id) {
- buffer_free(cme->tracking_id);
- }
- free(cme);
- }
-
- free(cm);
-}
-
-static connection_map_entry *connection_map_insert(connection_map *cm, buffer *tracking_id, connection *con) {
- 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->tracking_id = buffer_init();
- }
- cme->timeout = 0;
- cme->status = 0;
- buffer_copy_string_buffer(cme->tracking_id, tracking_id);
- cme->con = con;
-
- cm->ptr[cm->used++] = cme;
-
- return cme;
-}
-
-static connection_map_entry *connection_map_get_connection_entry(connection_map *cm, buffer *tracking_id) {
- size_t i;
-
- for (i = 0; i < cm->used; i++) {
- connection_map_entry *cme = cm->ptr[i];
-
- if (buffer_is_equal(cme->tracking_id, tracking_id)) {
- /* found connection */
- return cme;
- }
- }
- return NULL;
-}
-
-static void connection_map_remove_connection(connection_map *cm, size_t i) {
- connection_map_entry *cme = cm->ptr[i];
-
- buffer_reset(cme->tracking_id);
- cme->timeout=0;
- cme->status=0;
-
- cm->used--;
-
- /* swap positions with the last entry */
- if (cm->used) {
- cm->ptr[i] = cm->ptr[cm->used];
- cm->ptr[cm->used] = cme;
- }
-}
-
-/**
- * remove dead tracking IDs
- *
- * uploadprogress.remove-timeout sets a grace-period in which the
- * connection status is still known even of the connection is already
- * being removed
- *
- */
-static void connection_map_clear_timeout_connections(connection_map *cm) {
- size_t i;
- time_t now_t = time(NULL);
-
- for (i = 0; i < cm->used; i++) {
- connection_map_entry *cme = cm->ptr[i];
-
- if (cme->timeout != 0 && cme->timeout < now_t) {
- /* found connection */
- connection_map_remove_connection(cm, i);
- }
- }
-}
-
-/**
- * extract the tracking-id from the parameters
- *
- * for POST requests it is part of the request headers
- * for GET requests ... too
- */
-static buffer *get_tracking_id(plugin_data *p, connection *con) {
- data_string *ds;
- buffer *b = NULL;
- char *qstr=NULL;
- size_t i;
-
- /* the request has to contain a 32byte ID */
- if (NULL == (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("X-Progress-ID")))) {
- char *amp = NULL;
-
- /* perhaps the POST request is using the querystring to pass the X-Progress-ID */
- if (buffer_is_empty(con->uri.query)) {
- /*
- * con->uri.query will not be parsed out if a 413 error happens
- */
- if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
- /** extract query string from request.uri */
- buffer_copy_string(con->uri.query, qstr + 1);
- } else {
- return NULL;
- }
- }
-
- /** split the query-string and extract the X-Progress-ID */
- do {
- char *eq = NULL;
- char *start = amp ? amp + 1 : con->uri.query->ptr;
-
- amp = strchr(start, '&');
-
- /* check the string between start and amp for = */
-
- if (amp) {
- buffer_copy_string_len(p->tmp_buf, start, amp - start);
- } else {
- buffer_copy_string(p->tmp_buf, start);
- }
-
- eq = strchr(p->tmp_buf->ptr, '=');
-
- if (eq) {
- *eq = '\0';
-
- if (0 == strcmp(p->tmp_buf->ptr, "X-Progress-ID")) {
- size_t key_len = sizeof("X-Progress-ID") - 1;
- size_t var_len = p->tmp_buf->used - 1;
- /* found */
-
- buffer_copy_string_len(p->tmp_buf, start + key_len + 1, var_len - key_len - 1);
-
- b = p->tmp_buf;
-
- break;
- }
- }
- } while (amp);
-
- if (!b) return NULL;
- } else {
- /* request header was found, use it */
- b = ds->value;
- }
-
- if (b->used != 32 + 1) {
- if (p->conf.debug) ERROR("the Progress-ID has to be 32 characters long, got %zd characters", b->used - 1);
- return NULL;
- }
-
- for (i = 0; i < b->used - 1; i++) {
- char c = b->ptr[i];
-
- if (!light_isxdigit(c)) {
- if (p->conf.debug) ERROR("only hex-digits are allowed (0-9 + a-f): (ascii: %d)", c);
- return NULL;
- }
- }
-
- return b;
-}
-
-/* init the plugin data */
-INIT_FUNC(mod_uploadprogress_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->con_map = connection_map_init();
- p->tmp_buf = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_uploadprogress_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];
-
- buffer_free(s->progress_url);
- s->remove_timeout=0;
-
- free(s);
- }
- free(p->config_storage);
- }
-
- connection_map_free(p->con_map);
- buffer_free(p->tmp_buf);
-
- 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[] = {
- { CONFIG_UPLOAD_PROGRESS_URL, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { CONFIG_UPLOAD_PROGRESS_TIMEOUT, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { CONFIG_UPLOAD_PROGRESS_DEBUG, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->progress_url = buffer_init();
- s->remove_timeout = 60;
- s->debug = 0;
-
- cv[0].destination = s->progress_url;
- cv[1].destination = &(s->remove_timeout);
- cv[2].destination = &(s->debug);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-static int mod_uploadprogress_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH_OPTION(progress_url);
- PATCH_OPTION(remove_timeout);
- PATCH_OPTION(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(CONFIG_UPLOAD_PROGRESS_URL))) {
- PATCH_OPTION(progress_url);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_UPLOAD_PROGRESS_TIMEOUT))) {
- PATCH_OPTION(remove_timeout);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_UPLOAD_PROGRESS_DEBUG))) {
- PATCH_OPTION(debug);
- }
- }
- }
-
- return 0;
-}
-
-/**
- *
- * 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;
- buffer *tracking_id;
- buffer *b;
- connection_map_entry *post_con_entry = NULL;
- connection_map_entry *map_con_entry = NULL;
-
- if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
-
- mod_uploadprogress_patch_connection(srv, con, p);
-
- /* no progress URL set, ignore request */
- if (buffer_is_empty(p->conf.progress_url)) return HANDLER_GO_ON;
-
- switch(con->request.http_method) {
- case HTTP_METHOD_POST:
- /**
- * a POST request is the UPLOAD itself
- *
- * get the unique tracker id
- */
- if (NULL == (tracking_id = get_tracking_id(p, con))) {
- return HANDLER_GO_ON;
- }
-
- if (NULL == (map_con_entry = connection_map_get_connection_entry(p->con_map, tracking_id))) {
- connection_map_insert(p->con_map, tracking_id, con);
-
- if (p->conf.debug) TRACE("POST: connection is new, registered: %s", SAFE_BUF_STR(tracking_id));
- } else {
- map_con_entry->timeout = 0;
- map_con_entry->status = 0;
-
- if (p->conf.debug) TRACE("POST: connection is known, id: %s", SAFE_BUF_STR(tracking_id));
- }
-
- return HANDLER_GO_ON;
- case HTTP_METHOD_GET:
- /**
- * the status request for the current connection
- */
- if (p->conf.debug) TRACE("(uploadprogress) urls %s == %s", SAFE_BUF_STR(con->uri.path), SAFE_BUF_STR(p->conf.progress_url));
-
- if (!buffer_is_equal(con->uri.path, p->conf.progress_url)) {
- return HANDLER_GO_ON;
- }
-
- /* get the tracker id */
- if (NULL == (tracking_id = get_tracking_id(p, con))) {
- return HANDLER_GO_ON;
- }
-
- buffer_reset(con->physical.path);
-
- con->file_started = 1;
- con->http_status = 200;
- con->send->is_closed = 1;
-
- /* send JSON content */
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/javascript"));
-
- /* just an attempt the force the IE/proxies to NOT cache the request */
- response_header_overwrite(srv, con, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache"));
- response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT"));
- response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"),
- CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0"));
-
- b = chunkqueue_get_append_buffer(con->send);
-
- /* get the connection */
- if (NULL == (post_con_entry = connection_map_get_connection_entry(p->con_map, tracking_id))) {
- /**
- * looks like we don't know the tracking id yet, GET and POST out of sync ? */
- buffer_append_string_len(b, CONST_STR_LEN("new Object({ 'state' : 'starting' })\r\n"));
- con->send->bytes_in += b->used-1;
-
- if (p->conf.debug) TRACE("connection unknown: %s, sending: %s", SAFE_BUF_STR(tracking_id), SAFE_BUF_STR(b));
-
- return HANDLER_FINISHED;
- }
-
- buffer_copy_string_len(b, CONST_STR_LEN("new Object({ 'state' : "));
-
- if (post_con_entry->status == 413) {
- /* the upload was too large */
- buffer_append_string_len(b, CONST_STR_LEN("'error', 'status' : 413"));
- } else if (post_con_entry->con == NULL) {
- /* the connection is already gone */
- buffer_append_string_len(b, CONST_STR_LEN("'done', 'size' : "));
- buffer_append_off_t(b, post_con_entry->size);
- } else {
- /* the upload is already done, but the connection might be still open */
- buffer_append_string(b, post_con_entry->con->recv->is_closed ? "'done'" : "'uploading'");
- buffer_append_string_len(b, CONST_STR_LEN(", 'received' : "));
- buffer_append_off_t(b, post_con_entry->con->recv->bytes_in);
- buffer_append_string_len(b, CONST_STR_LEN(", 'size' : "));
- buffer_append_off_t(b, post_con_entry->con->request.content_length == -1 ? 0 : post_con_entry->con->request.content_length);
- }
- buffer_append_string_len(b, CONST_STR_LEN("})\r\n"));
- con->send->bytes_in += b->used-1;
-
- if (p->conf.debug) TRACE("connection is known: %s, sending: %s", SAFE_BUF_STR(tracking_id), SAFE_BUF_STR(b));
-
- return HANDLER_FINISHED;
- default:
- break;
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * check if request parser sent 413 for our POST request
- */
-URIHANDLER_FUNC(mod_uploadprogress_response_header) {
- plugin_data *p = p_d;
-
- buffer *tracking_id;
- connection_map_entry *map_con_entry = NULL;
-
- UNUSED(srv);
-
- /*
- * we only want to process an 413 (Bad length) error for the upload (POST request)
- */
- if (con->request.http_method != HTTP_METHOD_POST || con->http_status != 413) {
- return HANDLER_GO_ON;
- }
-
- if (p->conf.debug) {
- TRACE("response_header: con=%p, http_method=%d, http_status=%d", (void*) con,
- con->request.http_method, con->http_status);
- }
-
- /* get the tracker id */
- if (NULL == (tracking_id = get_tracking_id(p, con))) {
- return HANDLER_GO_ON;
- }
-
- if (NULL == (map_con_entry = connection_map_get_connection_entry(p->con_map, tracking_id))) {
- /**
- * in case the request parser meant the request was too large the URI handler won't
- * get called. Insert the connection mapping here
- */
- if (NULL == (map_con_entry = connection_map_insert(p->con_map, tracking_id, con))) {
- return HANDLER_GO_ON;
- }
- }
-
- /* ok, found our entries, setting 413 here for status */
- map_con_entry->status = 413;
-
- return HANDLER_GO_ON;
-}
-
-/**
- * remove the parent connection from the connection mapping
- * when it got closed
- *
- * keep the mapping active for a while to send a valid final status
- */
-REQUESTDONE_FUNC(mod_uploadprogress_request_done) {
- plugin_data *p = p_d;
- buffer *tracking_id;
- connection_map_entry *cm = NULL;
-
- UNUSED(srv);
-
- if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
-
- /*
- * only need to handle the upload request.
- */
- if (con->request.http_method != HTTP_METHOD_POST) {
- return HANDLER_GO_ON;
- }
-
- if (NULL == (tracking_id = get_tracking_id(p, con))) {
- return HANDLER_GO_ON;
- }
-
- if (p->conf.debug) {
- TRACE("upload is done, moving tracking-id to backlog: tracking-id=%s, http_status=%d",
- SAFE_BUF_STR(tracking_id),
- con->http_status);
- }
-
- /*
- * set timeout on the upload's connection_map_entry.
- */
- if (NULL == (cm = connection_map_get_connection_entry(p->con_map, tracking_id))) {
- if (p->conf.debug) {
- TRACE("tracking ID %s not found, can't set timeout", SAFE_BUF_STR(tracking_id));
- }
- return HANDLER_GO_ON;
- }
-
- /* save request size to be able to report it even when cm->con == NULL */
- cm->size = con->request.content_length;
-
- cm->timeout = time(NULL) + p->conf.remove_timeout;
- cm->con = NULL; /* con becomes invalid very soon */
-
- return HANDLER_GO_ON;
-}
-
-/**
- * remove dead connections once in while
- */
-TRIGGER_FUNC(mod_uploadprogress_trigger) {
- plugin_data *p = p_d;
-
- if ((srv->cur_ts % 10) != 0) return HANDLER_GO_ON;
-
- connection_map_clear_timeout_connections(p->con_map);
-
- return HANDLER_GO_ON;
-}
-
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_uploadprogress_plugin_init(plugin *p);
-LI_EXPORT 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->handle_response_done = mod_uploadprogress_request_done;
- p->set_defaults = mod_uploadprogress_set_defaults;
- p->cleanup = mod_uploadprogress_free;
- p->handle_trigger = mod_uploadprogress_trigger;
- p->handle_response_header = mod_uploadprogress_response_header;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_userdir.c b/src/mod_userdir.c
deleted file mode 100644
index 8ee91295..00000000
--- a/src/mod_userdir.c
+++ /dev/null
@@ -1,325 +0,0 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "response.h"
-
-#include "plugin.h"
-#include "sys-files.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;
-} 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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->username = buffer_init();
- p->temp_path = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_userdir_free) {
- plugin_data *p = p_d;
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- array_free(s->include_user);
- array_free(s->exclude_user);
- buffer_free(s->path);
- buffer_free(s->basepath);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->username);
- buffer_free(p->temp_path);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->exclude_user = array_init();
- s->include_user = array_init();
- s->path = buffer_init();
- s->basepath = buffer_init();
- s->letterhomes = 0;
-
- cv[0].destination = s->path;
- cv[1].destination = s->exclude_user;
- cv[2].destination = s->include_user;
- cv[3].destination = s->basepath;
- cv[4].destination = &(s->letterhomes);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(path);
- PATCH_OPTION(exclude_user);
- PATCH_OPTION(include_user);
- PATCH_OPTION(basepath);
- PATCH_OPTION(letterhomes);
-
- /* skip the first, the global context */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
- PATCH_OPTION(path);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
- PATCH_OPTION(exclude_user);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
- PATCH_OPTION(include_user);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
- PATCH_OPTION(basepath);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.letterhomes"))) {
- PATCH_OPTION(letterhomes);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_userdir_docroot_handler) {
- plugin_data *p = p_d;
- int uri_len;
- size_t k;
- char *rel_url;
-#ifdef HAVE_PWD_H
- struct passwd *pwd = NULL;
-#endif
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_userdir_patch_connection(srv, con, p);
-
- uri_len = con->uri.path->used - 1;
-
- /* /~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_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 */
-
- if (buffer_is_empty(p->conf.basepath)) {
-#ifdef HAVE_PWD_H
- buffer_copy_string(p->temp_path, pwd->pw_dir);
-#endif
- } else {
- char *cp;
- /* check if the username is valid
- * a request for /~../ should lead to a directory traversal
- * limiting to [-_a-z0-9.] should fix it */
-
- for (cp = p->username->ptr; *cp; cp++) {
- char c = *cp;
-
- if (!(c == '-' ||
- c == '_' ||
- c == '.' ||
- (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9'))) {
-
- return HANDLER_GO_ON;
- }
- }
- if (con->conf.force_lowercase_filenames) {
- buffer_to_lower(p->username);
- }
-
- buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
- PATHNAME_APPEND_SLASH(p->temp_path);
- if (p->conf.letterhomes) {
- buffer_append_string_len(p->temp_path, p->username->ptr, 1);
- PATHNAME_APPEND_SLASH(p->temp_path);
- }
- buffer_append_string_buffer(p->temp_path, p->username);
- }
- PATHNAME_APPEND_SLASH(p->temp_path);
- buffer_append_string_buffer(p->temp_path, p->conf.path);
-
- if (buffer_is_empty(p->conf.basepath)) {
- struct stat st;
- int ret;
-
- ret = stat(p->temp_path->ptr, &st);
- if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
- return HANDLER_GO_ON;
- }
- }
-
- /* the physical rel_path is basically the same as uri.path;
- * but it is converted to lowercase in case of force_lowercase_filenames and some special handling
- * for trailing '.', ' ' and '/' on windows
- * we assume that no docroot/physical handler changed this
- * (docroot should only set the docroot/server name, phyiscal should only change the phyiscal.path;
- * the exception mod_secure_download doesn't work with userdir anyway)
- */
- PATHNAME_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_string_buffer(con->physical.path, p->temp_path);
-
- buffer_reset(p->temp_path);
-
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_userdir_plugin_init(plugin *p);
-LI_EXPORT int mod_userdir_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("userdir");
-
- p->init = mod_userdir_init;
- p->handle_physical = mod_userdir_docroot_handler;
- p->set_defaults = mod_userdir_set_defaults;
- p->cleanup = mod_userdir_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c
deleted file mode 100644
index b0275107..00000000
--- a/src/mod_usertrack.c
+++ /dev/null
@@ -1,277 +0,0 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-
-typedef li_MD5_CTX MD5_CTX;
-#define MD5_Init li_MD5_Init
-#define MD5_Update li_MD5_Update
-#define MD5_Final li_MD5_Final
-
-#endif
-
-/* plugin config for all request/connections */
-
-typedef struct {
- buffer *cookie_name;
- buffer *cookie_domain;
- unsigned short 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;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_usertrack_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- buffer_free(s->cookie_name);
- buffer_free(s->cookie_domain);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
-
- { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->cookie_name = buffer_init();
- s->cookie_domain = buffer_init();
- s->cookie_max_age = 0;
-
- cv[0].destination = s->cookie_name;
- cv[1].destination = &(s->cookie_max_age);
- cv[2].destination = s->cookie_domain;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (buffer_is_empty(s->cookie_name)) {
- buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
- } else {
- size_t j;
- for (j = 0; j < s->cookie_name->used - 1; j++) {
- char c = s->cookie_name->ptr[j] | 32;
- if (c < 'a' || c > 'z') {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid character in usertrack.cookie-name:",
- s->cookie_name);
-
- return HANDLER_ERROR;
- }
- }
- }
-
- if (!buffer_is_empty(s->cookie_domain)) {
- size_t j;
- for (j = 0; j < s->cookie_domain->used - 1; j++) {
- char c = s->cookie_domain->ptr[j];
- if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid character in usertrack.cookie-domain:",
- s->cookie_domain);
-
- return HANDLER_ERROR;
- }
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-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_OPTION(cookie_name);
- PATCH_OPTION(cookie_domain);
- PATCH_OPTION(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_OPTION(cookie_name);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
- PATCH_OPTION(cookie_max_age);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
- PATCH_OPTION(cookie_domain);
- }
- }
- }
-
- return 0;
-}
-
-URIHANDLER_FUNC(mod_usertrack_uri_handler) {
- plugin_data *p = p_d;
- data_string *ds;
- unsigned char h[16];
- MD5_CTX Md5Ctx;
- char hh[32];
-
- if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
- mod_usertrack_patch_connection(srv, con, p);
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, 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(ds->value->ptr, p->conf.cookie_name->ptr))) {
- char *nc;
-
- /* skip WS */
- for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
-
- if (*nc == '=') {
- /* ok, found the key of our own cookie */
-
- if (strlen(nc) > 32) {
- /* i'm lazy */
- return HANDLER_GO_ON;
- }
- }
- }
- }
-
- /* set a cookie */
- if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
- ds = data_response_init();
- }
- buffer_copy_string_len(ds->key, CONST_STR_LEN("Set-Cookie"));
- buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
- buffer_append_string_len(ds->value, CONST_STR_LEN("="));
-
-
- /* taken from mod_auth.c */
-
- /* generate shared-secret */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
-
- /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
- LI_ltostr(hh, srv->cur_ts);
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
- MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
- LI_ltostr(hh, rand());
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
-
- MD5_Final(h, &Md5Ctx);
-
- buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
- buffer_append_string_len(ds->value, CONST_STR_LEN("; Path=/"));
- buffer_append_string_len(ds->value, CONST_STR_LEN("; Version=1"));
-
- if (!buffer_is_empty(p->conf.cookie_domain)) {
- buffer_append_string_len(ds->value, CONST_STR_LEN("; Domain="));
- buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
- }
-
- if (p->conf.cookie_max_age) {
- buffer_append_string_len(ds->value, CONST_STR_LEN("; max-age="));
- buffer_append_long(ds->value, p->conf.cookie_max_age);
- }
-
- array_insert_unique(con->response.headers, (data_unset *)ds);
-
- return HANDLER_GO_ON;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_usertrack_plugin_init(plugin *p);
-LI_EXPORT int mod_usertrack_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("usertrack");
-
- p->init = mod_usertrack_init;
- p->handle_uri_clean = mod_usertrack_uri_handler;
- p->set_defaults = mod_usertrack_set_defaults;
- p->cleanup = mod_usertrack_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/mod_webdav.c b/src/mod_webdav.c
deleted file mode 100644
index 49de74a5..00000000
--- a/src/mod_webdav.c
+++ /dev/null
@@ -1,2688 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <assert.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#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_H)
-#define USE_LOCKS
-#include <uuid/uuid.h>
-#endif
-
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-
-#include "plugin.h"
-
-#include "stream.h"
-#include "stat_cache.h"
-
-#include "sys-files.h"
-#include "sys-mmap.h"
-#include "sys-strings.h"
-
-/**
- * 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
- *
- */
-#ifdef _WIN32
-#define WEBDAV_FILE_MODE _S_IREAD | _S_IWRITE
-#define WEBDAV_DIR_MODE _S_IREAD | _S_IWRITE
-#else
-#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
-#endif
-
-/* 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;
-
-/* init the plugin data */
-INIT_FUNC(mod_webdav_init) {
- plugin_data *p;
-
- UNUSED(srv);
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- p->uri.scheme = buffer_init();
- p->uri.path_raw = buffer_init();
- p->uri.path = buffer_init();
- p->uri.authority = buffer_init();
-
- p->physical.path = buffer_init();
- p->physical.rel_path = buffer_init();
- p->physical.doc_root = buffer_init();
- p->physical.basedir = buffer_init();
-
- return p;
-}
-
-/* detroy the plugin data */
-FREE_FUNC(mod_webdav_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
-
- buffer_free(s->sqlite_db_name);
-#ifdef USE_PROPPATCH
- if (s->sql) {
- 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_raw);
- buffer_free(p->uri.path);
- buffer_free(p->uri.authority);
-
- buffer_free(p->physical.path);
- buffer_free(p->physical.rel_path);
- buffer_free(p->physical.doc_root);
- buffer_free(p->physical.basedir);
-
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-/* 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(specific_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->sqlite_db_name = buffer_init();
-
- cv[0].destination = &(s->enabled);
- cv[1].destination = &(s->is_readonly);
- cv[2].destination = s->sqlite_db_name;
- cv[3].destination = &(s->log_xml);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_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 properties ("
- " resource TEXT NOT NULL,"
- " prop TEXT NOT NULL,"
- " ns TEXT NOT NULL,"
- " value TEXT NOT NULL,"
- " PRIMARY KEY(resource, prop, ns))",
- NULL, NULL, &err)) {
-
- if (0 != strcmp(err, "table properties already exists")) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
- sqlite3_free(err);
-
- return HANDLER_ERROR;
- }
- sqlite3_free(err);
- }
-
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
- &(s->stmt_select_prop), &next_stmt)) {
- /* prepare failed */
-
- 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 properties SET resource = ? WHERE resource = ?"),
- &(s->stmt_move_uri), &next_stmt)) {
- /* prepare failed */
- log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
-
- return HANDLER_ERROR;
- }
-
- /* LOCKS */
-
- if (SQLITE_OK != sqlite3_exec(s->sql,
- "CREATE TABLE locks ("
- " locktoken TEXT NOT NULL,"
- " resource TEXT NOT NULL,"
- " 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("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 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 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;
-}
-
-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;
-
- if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
-
- mod_webdav_patch_connection(srv, con, p);
-
- if (!p->conf.enabled) {
- if (con->conf.log_request_handling) {
- TRACE("-- skipping %s in mod_webdav, not enabled",
- SAFE_BUF_STR(con->uri.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- handling request in mod_webdav: %s",
- SAFE_BUF_STR(con->uri.path));
- }
-
- 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 */
- response_header_overwrite(srv, con, CONST_STR_LEN("DAV"), CONST_STR_LEN("1,2"));
- response_header_overwrite(srv, con, CONST_STR_LEN("MS-Author-Via"), CONST_STR_LEN("DAV"));
-
- if (p->conf.is_readonly) {
- response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
- } else {
- response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
- }
-
- if (con->conf.log_request_handling) {
- TRACE("sending OPTIONS response for: %s",
- SAFE_BUF_STR(con->uri.path));
- }
-
- break;
- default:
- break;
- }
-
- return HANDLER_GO_ON;
-}
-
-PHYSICALPATH_FUNC(mod_webdav_physical_handler) {
- plugin_data *p = p_d;
-
- if (con->mode != DIRECT) return HANDLER_GO_ON;
-
- mod_webdav_patch_connection(srv, con, p);
-
- if (!p->conf.enabled) {
- if (con->conf.log_request_handling) {
- TRACE("-- skipping %s in mod_webdav, not enabled",
- SAFE_BUF_STR(con->uri.path));
- }
-
- return HANDLER_GO_ON;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- handling request in mod_webdav: %s",
- SAFE_BUF_STR(con->uri.path));
- }
-
- /* physical path is setup */
- if (con->physical.path->used == 0) {
- TRACE("-- missing con->physical.path: %s",
- SAFE_BUF_STR(con->uri.path));
- return HANDLER_GO_ON;
- }
-
- switch (con->request.http_method) {
- case HTTP_METHOD_OPTIONS:
- /* already handled */
- break;
- case HTTP_METHOD_PROPFIND:
- case HTTP_METHOD_MKCOL:
- case HTTP_METHOD_DELETE:
- case HTTP_METHOD_PUT:
- case HTTP_METHOD_MOVE:
- case HTTP_METHOD_COPY:
- case HTTP_METHOD_PROPPATCH:
- case HTTP_METHOD_LOCK:
- case HTTP_METHOD_UNLOCK:
- con->mode = p->id;
- return HANDLER_FINISHED;
- default: break;
- }
-
- 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 "));
- }
- buffer_append_long(b, status);
- buffer_append_string_len(b, CONST_STR_LEN(" "));
- buffer_append_string(b, get_http_status_name(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, plugin_data *p, physical *dst, buffer *b) {
- int status = 0;
-
- UNUSED(p);
-
- /* 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 = p->conf.stmt_delete_uri;
-
- if (stmt) {
- sqlite3_reset(stmt);
-
- /* bind the values to the insert */
-
- sqlite3_bind_text(stmt, 1,
- dst->rel_path->ptr,
- dst->rel_path->used - 1,
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- /* */
- }
- }
-#endif
- }
-
- return (status != 0);
-}
-
-static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, 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;
- int status = 0;
-
- 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 */
- }
-
- buffer_copy_string_buffer(d.path, dst->path);
- PATHNAME_APPEND_SLASH(d.path);
- buffer_append_string(d.path, de->d_name);
-
- buffer_copy_string_buffer(d.rel_path, dst->rel_path);
- PATHNAME_APPEND_SLASH(d.rel_path);
- buffer_append_string(d.rel_path, de->d_name);
-
- /* 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, p, &d, b);
-
- /* try to unlink it */
- if (-1 == rmdir(d.path->ptr)) {
- 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 = p->conf.stmt_delete_uri;
-
- status = 0;
-
- if (stmt) {
- sqlite3_reset(stmt);
-
- /* bind the values to the insert */
-
- sqlite3_bind_text(stmt, 1,
- d.rel_path->ptr,
- d.rel_path->used - 1,
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- /* */
- }
- }
-#endif
- }
- } else {
- have_multi_status = webdav_delete_file(srv, con, p, &d, b);
- }
- }
- closedir(dir);
-
- buffer_free(d.path);
- buffer_free(d.rel_path);
- }
-
- return have_multi_status;
-}
-
-static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) {
- stream s;
- int status = 0, ofd;
-
- UNUSED(con);
- UNUSED(srv);
- UNUSED(p);
-
- if (stream_open(&s, src->path)) {
- return 403;
- }
-
- if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 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;
- }
- stream_close(&s);
- return status;
- }
-
- if (-1 == write(ofd, s.start, s.size)) {
- switch(errno) {
- case ENOSPC:
- status = 507;
- break;
- default:
- status = 403;
- break;
- }
- }
-
- stream_close(&s);
- close(ofd);
-
-#ifdef USE_PROPPATCH
- if (0 == status) {
- /* copy worked fine, copy connected properties */
- sqlite3_stmt *stmt = p->conf.stmt_copy_uri;
-
- if (stmt) {
- sqlite3_reset(stmt);
-
- /* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- dst->rel_path->ptr,
- dst->rel_path->used - 1,
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 2,
- src->rel_path->ptr,
- src->rel_path->used - 1,
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- /* */
- }
- }
- }
-#endif
- return status;
-}
-
-static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, 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;
-
- if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
- continue;
- }
-
- buffer_copy_string_buffer(s.path, src->path);
- PATHNAME_APPEND_SLASH(s.path);
- buffer_append_string(s.path, de->d_name);
-
- buffer_copy_string_buffer(d.path, dst->path);
- PATHNAME_APPEND_SLASH(d.path);
- buffer_append_string(d.path, de->d_name);
-
- buffer_copy_string_buffer(s.rel_path, src->rel_path);
- PATHNAME_APPEND_SLASH(s.rel_path);
- buffer_append_string(s.rel_path, de->d_name);
-
- buffer_copy_string_buffer(d.rel_path, dst->rel_path);
- PATHNAME_APPEND_SLASH(d.rel_path);
- buffer_append_string(d.rel_path, de->d_name);
-
- 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 = p->conf.stmt_copy_uri;
-
- if (0 != (status = webdav_copy_dir(srv, con, p, &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,
- dst->rel_path->ptr,
- dst->rel_path->used - 1,
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 2,
- src->rel_path->ptr,
- src->rel_path->used - 1,
- 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, p, &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;
-}
-
-static int webdav_get_live_property(server *srv, connection *con, plugin_data *p, physical *dst, char *prop_name, buffer *b) {
- stat_cache_entry *sce = NULL;
- int found = 0;
-
- UNUSED(p);
-
- 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";
- size_t k;
-
- 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>"));
- 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)) {
- for (k = 0; k < con->conf.mimetypes->used; k++) {
- data_string *ds = (data_string *)con->conf.mimetypes->data[k];
-
- if (ds->key->used == 0) continue;
-
- if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
- buffer_append_string_len(b,CONST_STR_LEN("<D:getcontenttype>"));
- buffer_append_string_buffer(b, ds->value);
- buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
- found = 1;
-
- break;
- }
- }
- }
- } 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_off_t(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;
- }
- }
-
- return found ? 0 : -1;
-}
-
-static int webdav_get_property(server *srv, connection *con, plugin_data *p, 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, p, dst, prop_name, b);
- } else {
- int found = 0;
-#ifdef USE_PROPPATCH
- sqlite3_stmt *stmt = p->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,
- dst->rel_path->ptr,
- dst->rel_path->used - 1,
- 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;
-
-webdav_property live_properties[] = {
- { "DAV:", "creationdate" },
- { "DAV:", "displayname" },
- { "DAV:", "getcontentlanguage" },
- { "DAV:", "getcontentlength" },
- { "DAV:", "getcontenttype" },
- { "DAV:", "getetag" },
- { "DAV:", "getlastmodified" },
- { "DAV:", "resourcetype" },
- { "DAV:", "lockdiscovery" },
- { "DAV:", "source" },
- { "DAV:", "supportedlock" },
-
- { NULL, NULL }
-};
-
-typedef struct {
- webdav_property **ptr;
-
- size_t used;
- size_t size;
-} webdav_properties;
-
-static int webdav_get_props(server *srv, connection *con, plugin_data *p, physical *dst, webdav_properties *props, buffer *b_200, buffer *b_404) {
- size_t i;
-
- if (props) {
- for (i = 0; i < props->used; i++) {
- webdav_property *prop;
-
- prop = props->ptr[i];
-
- if (0 != webdav_get_property(srv, con, p,
- dst, prop->prop, prop->ns, b_200)) {
- webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
- }
- }
- } else {
- for (i = 0; live_properties[i].prop; i++) {
- /* a local 'live' property */
- webdav_get_live_property(srv, con, p, dst, live_properties[i].prop, b_200);
- }
- }
-
- return 0;
-}
-
-#ifdef USE_PROPPATCH
-static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p, chunkqueue *cq, xmlDoc **ret_xml) {
- xmlParserCtxtPtr ctxt;
- xmlDoc *xml;
- int res = 0;
- 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;
-
- 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 */
- if (c->file.mmap.start == MAP_FAILED) {
- if (-1 == c->file.fd && /* open the file if not already open */
- -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
- ERROR("open(%s) failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return -1;
- }
-
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
- ERROR("mmap(%s) failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return -1;
- }
-
- close(c->file.fd);
- c->file.fd = -1;
-
- c->file.mmap.length = c->file.length;
-
- /* chunk_reset() or chunk_free() will cleanup for us */
- }
-
- if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
- ERROR("xmlParseChunk() failed: %d", err);
- log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
- }
-
- c->offset += weHave;
- cq->bytes_out += weHave;
-
- break;
- case MEM_CHUNK:
- /* append to the buffer */
- weHave = c->mem->used - 1 - c->offset;
-
- if (weHave > weWant) weHave = weWant;
-
- if (p->conf.log_xml) {
- TRACE("XML-request-body: %s", c->mem->ptr + c->offset);
- }
-
- if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
- ERROR("xmlParseChunk(%s) failed: %d", c->mem->ptr + c->offset, err);
- }
-
- c->offset += weHave;
- cq->bytes_out += weHave;
-
- break;
- case UNUSED_CHUNK:
- break;
- }
- chunkqueue_remove_finished_chunks(cq);
- }
-
- switch ((err = xmlParseChunk(ctxt, 0, 0, 1))) {
- case XML_ERR_DOCUMENT_END:
- case XML_ERR_OK:
- break;
- default:
- ERROR("xmlParseChunk() failed: %d", 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(server *srv, connection *con,
- buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
-
- buffer *b;
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
-
- response_header_overwrite(srv, con,
- CONST_STR_LEN("Content-Type"),
- CONST_STR_LEN("text/xml; charset=\"utf-8\""));
-
- b = chunkqueue_get_append_buffer(con->send);
-
- buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
- buffer_append_string_len(b,CONST_STR_LEN("<D:lockdiscovery>\n"));
- buffer_append_string_len(b,CONST_STR_LEN("<D:activelock>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:lockscope>"));
- buffer_append_string_len(b,CONST_STR_LEN("<D:"));
- buffer_append_string(b, lockscope);
- buffer_append_string_len(b, CONST_STR_LEN("/>"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:lockscope>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:locktype>"));
- buffer_append_string_len(b,CONST_STR_LEN("<D:"));
- buffer_append_string(b, locktype);
- buffer_append_string_len(b, CONST_STR_LEN("/>"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:locktype>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:depth>"));
- buffer_append_string(b, depth == 0 ? "0" : "infinity");
- buffer_append_string_len(b,CONST_STR_LEN("</D:depth>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:timeout>"));
- buffer_append_string_len(b, CONST_STR_LEN("Second-600"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:timeout>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:owner>"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:owner>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("<D:locktoken>"));
- buffer_append_string_len(b, CONST_STR_LEN("<D:href>"));
- buffer_append_string_buffer(b, locktoken);
- buffer_append_string_len(b, CONST_STR_LEN("</D:href>"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:locktoken>\n"));
-
- buffer_append_string_len(b,CONST_STR_LEN("</D:activelock>\n"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));
- buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
-
- con->send->bytes_in += b->used-1;
-
- return 0;
-}
-#endif
-
-/**
- * check if resource is having the right locks to access to resource
- *
- *
- *
- */
-static int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
- int has_lock = 1;
-
-#ifdef USE_LOCKS
- data_string *ds;
-
- UNUSED(srv);
-
- /**
- * This implementation is more fake than real
- * we need a parser for the If: header to really handle the full scope
- *
- * X-Litmus: locks: 11 (owner_modify)
- * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
- * - a tagged check:
- * if http://127.0.0.1:1025/dav/litmus/lockme is locked with
- * opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1, go on
- *
- * X-Litmus: locks: 16 (fail_cond_put)
- * If: (<DAV:no-lock> ["-1622396671"])
- * - untagged:
- * go on if the resource has the etag [...] and the lock
- */
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, 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 = p->conf.stmt_read_lock_by_uri;
-
- sqlite3_reset(stmt);
-
- sqlite3_bind_text(stmt, 1,
- CONST_BUF_LEN(uri),
- SQLITE_TRANSIENT);
-
- while (SQLITE_ROW == sqlite3_step(stmt)) {
- has_lock = 0;
- }
- }
-#else
- UNUSED(srv);
- UNUSED(uri);
- UNUSED(con);
- UNUSED(p);
-#endif
-
- return has_lock;
-}
-
-URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
- plugin_data *p = p_d;
- buffer *b;
- DIR *dir;
- data_string *ds;
- int depth = -1;
- struct stat st;
- buffer *prop_200;
- buffer *prop_404;
- webdav_properties *req_props;
- stat_cache_entry *sce = NULL;
-
- if (con->conf.log_request_handling) {
- TRACE("-- handling request in mod_webdav: %s",
- SAFE_BUF_STR(con->uri.path));
- }
-
- /* PROPFIND need them */
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Depth")))) {
- depth = strtol(ds->value->ptr, NULL, 10);
- }
-
- if (con->conf.log_request_handling) {
- TRACE("depth for %s: %d",
- SAFE_BUF_STR(con->uri.path), depth);
- }
-
- if (con->conf.log_request_handling) {
- TRACE("method for %s: %s",
- SAFE_BUF_STR(con->uri.path), get_http_method_name(con->request.http_method));
- }
-
- switch (con->request.http_method) {
- case HTTP_METHOD_PROPFIND:
- /* they want to know the properties of the directory */
- req_props = NULL;
-
- /* is there a content-body ? */
- if (con->conf.log_request_handling) {
- TRACE("path-name: %s",
- SAFE_BUF_STR(con->physical.path));
- }
-
- switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- case HANDLER_ERROR:
- if (errno == ENOENT) {
- if (con->conf.log_request_handling) {
- TRACE("path-name: %s ... not found",
- SAFE_BUF_STR(con->physical.path));
- }
-
- con->http_status = 404;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- break;
- default:
- break;
- }
-
-
-#ifdef USE_PROPPATCH
- /* any special requests or just allprop ? */
- if (p->conf.sql && con->request.content_length > 0) {
- xmlDocPtr xml;
-
- if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
- xmlNode *rootnode = xmlDocGetRootElement(xml);
-
- 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;
-
- ERROR("no name space for: %s", 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;
- con->mode = DIRECT;
- 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,
- con->uri.path->ptr,
- con->uri.path->used - 1,
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- }
- }
- } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
- /* get all properties (EMPTY) */
- }
- }
- }
-
- xmlFreeDoc(xml);
- } else {
- ERROR("webdav_parse_chunkqueue() failed: %s", "");
-
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- }
-#endif
- con->http_status = 207;
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
-
- b = chunkqueue_get_append_buffer(con->send);
-
- 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();
-
- switch(depth) {
- case 0:
- /* Depth: 0 */
- webdav_get_props(srv, con, p, &(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_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_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"));
-
- break;
- case 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))) {
- if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
- continue;
- /* ignore the parent dir */
- }
-
- buffer_copy_string_buffer(d.path, dst->path);
- PATHNAME_APPEND_SLASH(d.path);
-
- buffer_copy_string_buffer(d.rel_path, dst->rel_path);
- PATHNAME_APPEND_SLASH(d.rel_path);
-
- if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
- /* don't append the . */
- } else {
- buffer_append_string(d.path, de->d_name);
- buffer_append_string(d.rel_path, de->d_name);
- }
-
- buffer_reset(prop_200);
- buffer_reset(prop_404);
-
- webdav_get_props(srv, con, p, &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);
- buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
-
- if (!buffer_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_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);
- }
- break;
- }
-
- 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 (con->conf.log_request_handling) {
- TRACE("sending XML: %s",
- SAFE_BUF_STR(b));
- }
-
- if (p->conf.log_xml) {
- TRACE("XML-response-body: %s", SAFE_BUF_STR(b));
- }
- con->send->bytes_in += b->used-1;
- con->send->is_closed = 1;
-
- return HANDLER_FINISHED;
- case HTTP_METHOD_MKCOL:
- if (p->conf.is_readonly) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- if (con->request.content_length > 0) {
- /* we don't support MKCOL with a body */
- con->http_status = 415;
- con->mode = DIRECT;
-
- 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;
- }
- con->mode = DIRECT;
- } else {
- con->http_status = 201;
- con->send->is_closed = 1;
- }
-
- return HANDLER_FINISHED;
- case HTTP_METHOD_DELETE:
- if (p->conf.is_readonly) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- /* does the client have a lock for this connection ? */
- if (!webdav_has_lock(srv, con, p, con->uri.path)) {
- con->http_status = 423;
- con->mode = DIRECT;
- 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;
- }
- con->mode = DIRECT;
- } else if (S_ISDIR(st.st_mode)) {
- buffer *multi_status_resp = buffer_init();
-
- if (webdav_delete_dir(srv, con, p, &(con->physical), multi_status_resp)) {
- /* we got an error somewhere in between, build a 207 */
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
-
- b = chunkqueue_get_append_buffer(con->send);
-
- 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);
- }
-
- con->http_status = 207;
- con->send->bytes_in += b->used-1;
- con->send->is_closed = 1;
- } else {
- /* everything went fine, remove the directory */
-
- if (-1 == rmdir(con->physical.path->ptr)) {
- switch(errno) {
- case ENOENT:
- con->http_status = 404;
- break;
- default:
- con->http_status = 501;
- break;
- }
- con->mode = DIRECT;
- } else {
- con->http_status = 204;
- con->send->is_closed = 1;
- }
- }
-
- 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;
- }
- con->mode = DIRECT;
- } else {
- con->http_status = 204;
- con->send->is_closed = 1;
- }
- return HANDLER_FINISHED;
- case HTTP_METHOD_PUT: {
- int fd;
- chunkqueue *cq = con->recv;
- chunk *c;
- data_string *ds_range;
-
- if (p->conf.is_readonly) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- /* is a exclusive lock set on the source */
- if (!webdav_has_lock(srv, con, p, con->uri.path)) {
- con->http_status = 423;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
-
- if (chunkqueue_length(cq) != (off_t)con->request.content_length) {
- ERROR("%s", "chunkqueue_length didn't match request.content_length");
- con->http_status = 500;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
- * - most important Content-Range
- *
- *
- * Example: Content-Range: bytes 100-1037/1038 */
-
- if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Content-Range")))) {
- const char *num = ds_range->value->ptr;
- off_t offset;
- char *err = NULL;
-
- if (0 != strncmp(num, "bytes ", 6)) {
- con->http_status = 501; /* not implemented */
- con->mode = DIRECT;
-
- 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 */
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
- offset = str_to_off_t(num, &err, 10);
-
- if (offset == STR_OFF_T_MAX ||
- offset == STR_OFF_T_MIN) {
- /**
- * conversion did a over- or underrun
- */
- con->http_status = 501; /* not implemented */
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
- if (*err != '-' || offset < 0) {
- con->http_status = 501; /* not implemented */
- con->mode = DIRECT;
-
- 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;
- }
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- if (-1 == lseek(fd, offset, SEEK_SET)) {
- con->http_status = 501; /* not implemented */
- con->mode = DIRECT;
-
- 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;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- } else {
- con->http_status = 201; /* created */
- }
- } else {
- con->http_status = 200; /* modified */
- }
- }
-
- con->send->is_closed = 1;
-
- for (c = cq->first; c; c = cq->first) {
- int r = 0;
-
- /* copy all chunks */
- switch(c->type) {
- case FILE_CHUNK:
-
- if (c->file.mmap.start == MAP_FAILED) {
- if (-1 == c->file.fd && /* open the file if not already open */
- -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
- strerror(errno), c->file.name, c->file.fd);
-
- return HANDLER_ERROR;
- }
-
- c->file.mmap.length = c->file.length;
-
- close(c->file.fd);
- c->file.fd = -1;
-
- /* chunk_reset() or chunk_free() will cleanup for us */
- }
-
- if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
- switch(errno) {
- case ENOSPC:
- con->http_status = 507;
-
- break;
- default:
- con->http_status = 403;
- break;
- }
- }
- break;
- case MEM_CHUNK:
- if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
- switch(errno) {
- case ENOSPC:
- con->http_status = 507;
-
- break;
- default:
- con->http_status = 403;
- break;
- }
- }
- break;
- case UNUSED_CHUNK:
- break;
- }
-
- if (r > 0) {
- c->offset += r;
- cq->bytes_out += r;
- } else {
- break;
- }
- chunkqueue_remove_finished_chunks(cq);
- }
- close(fd);
-
- return HANDLER_FINISHED;
- }
- case HTTP_METHOD_MOVE:
- case HTTP_METHOD_COPY: {
- buffer *destination = NULL;
- char *sep, *start;
- int overwrite = 1;
-
- if (p->conf.is_readonly) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- /* is a exclusive lock set on the source */
- if (con->request.http_method == HTTP_METHOD_MOVE) {
- if (!webdav_has_lock(srv, con, p, con->uri.path)) {
- con->http_status = 423;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- }
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Destination")))) {
- destination = ds->value;
- } else {
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Overwrite")))) {
- if (ds->value->used != 2 ||
- (ds->value->ptr[0] != 'F' &&
- ds->value->ptr[0] != 'T') ) {
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- overwrite = (ds->value->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
- * */
-
- buffer_reset(p->uri.scheme);
- buffer_reset(p->uri.path_raw);
- buffer_reset(p->uri.authority);
-
- start = destination->ptr;
-
- if (NULL == (sep = strstr(start, "://"))) {
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- buffer_copy_string_len(p->uri.scheme, start, sep - start);
-
- start = sep + 3;
-
- if (NULL == (sep = strchr(start, '/'))) {
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- 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_raw, start);
- } else {
- buffer_copy_string_len(p->uri.path_raw, start, sep - start);
- }
-
- if (!buffer_is_equal(p->uri.authority, con->uri.authority)) {
- /* not the same host */
- con->http_status = 502;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- buffer_copy_string_buffer(p->tmp_buf, p->uri.path_raw);
- buffer_urldecode_path(p->tmp_buf);
- buffer_path_simplify(p->uri.path, p->tmp_buf);
-
- /* we now have a URI which is clean. transform it into a physical path */
- buffer_copy_string_buffer(p->physical.doc_root, con->physical.doc_root);
- buffer_copy_string_buffer(p->physical.rel_path, p->uri.path);
-
- if (con->conf.force_lowercase_filenames) {
- buffer_to_lower(p->physical.rel_path);
- }
-
- buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
- PATHNAME_APPEND_SLASH(p->physical.path);
- buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
-
- /* don't add a second / */
- if (p->physical.rel_path->ptr[0] == '/') {
- buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
- } else {
- buffer_append_string_buffer(p->physical.path, 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;
- }
- con->mode = DIRECT;
- } else if (S_ISDIR(st.st_mode)) {
- int r;
- /* src is a directory */
-
- con->http_status = 204;
- con->send->is_closed = 1;
- if (-1 == stat(p->physical.path->ptr, &st)) {
- if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- con->http_status = 201;
- } else if (!S_ISDIR(st.st_mode)) {
- if (overwrite == 0) {
- /* copying into a non-dir ? */
- con->http_status = 409;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- } else {
- unlink(p->physical.path->ptr);
- if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- }
- }
-
- /* copy the content of src to dest */
- if (0 != (r = webdav_copy_dir(srv, con, p, &(con->physical), &(p->physical), overwrite))) {
- con->http_status = r;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- if (con->request.http_method == HTTP_METHOD_MOVE) {
- b = buffer_init();
- webdav_delete_dir(srv, con, p, &(con->physical), b); /* content */
- buffer_free(b);
-
- rmdir(con->physical.path->ptr);
- }
- } else {
- /* it is just a file, good */
- int r;
-
- /* does the client have a lock for this connection ? */
- if (!webdav_has_lock(srv, con, p, p->uri.path)) {
- con->http_status = 423;
- con->mode = DIRECT;
- 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 */
-
- 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 = 201; /* we will create a new one */
- con->send->is_closed = 1;
-
- switch(errno) {
- case ENOTDIR:
- con->http_status = 409;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- } else if (overwrite == 0) {
- /* destination exists, but overwrite is not set */
- con->http_status = 412;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- } else {
- con->http_status = 204; /* resource already existed */
- con->send->is_closed = 1;
- }
-
- 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 = p->conf.stmt_move_uri;
-
- if (stmt) {
-
- sqlite3_reset(stmt);
-
- /* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- p->uri.path->ptr,
- p->uri.path->used - 1,
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 2,
- con->uri.path->ptr,
- con->uri.path->used - 1,
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
- }
- }
-#endif
- return HANDLER_FINISHED;
- }
-
- /* rename failed, fall back to COPY + DELETE */
- }
-
- if (0 != (r = webdav_copy_file(srv, con, p, &(con->physical), &(p->physical), overwrite))) {
- con->http_status = r;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
- if (con->request.http_method == HTTP_METHOD_MOVE) {
- b = buffer_init();
- webdav_delete_file(srv, con, p, &(con->physical), b);
- buffer_free(b);
- }
- }
-
- return HANDLER_FINISHED;
- }
- case HTTP_METHOD_PROPPATCH:
- if (p->conf.is_readonly) {
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- if (!webdav_has_lock(srv, con, p, con->uri.path)) {
- con->http_status = 423;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
-
- /* check if destination exists */
- if (-1 == stat(con->physical.path->ptr, &st)) {
- switch(errno) {
- case ENOENT:
- con->http_status = 404;
- con->mode = DIRECT;
- break;
- }
- }
-
-#ifdef USE_PROPPATCH
- if (p->conf.sql && con->request.content_length > 0) {
- xmlDocPtr xml;
-
- if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &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;
- 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,
- con->uri.path->ptr,
- con->uri.path->used - 1,
- 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) {
- sqlite3_bind_text(stmt, 4,
- (char *)xmlNodeGetContent(prop),
- strlen((char *)xmlNodeGetContent(prop)),
- SQLITE_TRANSIENT);
- }
-
- if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "sql-set failed:", sqlite3_errmsg(p->conf.sql));
- }
- }
- }
- 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;
- con->mode = DIRECT;
- } 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->send->is_closed = 1;
-
- return HANDLER_FINISHED;
- }
-
-propmatch_cleanup:
-
- xmlFreeDoc(xml);
- } else {
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- }
-#endif
- con->http_status = 501;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- case HTTP_METHOD_LOCK:
- /**
- * a mac wants to write
- *
- * LOCK /dav/expire.txt HTTP/1.1\r\n
- * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
- * Accept: * / *\r\n
- * Depth: 0\r\n
- * Timeout: Second-600\r\n
- * Content-Type: text/xml; charset=\"utf-8\"\r\n
- * Content-Length: 229\r\n
- * Connection: keep-alive\r\n
- * Host: 192.168.178.23:1025\r\n
- * \r\n
- * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
- * <D:lockinfo xmlns:D=\"DAV:\">\n
- * <D:lockscope><D:exclusive/></D:lockscope>\n
- * <D:locktype><D:write/></D:locktype>\n
- * <D:owner>\n
- * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
- * </D:owner>\n
- * </D:lockinfo>\n
- */
-
- if (depth != 0 && depth != -1) {
- con->http_status = 400;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
-#ifdef USE_LOCKS
- if (p->conf.sql && con->request.content_length > 0) {
- xmlDocPtr xml;
- buffer *hdr_if = NULL;
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("If")))) {
- hdr_if = ds->value;
- }
-
- /* we don't support Depth: Infinity on locks */
- if (hdr_if == NULL && depth == -1) {
- con->http_status = 409; /* Conflict */
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
- if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
- xmlNode *rootnode = xmlDocGetRootElement(xml);
-
- assert(rootnode);
-
- if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
- xmlNode *lockinfo;
- const xmlChar *lockscope = NULL, *locktype = NULL; /* unused variable: , *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;
- con->mode = DIRECT;
-
- 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;
- con->mode = DIRECT;
-
- xmlFreeDoc(xml);
- return HANDLER_FINISHED;
- }
- }
-
- } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
- }
- }
-
- if (lockscope && locktype) {
- sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
-
- /* is this resourse already locked ? */
-
- /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
- * FROM locks
- * WHERE resource = ? */
-
- if (stmt) {
-
- sqlite3_reset(stmt);
-
- sqlite3_bind_text(stmt, 1,
- p->uri.path->ptr,
- p->uri.path->used - 1,
- SQLITE_TRANSIENT);
-
- /* it is the PK */
- while (SQLITE_ROW == sqlite3_step(stmt)) {
- /* we found a lock
- * 1. is it compatible ?
- * 2. is it ours */
- char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
-
- if (strcmp(sql_lockscope, "exclusive")) {
- con->http_status = 423;
- con->mode = DIRECT;
- } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
- /* resourse is locked with a shared lock
- * client wants exclusive */
- con->http_status = 423;
- con->mode = DIRECT;
- }
- }
- if (con->http_status == 423) {
- xmlFreeDoc(xml);
- return HANDLER_FINISHED;
- }
- }
-
- stmt = p->conf.stmt_create_lock;
- if (stmt) {
- /* create a lock-token */
- uuid_t id;
- char uuid[37] /* 36 + \0 */;
-
- uuid_generate(id);
- uuid_unparse(id, uuid);
-
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("opaquelocktoken:"));
- buffer_append_string(p->tmp_buf, uuid);
-
- /* "CREATE TABLE locks ("
- * " locktoken TEXT NOT NULL,"
- * " resource TEXT NOT NULL,"
- * " lockscope TEXT NOT NULL,"
- * " locktype TEXT NOT NULL,"
- * " owner TEXT NOT NULL,"
- * " depth INT NOT NULL,"
- */
-
- sqlite3_reset(stmt);
-
- sqlite3_bind_text(stmt, 1,
- CONST_BUF_LEN(p->tmp_buf),
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 2,
- CONST_BUF_LEN(con->uri.path),
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 3,
- (const char *)lockscope,
- xmlStrlen(lockscope),
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 4,
- (const char *)locktype,
- +xmlStrlen(locktype),
- SQLITE_TRANSIENT);
-
- /* owner */
- sqlite3_bind_text(stmt, 5,
- "",
- 0,
- SQLITE_TRANSIENT);
-
- /* depth */
- sqlite3_bind_int(stmt, 6,
- depth);
-
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "create lock:", sqlite3_errmsg(p->conf.sql));
- }
-
- /* looks like we survived */
- webdav_lockdiscovery(srv, con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth);
-
- con->http_status = 201;
- con->send->is_closed = 1;
- }
- }
- }
-
- xmlFreeDoc(xml);
- return HANDLER_FINISHED;
- } else {
- con->http_status = 400;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
- }
- } else {
-
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("If")))) {
- buffer *locktoken = ds->value;
- sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
-
- /* remove the < > around the token */
- if (locktoken->used < 6) {
- con->http_status = 400;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
- buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
-
- sqlite3_reset(stmt);
-
- sqlite3_bind_text(stmt, 1,
- CONST_BUF_LEN(p->tmp_buf),
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- TRACE("refresh lock failed: %s", sqlite3_errmsg(p->conf.sql));
- }
-
- webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
-
- con->http_status = 200;
- con->send->is_closed = 1;
- return HANDLER_FINISHED;
- } else {
- /* we need a lock-token to refresh */
- con->http_status = 400;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
- }
- break;
-#else
- con->http_status = 501;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
-#endif
- case HTTP_METHOD_UNLOCK:
-#ifdef USE_LOCKS
- if (NULL != (ds = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("Lock-Token")))) {
- buffer *locktoken = ds->value;
- sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
-
- /* remove the < > around the token */
- if (locktoken->used < 4) {
- con->http_status = 400;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
-
- /**
- * FIXME:
- *
- * if the resourse is locked:
- * - by us: unlock
- * - by someone else: 401
- * if the resource is not locked:
- * - 412
- * */
-
- buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
-
- sqlite3_reset(stmt);
-
- sqlite3_bind_text(stmt, 1,
- CONST_BUF_LEN(p->tmp_buf),
- SQLITE_TRANSIENT);
-
- sqlite3_bind_text(stmt, 2,
- CONST_BUF_LEN(con->uri.path),
- SQLITE_TRANSIENT);
-
- if (SQLITE_DONE != sqlite3_step(stmt)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "remove lock:", sqlite3_errmsg(p->conf.sql));
- }
-
- if (0 == sqlite3_changes(p->conf.sql)) {
- con->http_status = 401;
- con->mode = DIRECT;
- } else {
- con->http_status = 204;
- con->send->is_closed = 1;
- }
- return HANDLER_FINISHED;
- } else {
- /* we need a lock-token to unlock */
- con->http_status = 400;
- con->mode = DIRECT;
-
- return HANDLER_FINISHED;
- }
- break;
-#else
- con->http_status = 501;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
-#endif
- default:
- break;
- }
-
- /* not found */
- return HANDLER_GO_ON;
-}
-
-/**
- * calls the request-handler if we have received all the content
- */
-CONNECTION_FUNC(mod_webdav_recv_request_content) {
- chunkqueue *in = con->recv;
- plugin_data *p = p_d;
- handler_t res;
-
- /**
- * is the content for webdav
- */
- if (con->mode != p->id) return HANDLER_GO_ON;
-
- if (!in->is_closed) return HANDLER_GO_ON;
-
- /* we received all the content, let's call the webdav handler */
-
- res = mod_webdav_subrequest_handler(srv, con, p_d);
-
- /* mark body as read */
- con->recv->bytes_out += chunkqueue_skip(con->recv, con->recv->bytes_in - con->recv->bytes_out);
- chunkqueue_remove_finished_chunks(con->recv);
-
- return res;
-}
-
-/* this function is called at dlopen() time and inits the callbacks */
-
-LI_EXPORT int mod_webdav_plugin_init(plugin *p);
-LI_EXPORT 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; /* check if we handle this URL */
-#if 0
- /* will get called when the content is received */
-#endif
- p->handle_physical = mod_webdav_physical_handler;
- p->handle_send_request_content = mod_webdav_recv_request_content; /* check if we received all the content */
- p->set_defaults = mod_webdav_set_defaults;
- p->cleanup = mod_webdav_free;
-
- p->data = NULL;
-
- return 0;
-}
diff --git a/src/network.c b/src/network.c
deleted file mode 100644
index 988dc940..00000000
--- a/src/network.c
+++ /dev/null
@@ -1,891 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include <stdio.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "connections.h"
-#include "plugin.h"
-#include "joblist.h"
-
-#include "network_backends.h"
-#include "sys-mmap.h"
-#include "sys-socket.h"
-#include "sys-files.h"
-
-#ifdef USE_OPENSSL
-# include <openssl/ssl.h>
-# include <openssl/err.h>
-# include <openssl/rand.h>
-#endif
-
-#define BACKEND_HANDLERS(read, write) network_read_chunkqueue_##read, network_write_chunkqueue_##write
-static network_backend_info_t network_backends[] = {
- /* lowest id wins */
- {
- NETWORK_BACKEND_LINUX_SENDFILE,
- "linux-sendfile",
- NULL,
-#if defined USE_WRITE && defined USE_LINUX_SENDFILE
- BACKEND_HANDLERS(read, linuxsendfile)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_LINUX_AIO_SENDFILE,
- "linux-aio-sendfile",
- NULL,
-#if defined USE_WRITE && defined USE_LINUX_AIO_SENDFILE
- BACKEND_HANDLERS(read, linuxaiosendfile)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_FREEBSD_SENDFILE,
- "freebsd-sendfile",
- NULL,
-#if defined USE_WRITE && defined USE_FREEBSD_SENDFILE
- BACKEND_HANDLERS(read, freebsdsendfile)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_SOLARIS_SENDFILEV,
- "solaris-sendfilev",
- NULL,
-#if defined USE_WRITE && defined USE_SOLARIS_SENDFILEV
- BACKEND_HANDLERS(read, solarissendfilev)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_POSIX_AIO,
- "posix-aio",
- NULL,
-#if defined USE_WRITE && defined USE_POSIX_AIO
- BACKEND_HANDLERS(read, posixaio)
-#else
- NULL, NULL
-#endif
- },
-
- {
- NETWORK_BACKEND_GTHREAD_AIO,
- "gthread-aio",
- NULL,
-#if defined USE_WRITE && defined USE_GTHREAD_AIO
- BACKEND_HANDLERS(read, gthreadaio)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_GTHREAD_SENDFILE,
- "gthread-sendfile",
- NULL,
-#if defined USE_WRITE && defined USE_GTHREAD_AIO && defined USE_GTHREAD_SENDFILE
- BACKEND_HANDLERS(read, gthreadsendfile)
-#else
- NULL, NULL
-#endif
- },
-
- {
- NETWORK_BACKEND_GTHREAD_FREEBSD_SENDFILE,
- "gthread-freebsd-sendfile",
- NULL,
-#if defined USE_WRITE && defined USE_GTHREAD_AIO && defined USE_GTHREAD_FREEBSD_SENDFILE
- BACKEND_HANDLERS(read, gthreadfreebsdsendfile)
-#else
- NULL, NULL
-#endif
- },
-
- {
- NETWORK_BACKEND_WRITEV,
- "writev",
- NULL,
-#if defined USE_WRITE && defined USE_WRITEV
- BACKEND_HANDLERS(read, writev)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_WRITE,
- "write",
- NULL,
-#if defined USE_WRITE
- BACKEND_HANDLERS(read, write)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_WIN32_TRANSMITFILE,
- "win32-transmitfile",
- NULL,
-#if defined USE_WIN32_TRANSMITFILE
- BACKEND_HANDLERS(win32recv, win32transmitfile)
-#else
- NULL, NULL
-#endif
- },
- {
- NETWORK_BACKEND_WIN32_SEND,
- "win32-send",
- NULL,
-#if defined USE_WIN32_SEND && defined USE_WIN32_SEND
- BACKEND_HANDLERS(win32recv, win32send)
-#else
- NULL, NULL
-#endif
- },
-
- {
- NETWORK_BACKEND_UNSET,
- NULL,
- NULL,
- NULL, NULL
- }
-};
-
-const network_backend_info_t *network_get_backends() {
- return network_backends;
-}
-
-const network_backend_info_t *network_get_defaultbackend() {
- const network_backend_info_t *backend = network_get_backends();
-
- while (backend->name) {
- if (backend->write_handler) {
- return backend;
- }
- backend ++;
- }
-
- return NULL;
-}
-
-const network_backend_info_t *network_get_backend_info_by_type(network_backend_t type) {
- const network_backend_info_t *backend = network_get_backends();
-
- while (backend->name) {
- if (type == backend->type) {
- return backend;
- }
- backend ++;
- }
-
- return NULL;
-}
-
-const network_backend_info_t *network_get_backend_info_by_name(const char *name) {
- const network_backend_info_t *backend = network_get_backends();
-
- while (backend->name) {
- if (strcmp(name, backend->name) == 0) {
- return backend;
- }
- backend ++;
- }
-
- return NULL;
-}
-
-handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
- server *srv = (server *)s;
- server_socket *srv_socket = (server_socket *)context;
- connection *con;
- int loops = 0;
-
- UNUSED(context);
-
- if (revents != FDEVENT_IN) {
- log_error_write(srv, __FILE__, __LINE__, "sdd",
- "strange event for server socket",
- srv_socket->sock->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++) {
- joblist_append(srv, con);
- }
- return HANDLER_GO_ON;
-}
-
-#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
-static int network_ssl_servername_callback(SSL *ssl, int *al, server *srv) {
- const char *servername;
- connection *con = (connection *) SSL_get_app_data(ssl);
-
- UNUSED(al);
-
- buffer_copy_string(con->uri.scheme, "https");
-
- if (NULL == (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
-#if 0
- /* this "error" just means the client didn't support it */
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "failed to get TLS server name");
-#endif
- return SSL_TLSEXT_ERR_NOACK;
- }
- buffer_copy_string(con->sock->tlsext_server_name, servername);
- buffer_to_lower(con->sock->tlsext_server_name);
-
- config_patch_connection(srv, con, COMP_SERVER_SOCKET);
- config_patch_connection(srv, con, COMP_HTTP_SCHEME);
- config_patch_connection(srv, con, COMP_HTTP_HOST);
-
- if (NULL == con->conf.ssl_ctx) {
- /* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- "null SSL_CTX for TLS server name", con->sock->tlsext_server_name);
- return SSL_TLSEXT_ERR_ALERT_FATAL;
- }
-
- /* switch to new SSL_CTX in reaction to a client's server_name extension */
- if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- "failed to set SSL_CTX for TLS server name", con->sock->tlsext_server_name);
- return SSL_TLSEXT_ERR_ALERT_FATAL;
- }
-
- return SSL_TLSEXT_ERR_OK;
-}
-#endif
-
-static int network_server_init(server *srv, buffer *host_token, specific_config *s) {
- int val;
- socklen_t addr_len;
- server_socket *srv_socket;
- char *sp;
- unsigned int port = 0;
- const char *host;
- buffer *b;
- int is_unix_domain_socket = 0;
- int fd;
-
-#ifdef SO_ACCEPTFILTER
- struct accept_filter_arg afa;
-#endif
-
-#ifdef _WIN32
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
-
- wVersionRequested = MAKEWORD( 2, 2 );
-
- err = WSAStartup( wVersionRequested, &wsaData );
- if ( err != 0 ) {
- /* Tell the user that we could not find a usable */
- /* WinSock DLL. */
- return -1;
- }
-#endif
-
- srv_socket = calloc(1, sizeof(*srv_socket));
- srv_socket->sock = iosocket_init();
-
- srv_socket->srv_token = buffer_init();
- buffer_copy_string_buffer(srv_socket->srv_token, host_token);
-
- b = buffer_init();
- buffer_copy_string_buffer(b, host_token);
-
- /* ipv4:port
- * [ipv6]:port
- */
- if (NULL == (sp = strrchr(b->ptr, ':'))) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
-
- goto error_free_socket;
- }
-
- host = b->ptr;
-
- /* check for [ and ] */
- if (b->ptr[0] == '[' && *(sp-1) == ']') {
- *(sp-1) = '\0';
- host++;
-
- s->use_ipv6 = 1;
- }
-
- *(sp++) = '\0';
-
- port = strtol(sp, NULL, 10);
-
- if (host[0] == '/') {
- /* host is a unix-domain-socket */
- is_unix_domain_socket = 1;
- } else if (port == 0 || port > 65535) {
- log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
-
- goto error_free_socket;
- }
-
- if (*host == '\0') host = NULL;
-
- if (is_unix_domain_socket) {
-#ifdef HAVE_SYS_UN_H
-
- srv_socket->addr.plain.sa_family = AF_UNIX;
-
- if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
- goto error_free_socket;
- }
-#else
- log_error_write(srv, __FILE__, __LINE__, "s",
- "ERROR: Unix Domain sockets are not supported.");
- goto error_free_socket;
-#endif
- }
-
-#ifdef HAVE_IPV6
- if (s->use_ipv6) {
- srv_socket->addr.plain.sa_family = AF_INET6;
-
- if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
- goto error_free_socket;
- }
- srv_socket->use_ipv6 = 1;
- }
-#endif
-
- if (srv_socket->sock->fd == -1) {
- srv_socket->addr.plain.sa_family = AF_INET;
- if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
- goto error_free_socket;
- }
- }
-
- val = 1;
- if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
- goto error_free_socket;
- }
-
- switch(srv_socket->addr.plain.sa_family) {
-#ifdef HAVE_IPV6
- case AF_INET6:
- memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in6));
- srv_socket->addr.ipv6.sin6_family = AF_INET6;
- if (host == NULL) {
- srv_socket->addr.ipv6.sin6_addr = in6addr_any;
- } 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(host, NULL, &hints, &res))) {
- log_error_write(srv, __FILE__, __LINE__,
- "sssss", "getaddrinfo failed: ",
- gai_strerror(r), "'", host, "'");
-
- goto error_free_socket;
- }
-
- memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
-
- freeaddrinfo(res);
- }
- srv_socket->addr.ipv6.sin6_port = htons(port);
- addr_len = sizeof(struct sockaddr_in6);
- break;
-#endif
- case AF_INET:
- memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in));
- srv_socket->addr.ipv4.sin_family = AF_INET;
- if (host == NULL) {
- srv_socket->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
- } else {
- struct hostent *he;
- if (NULL == (he = gethostbyname(host))) {
- log_error_write(srv, __FILE__, __LINE__,
- "sds", "gethostbyname failed: ",
- h_errno, host);
- goto error_free_socket;
- }
-
- if (he->h_addrtype != AF_INET) {
- log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
- goto error_free_socket;
- }
-
- if (he->h_length != sizeof(struct in_addr)) {
- log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
- goto error_free_socket;
- }
-
- memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
- }
- srv_socket->addr.ipv4.sin_port = htons(port);
-
- addr_len = sizeof(struct sockaddr_in);
-
- break;
-#ifndef _WIN32
- case AF_UNIX:
- srv_socket->addr.un.sun_family = AF_UNIX;
- strcpy(srv_socket->addr.un.sun_path, host);
-
-#ifdef SUN_LEN
- addr_len = SUN_LEN(&srv_socket->addr.un);
-#else
- /* stevens says: */
- addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family);
-#endif
-
- /* check if the socket exists and try to connect to it. */
- if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
- close(fd);
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "server socket is still in use:",
- host);
-
-
- goto error_free_socket;
- }
-
- /* 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));
-
- goto error_free_socket;
- }
-
- break;
-#endif
- default:
- addr_len = 0;
-
- goto error_free_socket;
- }
-
- if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
- switch(srv_socket->addr.plain.sa_family) {
- case AF_UNIX:
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "can't bind to socket:",
- host, strerror(errno));
- break;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ssds",
- "can't bind to port:",
- host, port, strerror(errno));
- break;
- }
- goto error_free_socket;
- }
-
- if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
- goto error_free_socket;
- }
-
- if (s->is_ssl) {
-#ifdef USE_OPENSSL
- if (NULL == (srv_socket->ssl_ctx = s->ssl_ctx)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
- goto error_free_socket;
- }
-#else
-
- buffer_free(srv_socket->srv_token);
- free(srv_socket);
-
- buffer_free(b);
-
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "ssl requested but openssl support is not compiled in");
-
- goto error_free_socket;
-#endif
- } else {
-#ifdef SO_ACCEPTFILTER
- /*
- * FreeBSD accf_http filter
- *
- */
- memset(&afa, 0, sizeof(afa));
- strcpy(afa.af_name, "httpready");
- if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
- if (errno != ENOENT) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
- }
- }
-#endif
- }
-
-#ifdef FD_CLOEXEC
- /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */
- fcntl(srv_socket->sock->fd, F_SETFD, FD_CLOEXEC);
-#endif
-
- srv_socket->is_ssl = s->is_ssl;
-
- 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));
- } 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));
- }
-
- srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
- buffer_free(b);
-
- return 0;
-
-error_free_socket:
- iosocket_free(srv_socket->sock);
- buffer_free(srv_socket->srv_token);
- free(srv_socket);
-
- return -1;
-}
-
-int network_close(server *srv) {
- size_t i;
- for (i = 0; i < srv->srv_sockets.used; i++) {
- server_socket *srv_socket = srv->srv_sockets.ptr[i];
-
- if (srv_socket->sock->fd != -1) {
- /* check if server fd are already registered */
- if (srv_socket->sock->fde_ndx != -1) {
- fdevent_event_del(srv->ev, srv_socket->sock);
- fdevent_unregister(srv->ev, srv_socket->sock);
- }
- }
-
- iosocket_free(srv_socket->sock);
-
- buffer_free(srv_socket->srv_token);
-
- free(srv_socket);
- }
-
-#ifdef USE_OPENSSL
- ERR_free_strings();
-#endif
- free(srv->srv_sockets.ptr);
-
- return 0;
-}
-
-int network_init(server *srv) {
- buffer *b;
- size_t i;
- const network_backend_info_t *backend;
-
-#ifdef USE_OPENSSL
- /* load SSL certificates */
- for (i = 0; i < srv->config_context->used; i++) {
- specific_config *s = srv->config_storage[i];
-
- if (buffer_is_empty(s->ssl_pemfile)) continue;
-
-#ifdef OPENSSL_NO_TLSEXT
- {
- data_config *dc = (data_config *)srv->config_context->data[i];
- if (COMP_HTTP_HOST == dc->comp) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");
- return -1;
- }
- }
-#endif
-
- if (srv->ssl_is_init == 0) {
- SSL_load_error_strings();
- SSL_library_init();
- srv->ssl_is_init = 1;
-
- if (0 == RAND_status()) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "not enough entropy in the pool");
- return -1;
- }
- }
-
- if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-
- if (!s->ssl_use_sslv2) {
- /* disable SSLv2 */
- if (!(SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
- }
-
- if (!buffer_is_empty(s->ssl_cipher_list)) {
- 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 (!buffer_is_empty(s->ssl_ca_file)) {
- if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
- return -1;
- }
- if (s->ssl_verifyclient) {
- STACK_OF(X509_NAME) *certs = SSL_load_client_CA_file(s->ssl_ca_file->ptr);
- if (!certs) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
- }
- if (SSL_CTX_set_session_id_context(s->ssl_ctx, (void*) &srv, sizeof(srv)) != 1) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
- SSL_CTX_set_client_CA_list(s->ssl_ctx, certs);
- SSL_CTX_set_verify(
- s->ssl_ctx,
- SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
- NULL
- );
- SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);
- }
- } else if (s->ssl_verifyclient) {
- log_error_write(
- srv, __FILE__, __LINE__, "s",
- "SSL: You specified ssl.verifyclient.activate but no ca_file"
- );
- }
-
- if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
- return -1;
- }
-
- if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
- return -1;
- }
-
- if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
- log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
- "Private key does not match the certificate public key, reason:",
- ERR_error_string(ERR_get_error(), NULL),
- s->ssl_pemfile);
- return -1;
- }
-
-#ifndef OPENSSL_NO_TLSEXT
- if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) ||
- !SSL_CTX_set_tlsext_servername_arg(s->ssl_ctx, srv)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "failed to initialize TLS servername callback, openssl library does not support TLS servername extension");
- return -1;
- }
-#endif
- }
-#endif
-
- b = buffer_init();
-
- buffer_copy_string_buffer(b, srv->srvconf.bindhost);
- buffer_append_string_len(b, CONST_STR_LEN(":"));
- buffer_append_long(b, srv->srvconf.port);
-
- if (0 != network_server_init(srv, b, srv->config_storage[0])) {
- return -1;
- }
- buffer_free(b);
-
-#ifdef USE_OPENSSL
- srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
-#endif
-
- backend = network_get_backend_info_by_type(srv->network_backend);
- assert(backend && backend->read_handler);
- srv->network_backend_read = backend->read_handler;
- srv->network_backend_write = backend->write_handler;
-
-#ifdef USE_OPENSSL
- srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
- srv->network_ssl_backend_read = network_read_chunkqueue_openssl;
-#endif
-
- /* check for $SERVER["socket"] */
- for (i = 1; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- specific_config *s = srv->config_storage[i];
- size_t j;
-
- /* not our stage */
- if (COMP_SERVER_SOCKET != dc->comp) continue;
-
- if (dc->cond != CONFIG_COND_EQ) continue;
-
- /* check if we already know this socket,
- * if yes, don't init it */
- for (j = 0; j < srv->srv_sockets.used; j++) {
- if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) {
- break;
- }
- }
-
- if (j == srv->srv_sockets.used) {
- if (0 != network_server_init(srv, dc->string, s)) return -1;
- }
- }
-
- return 0;
-}
-
-int network_register_fdevents(server *srv) {
- size_t i;
- if (-1 == fdevent_reset(srv->ev)) {
- return -1;
- }
- /* register fdevents after reset */
- for (i = 0; i < srv->srv_sockets.used; i++) {
- server_socket *srv_socket = srv->srv_sockets.ptr[i];
- fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
- fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
- }
- return 0;
-}
-
-network_status_t network_read(server *srv, connection *con, iosocket *sock, chunkqueue *cq) {
- server_socket *srv_socket = con->srv_socket;
- network_status_t ret = NETWORK_STATUS_UNSET;
- off_t start_bytes_in = cq->bytes_in;
-
- if (srv_socket->is_ssl) {
-#ifdef USE_OPENSSL
- ret = srv->network_ssl_backend_read(srv, con, sock, cq);
-#else
- ret = NETWORK_STATUS_FATAL_ERROR;
-#endif
- } else {
- ret = srv->network_backend_read(srv, con, sock, cq);
- }
-
- con->bytes_read += cq->bytes_in - start_bytes_in;
-
- return ret;
-}
-
-network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
- network_status_t ret = NETWORK_STATUS_UNSET;
- off_t written = 0;
-#ifdef TCP_CORK
- int corked = 0;
-#endif
- server_socket *srv_socket = con->srv_socket;
-
- if (con->conf.global_kbytes_per_second &&
- *(con->conf.global_bytes_per_second_cnt_ptr) > con->conf.global_kbytes_per_second * 1024) {
- /* we reached the global traffic limit */
-
- con->traffic_limit_reached = 1;
- joblist_append(srv, con);
-
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
- }
-
- written = cq->bytes_out;
-
-#ifdef TCP_CORK
- /* Linux: put a cork into the socket as we want to combine the write() calls
- * but only if we really have multiple chunks
- */
- if (cq->first && cq->first->next) {
- corked = 1;
- setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
- }
-#endif
-
- if (srv_socket->is_ssl) {
-#ifdef USE_OPENSSL
- ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
-#endif
- } else {
- ret = srv->network_backend_write(srv, con, con->sock, cq);
- }
-
- switch (ret) {
- case NETWORK_STATUS_WAIT_FOR_FD:
- case NETWORK_STATUS_WAIT_FOR_AIO_EVENT:
- case NETWORK_STATUS_WAIT_FOR_EVENT:
- case NETWORK_STATUS_SUCCESS:
- chunkqueue_remove_finished_chunks(cq);
-
- break;
- default:
- break;
- }
-
-#ifdef TCP_CORK
- if (corked) {
- corked = 0;
- setsockopt(con->sock->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;
-
- if (con->conf.kbytes_per_second &&
- (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
- /* we reached the traffic limit */
-
- con->traffic_limit_reached = 1;
- joblist_append(srv, con);
- }
- return ret;
-}
diff --git a/src/network.h b/src/network.h
deleted file mode 100644
index 1e3016f3..00000000
--- a/src/network.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _NETWORK_H_
-#define _NETWORK_H_
-
-#include "settings.h"
-#include "server.h"
-
-LI_API network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
-LI_API network_status_t network_read(server *srv, connection *con, iosocket *sock, chunkqueue *c);
-
-LI_API int network_init(server *srv);
-LI_API int network_close(server *srv);
-
-LI_API int network_register_fdevents(server *srv);
-LI_API handler_t network_server_handle_fdevent(void *s, void *context, int revents);
-
-#endif
diff --git a/src/network_backends.h b/src/network_backends.h
deleted file mode 100644
index 4f99a663..00000000
--- a/src/network_backends.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef _NETWORK_BACKENDS_H_
-#define _NETWORK_BACKENDS_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/types.h>
-
-#include "settings.h"
-#include "base.h"
-#include "network.h"
-
-#define NETWORK_BACKEND_WRITE_CHUNK(x) \
- network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
-
-#define NETWORK_BACKEND_WRITE(x) \
- network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
-#define NETWORK_BACKEND_READ(x) \
- network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
-
-LI_API NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
-
-LI_API NETWORK_BACKEND_WRITE(write);
-LI_API NETWORK_BACKEND_WRITE(writev);
-LI_API NETWORK_BACKEND_WRITE(linuxsendfile);
-LI_API NETWORK_BACKEND_WRITE(linuxaiosendfile);
-LI_API NETWORK_BACKEND_WRITE(posixaio);
-LI_API NETWORK_BACKEND_WRITE(gthreadaio);
-LI_API NETWORK_BACKEND_WRITE(gthreadsendfile);
-LI_API NETWORK_BACKEND_WRITE(gthreadfreebsdsendfile);
-LI_API NETWORK_BACKEND_WRITE(freebsdsendfile);
-LI_API NETWORK_BACKEND_WRITE(solarissendfilev);
-
-LI_API NETWORK_BACKEND_WRITE(win32transmitfile);
-LI_API NETWORK_BACKEND_WRITE(win32send);
-
-LI_API NETWORK_BACKEND_READ(read);
-LI_API NETWORK_BACKEND_READ(win32recv);
-
-#ifdef USE_OPENSSL
-LI_API NETWORK_BACKEND_WRITE(openssl);
-LI_API NETWORK_BACKEND_READ(openssl);
-#endif
-
-typedef struct {
- network_backend_t type;
- const char *name;
- const char *description;
- network_status_t (*read_handler)(server *srv, connection *con, iosocket *sock, chunkqueue *cq);
- network_status_t (*write_handler)(server *srv, connection *con, iosocket *sock, chunkqueue *cq);
-} network_backend_info_t;
-
-LI_API const network_backend_info_t *network_get_backends();
-LI_API const network_backend_info_t *network_get_defaultbackend();
-LI_API const network_backend_info_t *network_get_backend_info_by_type(network_backend_t type);
-LI_API const network_backend_info_t *network_get_backend_info_by_name(const char *name);
-
-#endif
diff --git a/src/network_freebsd_sendfile.c b/src/network_freebsd_sendfile.c
deleted file mode 100644
index 446e1fe7..00000000
--- a/src/network_freebsd_sendfile.c
+++ /dev/null
@@ -1,157 +0,0 @@
-#include "network_backends.h"
-
-#ifdef USE_FREEBSD_SENDFILE
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-
-#ifndef UIO_MAXIOV
-# if defined(__FreeBSD__) || defined(__DragonFly__)
-/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
-# define UIO_MAXIOV 1024
-# endif
-#endif
-
-NETWORK_BACKEND_WRITE(freebsdsendfile) {
- chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- chunk *tc;
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc; tc = tc->next) {
- /* finished the chunk */
- if (tc->offset == tc->mem->used - 1) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- } else {
- break;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- off_t offset, r;
- size_t toSend;
- stat_cache_entry *sce = NULL;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), c->file.name);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- offset = c->file.start + c->offset;
- /* limit the toSend to 2^31-1 bytes in a chunk */
- toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
- ((1 << 30) - 1) : c->file.length - c->offset;
-
- if (-1 == c->file.fd) {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
- switch (errno) {
- case EMFILE:
- return NETWORK_STATUS_WAIT_FOR_FD;
- default:
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- r = 0;
-
- /* FreeBSD sendfile() */
- if (-1 == sendfile(c->file.fd, sock->fd, offset, toSend, NULL, &r, 0)) {
- switch(errno) {
- case EAGAIN:
- break;
- case ENOTCONN:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- /* We got an event to write but we wrote nothing
- *
- * - the file shrinked -> error
- * - the remote side closed inbetween -> remote-close */
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- /* file is gone ? */
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (offset > sce->st.st_size) {
- /* file shrinked, close the connection */
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- return NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
- c->offset += r;
- cq->bytes_out += r;
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
- }
-
- break;
- }
- default:
- ERROR("chunk-type '%d' not known", c->type);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/network_gthread_aio.c b/src/network_gthread_aio.c
deleted file mode 100644
index 42a2f3bd..00000000
--- a/src/network_gthread_aio.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/**
- * - MAP_ANON needs _BSD_SOURCE | _SVID_SOURCE
- * - pread() needs _XOPEN_SOURCE 500 on Linux
- * - _XOPEN_SOURCE breaks the compile on FreeBSD (see #1240, #1251)
- *
- */
-#ifndef _GNU_SOURCE
-# ifndef _BSD_SOURCE
-# define _BSD_SOURCE 1
-# endif
-#endif
-
-#ifdef linux
-/* For pread()/pwrite() */
-#define _XOPEN_SOURCE 500
-#endif
-
-#include "settings.h"
-#include "network_backends.h"
-#ifdef USE_GTHREAD_AIO
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "joblist.h"
-#include "timing.h"
-
-#include "sys-files.h"
-#include "sys-socket.h"
-
-typedef struct {
- chunk *c;
-
- void *con;
-
- int sock_fd;
-} write_job;
-
-static write_job *write_job_init() {
- write_job *wj = calloc(1, sizeof(*wj));
-
- return wj;
-}
-
-static void write_job_free(write_job *wj) {
- if (!wj) return;
-
- free(wj);
-}
-
-#define kByte * (1024)
-#define MByte * (1024 kByte)
-
-/**
- * log the time-stamps of the different stages
- */
-static void timing_print(server *srv, connection *con) {
- if (!srv->srvconf.log_timing) return;
-
- TRACE("write-start: %ld.%06ld "
- "read-queue-wait: %ld ms "
- "read-time: %ld ms "
- "write-time: %ld ms ",
- con->timestamps[TIME_SEND_WRITE_START].tv_sec,
- con->timestamps[TIME_SEND_WRITE_START].tv_usec,
-
- TIME_DIFF(TIME_SEND_ASYNC_READ_START, TIME_SEND_ASYNC_READ_QUEUED),
- TIME_DIFF(TIME_SEND_ASYNC_READ_END, TIME_SEND_ASYNC_READ_START),
- TIME_DIFF(TIME_SEND_WRITE_END, TIME_SEND_ASYNC_READ_END_QUEUED)
- );
-}
-
-gpointer network_gthread_aio_read_thread(gpointer _srv) {
- server *srv = (server *)_srv;
-
- GAsyncQueue * inq;
-
- int fadvise_is_enosys = 0;
-
- g_async_queue_ref(srv->aio_write_queue);
-
- inq = srv->aio_write_queue;
-
- /* */
- while (!srv->is_shutdown) {
- write_job *wj = NULL;
-
- if ((wj = g_async_queue_pop(inq))) {
- /* let's see what we have to stat */
- ssize_t r;
- off_t offset;
- size_t toSend;
- chunk *c;
- connection *con;
- off_t max_toSend = 64 kByte; /** should be larger than the send buffer */
-
- int fadvise_fd = 0;
- off_t fadvise_offset = 0;
- off_t fadvise_len = 0;
-
- if(wj == (write_job *) 1)
- continue; /* just notifying us that srv->is_shutdown changed */
-
- c = wj->c;
- con = wj->con;
-
-#if 0
- /* try to be adaptive */
- int snd_buf_size = 0;
- socklen_t snd_buf_size_size = sizeof(snd_buf_size);
-
- if (0 == getsockopt(con->sock->fd, SOL_SOCKET, SO_SNDBUF, &snd_buf_size, &snd_buf_size_size)) {
- /* adjust the read-data to the send-buffer */
- if (snd_buf_size * 4 > max_toSend) {
- max_toSend = snd_buf_size * 4;
- }
- }
-#endif
-
- offset = c->file.start + c->offset;
-
- toSend = c->file.length - c->offset > max_toSend ?
- max_toSend : c->file.length - c->offset;
-
- c->file.copy.offset = 0;
- c->file.copy.length = 0;
-
- /* open a file in /dev/shm to write to */
- if (c->file.mmap.start == MAP_FAILED) {
-#if defined(HAVE_MEM_MMAP_ZERO)
- int mmap_fd;
- if (-1 == (mmap_fd = open("/dev/zero", O_RDWR))) {
- if (errno != EMFILE) {
- TRACE("open(/dev/zero) returned: %d (%s)",
- errno, strerror(errno));
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- } else {
- c->async.ret_val = NETWORK_STATUS_WAIT_FOR_FD;
- }
- } else {
- c->file.mmap.offset = 0;
- c->file.mmap.length = toSend;
-
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, 0);
- if (c->file.mmap.start == MAP_FAILED) {
- TRACE("mmap(/dev/zero) returned: %d (%s)",
- errno, strerror(errno));
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- }
-
- close(mmap_fd);
- mmap_fd = -1;
- }
-#elif defined(HAVE_MEM_MMAP_ANON)
- c->file.mmap.offset = 0;
- c->file.mmap.length = toSend; /* align to page-size */
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
-
- if (c->file.mmap.start == MAP_FAILED) {
- TRACE("mmap(MAP_ANON) returned: %d (%s)",
- errno, strerror(errno));
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- }
-#else
-#error hmm, does your system support mmap(/dev/zero) or mmap(MAP_ANON)
-#endif
- }
- if (c->file.mmap.start != MAP_FAILED) {
- timing_log(srv, con, TIME_SEND_ASYNC_READ_START);
-
- if (-1 == (r = pread(c->file.fd, c->file.mmap.start, toSend, c->file.start + c->offset))) {
- switch(errno) {
- default:
- ERROR("reading file failed: %d (%s)", errno, strerror(errno));
-
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- }
- } else if (r == 0) {
- ERROR("pread(%s) returned 0 ... not good", SAFE_BUF_STR(c->file.name));
-
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- } else {
- timing_log(srv, con, TIME_SEND_ASYNC_READ_END);
- c->file.copy.length = r;
- }
- }
-
- if (c->file.copy.length && !fadvise_is_enosys) {
- fadvise_fd = c->file.fd;
- fadvise_offset = c->file.start + c->offset + c->file.copy.length;
- fadvise_len = c->file.length - c->offset - c->file.copy.length;
-
- if (fadvise_len > max_toSend) {
- fadvise_len = max_toSend;
- }
- }
- timing_log(srv, con, TIME_SEND_ASYNC_READ_END_QUEUED);
- /* read async, write as usual */
- joblist_async_append(srv, wj->con);
-
-#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
- /* read ahead */
- if (c->file.copy.length && !fadvise_is_enosys && fadvise_len) {
- /* let's hope that the fd is still valid when we try to read ahead */
- if (-1 == posix_fadvise(fadvise_fd, fadvise_offset, fadvise_len, POSIX_FADV_WILLNEED)) {
- if (ENOSYS != errno) {
- ERROR("posix_fadvise(%d) failed: %s (%d)", fadvise_fd, strerror(errno), errno);
- } else {
- /* don't try again as we don't support it */
- fadvise_is_enosys = 1;
- }
- }
- }
-#endif
- write_job_free(wj);
- }
- }
-
- g_async_queue_unref(srv->aio_write_queue);
-
- return NULL;
-
-}
-
-
-NETWORK_BACKEND_WRITE(gthreadaio) {
- chunk *c, *tc;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc && chunk_is_done(tc); tc = tc->next) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- ssize_t r;
-
- /* we might be on our way back from the async request and have a status-code */
- if (c->async.ret_val != NETWORK_STATUS_UNSET) {
- ret = c->async.ret_val;
-
- c->async.ret_val = NETWORK_STATUS_UNSET;
-
- ERROR("thread returned: %d", ret);
-
- return ret;
- }
-
- /* open file if not already opened */
- if (-1 == c->file.fd) {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY /* | O_DIRECT */ | (srv->srvconf.use_noatime ? O_NOATIME : 0)))) {
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
-#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_SEQUENTIAL)
- /* tell the kernel that we want to stream the file
- *
- * - POSIX_FADV_SEQUENTIAL doubles the read-ahead on Linux
- *
- * */
- if (-1 == posix_fadvise(c->file.fd, c->file.start, c->file.length, POSIX_FADV_SEQUENTIAL)) {
- if (ENOSYS != errno) {
- ERROR("posix_fadvise(%s) failed: %s (%d)", c->file.name->ptr, strerror(errno), errno);
- }
- }
-#endif
- }
- /* check if we have content */
- if (c->file.copy.length == 0) {
- const off_t max_toSend = 64 kByte; /** should be larger than the send buffer */
- size_t toSend;
- off_t offset;
-
- /* start to write a block out the to net work */
- timing_log(srv, con, TIME_SEND_WRITE_START);
-
- offset = c->file.start + c->offset;
-
- toSend = c->file.length - c->offset > max_toSend ?
- max_toSend : c->file.length - c->offset;
-
- /* we small files don't take the overhead of a full async-loop */
- if (toSend < 4 * 1024) {
-
- c->file.copy.offset = 0;
- c->file.copy.length = toSend;
-
- /* open a file in /dev/shm to write to */
- if (c->file.mmap.start == MAP_FAILED) {
-#if defined(HAVE_MEM_MMAP_ZERO)
- int mmap_fd;
-
- if (-1 == (mmap_fd = open("/dev/zero", O_RDWR))) {
- if (errno != EMFILE) {
- TRACE("open(/dev/zero) returned: %d (%s), open fds: %d",
- errno, strerror(errno));
- return NETWORK_STATUS_FATAL_ERROR;
- } else {
- return NETWORK_STATUS_WAIT_FOR_FD;
- }
- } else {
- c->file.mmap.offset = 0;
- c->file.mmap.length = c->file.copy.length; /* align to page-size */
-
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, 0);
- if (c->file.mmap.start == MAP_FAILED) {
- ERROR("mmap(%s) failed: %s (%d)", c->file.name->ptr, strerror(errno), errno);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- close(mmap_fd);
- mmap_fd = -1;
- }
-#elif defined(HAVE_MEM_MMAP_ANON)
- c->file.mmap.offset = 0;
- c->file.mmap.length = c->file.copy.length; /* align to page-size */
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
-
- if (c->file.mmap.start == MAP_FAILED) {
- TRACE("mmap(MAP_ANON) returned: %d (%s)",
- errno, strerror(errno));
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#else
-#error hmm, does your system support mmap(/dev/zero) or mmap(MAP_ANON)
-#endif
-
- }
-
- if (c->file.mmap.start != MAP_FAILED) {
- lseek(c->file.fd, c->file.start + c->offset, SEEK_SET);
-
- if (-1 == (r = read(c->file.fd, c->file.mmap.start, c->file.copy.length))) {
- switch(errno) {
- default:
- ERROR("reading file failed: %d (%s)", errno, strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- } else if (r == 0) {
- ERROR("read() returned 0 ... not good: %s", "");
-
- return NETWORK_STATUS_FATAL_ERROR;
- } else if (r != c->file.copy.length) {
- ERROR("read() returned %zd instead of %jd", r, (intmax_t) c->file.copy.length);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- } else {
- return NETWORK_STATUS_FATAL_ERROR;
- }
- } else {
- write_job *wj;
-
- wj = write_job_init();
- wj->c = c;
- wj->con = con;
- wj->sock_fd = sock->fd;
-
- c->async.written = -1;
- c->async.ret_val = NETWORK_STATUS_UNSET;
-
- g_async_queue_push(srv->aio_write_queue, wj);
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_QUEUED);
-
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
- }
- }
-
- if (-1 == (r = write(sock->fd, c->file.mmap.start + c->file.copy.offset, c->file.copy.length - c->file.copy.offset))) {
- switch (errno) {
- case EINTR:
- case EAGAIN:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("write failed: %d (%s) [%jd, %p, %jd]",
- errno, strerror(errno), (intmax_t) c->file.copy.length,
- c->file.mmap.start, (intmax_t) c->file.copy.offset);
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- return NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
- c->file.copy.offset += r; /* offset in the copy-chunk */
-
- c->offset += r; /* global offset in the file */
- cq->bytes_out += r;
-
- if (c->file.copy.offset == (off_t) c->file.mmap.length) {
- /* this block is sent, get a new one */
- timing_log(srv, con, TIME_SEND_WRITE_END);
-
- timing_print(srv, con);
-
- c->file.copy.length = 0;
- }
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- munmap(c->file.mmap.start, c->file.mmap.length);
- c->file.mmap.start = MAP_FAILED;
-
- if (c->file.copy.fd != -1) {
- close(c->file.copy.fd);
- c->file.copy.fd = -1;
- }
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
- }
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/network_gthread_freebsd_sendfile.c b/src/network_gthread_freebsd_sendfile.c
deleted file mode 100644
index 639eda67..00000000
--- a/src/network_gthread_freebsd_sendfile.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#include "settings.h"
-#include "network_backends.h"
-#if defined(USE_GTHREAD_FREEBSD_SENDFILE)
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "joblist.h"
-#include "timing.h"
-
-#include "sys-files.h"
-#include "sys-socket.h"
-
-typedef struct {
- chunk *c;
-
- void *con;
-
- int sock_fd;
-} write_job;
-
-static write_job *write_job_init() {
- write_job *wj = calloc(1, sizeof(*wj));
-
- return wj;
-}
-
-static void write_job_free(write_job *wj) {
- if (!wj) return;
-
- free(wj);
-}
-
-#define kByte * (1024)
-#define MByte * (1024 kByte)
-
-/**
- * log the time-stamps of the different stages
- */
-static void timing_print(server *srv, connection *con) {
- if (!srv->srvconf.log_timing) return;
-
- TRACE("write-start: %ld.%06ld "
- "read-queue-wait: %ld ms "
- "read-time: %ld ms "
- "write-time: %ld ms ",
- con->timestamps[TIME_SEND_WRITE_START].tv_sec,
- con->timestamps[TIME_SEND_WRITE_START].tv_usec,
-
- TIME_DIFF(TIME_SEND_ASYNC_READ_START, TIME_SEND_ASYNC_READ_QUEUED),
- TIME_DIFF(TIME_SEND_ASYNC_READ_END, TIME_SEND_ASYNC_READ_START),
- TIME_DIFF(TIME_SEND_WRITE_END, TIME_SEND_ASYNC_READ_END_QUEUED)
- );
-}
-
-/**
- * a backend which calls sendfile() in a thread
- */
-
-gpointer network_gthread_freebsd_sendfile_read_thread(gpointer _srv) {
- server *srv = (server *)_srv;
-
- GAsyncQueue * inq;
-
- g_async_queue_ref(srv->aio_write_queue);
-
- inq = srv->aio_write_queue;
-
- /* */
- while (!srv->is_shutdown) {
- write_job *wj = NULL;
-
- if ((wj = g_async_queue_pop(inq))) {
- /* let's see what we have to stat */
- off_t r;
- off_t offset;
- size_t toSend;
- chunk *c;
- connection *con;
- off_t max_toSend = 512 kByte; /** should be larger than the send buffer */
-
- if(wj == (write_job *) 1)
- continue; /* just notifying us that srv->is_shutdown changed */
-
- c = wj->c;
- con = wj->con;
- offset = c->file.start + c->offset;
-
- toSend = c->file.length - c->offset > max_toSend ?
- max_toSend : c->file.length - c->offset;
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_START);
-
- r = 0;
- if (-1 == sendfile(c->file.fd, wj->sock_fd, offset, toSend, NULL, &r, 0)) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- c->async.ret_val = NETWORK_STATUS_WAIT_FOR_EVENT;
- break;
- case ENOTCONN:
- c->async.ret_val = NETWORK_STATUS_CONNECTION_CLOSE;
- break;
- default:
- ERROR("sendfile(%s) failed: %s (%d)",
- SAFE_BUF_STR(c->file.name),
- strerror(errno), errno);
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- break;
- }
- } else if (r == 0) {
- c->async.ret_val = NETWORK_STATUS_CONNECTION_CLOSE;
- } else {
- c->async.written = r;
- }
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_END);
- timing_log(srv, con, TIME_SEND_ASYNC_READ_END_QUEUED);
-
- /* read async, write as usual */
- joblist_async_append(srv, wj->con);
-
- write_job_free(wj);
- }
- }
-
- g_async_queue_unref(srv->aio_write_queue);
-
- return NULL;
-
-}
-
-
-NETWORK_BACKEND_WRITE(gthreadfreebsdsendfile) {
- chunk *c, *tc;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc && chunk_is_done(tc); tc = tc->next) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- /* we might be on our way back from the async request and have a status-code */
- if (c->async.ret_val != NETWORK_STATUS_UNSET) {
- ret = c->async.ret_val;
-
- c->async.ret_val = NETWORK_STATUS_UNSET;
-
- return ret;
- }
-
- /* open file if not already opened */
- if (-1 == c->file.fd) {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY /* | O_DIRECT */ | (srv->srvconf.use_noatime ? O_NOATIME : 0)))) {
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
-#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_SEQUENTIAL)
- /* tell the kernel that we want to stream the file */
- if (-1 == posix_fadvise(c->file.fd, c->file.start, c->file.length, POSIX_FADV_SEQUENTIAL)) {
- if (ENOSYS != errno) {
- ERROR("posix_fadvise(%s) failed: %s (%d)", c->file.name->ptr, strerror(errno), errno);
- }
- }
-#endif
- }
-
- if (c->async.written > 0) {
- /* the backend has written something */
-
- c->offset += c->async.written; /* global offset in the file */
- cq->bytes_out += c->async.written;
-
- /* this block is sent, get a new one */
- timing_log(srv, con, TIME_SEND_WRITE_END);
-
- timing_print(srv, con);
-
- c->async.written = -1;
- }
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
- } else {
- /* start this write */
- write_job *wj;
-
- timing_log(srv, con, TIME_SEND_WRITE_START);
- wj = write_job_init();
- wj->c = c;
- wj->con = con;
- wj->sock_fd = sock->fd;
-
- c->async.written = -1;
- c->async.ret_val = NETWORK_STATUS_UNSET;
-
- g_async_queue_push(srv->aio_write_queue, wj);
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_QUEUED);
-
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
- }
-
- break;
- }
- case UNUSED_CHUNK:
- continue;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
-
diff --git a/src/network_gthread_sendfile.c b/src/network_gthread_sendfile.c
deleted file mode 100644
index b39a082d..00000000
--- a/src/network_gthread_sendfile.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#include "settings.h"
-#include "network_backends.h"
-#if defined(USE_GTHREAD_SENDFILE)
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "joblist.h"
-#include "timing.h"
-
-#include "sys-files.h"
-#include "sys-socket.h"
-
-typedef struct {
- chunk *c;
-
- void *con;
-
- int sock_fd;
-} write_job;
-
-static write_job *write_job_init() {
- write_job *wj = calloc(1, sizeof(*wj));
-
- return wj;
-}
-
-static void write_job_free(write_job *wj) {
- if (!wj) return;
-
- free(wj);
-}
-
-#define kByte * (1024)
-#define MByte * (1024 kByte)
-
-/**
- * log the time-stamps of the different stages
- */
-static void timing_print(server *srv, connection *con) {
- if (!srv->srvconf.log_timing) return;
-
- TRACE("write-start: %ld.%06ld "
- "read-queue-wait: %ld ms "
- "read-time: %ld ms "
- "write-time: %ld ms ",
- con->timestamps[TIME_SEND_WRITE_START].tv_sec,
- con->timestamps[TIME_SEND_WRITE_START].tv_usec,
-
- TIME_DIFF(TIME_SEND_ASYNC_READ_START, TIME_SEND_ASYNC_READ_QUEUED),
- TIME_DIFF(TIME_SEND_ASYNC_READ_END, TIME_SEND_ASYNC_READ_START),
- TIME_DIFF(TIME_SEND_WRITE_END, TIME_SEND_ASYNC_READ_END_QUEUED)
- );
-}
-
-/**
- * a backend which calls sendfile() in a thread
- */
-
-gpointer network_gthread_sendfile_read_thread(gpointer _srv) {
- server *srv = (server *)_srv;
-
- GAsyncQueue * inq;
-
- g_async_queue_ref(srv->aio_write_queue);
-
- inq = srv->aio_write_queue;
-
- /* */
- while (!srv->is_shutdown) {
- write_job *wj = NULL;
-
- if ((wj = g_async_queue_pop(inq))) {
- /* let's see what we have to stat */
- ssize_t r;
- off_t offset;
- size_t toSend;
- chunk *c;
- connection *con;
- off_t max_toSend = 512 kByte; /** should be larger than the send buffer */
-
- if(wj == (write_job *) 1)
- continue; /* just notifying us that srv->is_shutdown changed */
-
- c = wj->c;
- con = wj->con;
- offset = c->file.start + c->offset;
-
- toSend = c->file.length - c->offset > max_toSend ?
- max_toSend : c->file.length - c->offset;
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_START);
-
- if (-1 == (r = sendfile(wj->sock_fd, c->file.fd, &offset, toSend))) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- c->async.ret_val = NETWORK_STATUS_WAIT_FOR_EVENT;
- break;
- case EPIPE:
- case ECONNRESET:
- c->async.ret_val = NETWORK_STATUS_CONNECTION_CLOSE;
- break;
- case ENOSYS:
- ERROR("sendfile(%s) is not implemented, use server.network-backend = \"writev\"",
- SAFE_BUF_STR(c->file.name));
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- break;
- default:
- ERROR("sendfile(%s) failed: %s (%d)",
- SAFE_BUF_STR(c->file.name),
- strerror(errno), errno);
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- break;
- }
- } else if (r == 0) {
- c->async.ret_val = NETWORK_STATUS_CONNECTION_CLOSE;
- } else {
- c->async.written = r;
- }
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_END);
- timing_log(srv, con, TIME_SEND_ASYNC_READ_END_QUEUED);
-
- /* read async, write as usual */
- joblist_async_append(srv, wj->con);
-
- write_job_free(wj);
- }
- }
-
- g_async_queue_unref(srv->aio_write_queue);
-
- return NULL;
-
-}
-
-
-NETWORK_BACKEND_WRITE(gthreadsendfile) {
- chunk *c, *tc;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc && chunk_is_done(tc); tc = tc->next) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- /* we might be on our way back from the async request and have a status-code */
- if (c->async.ret_val != NETWORK_STATUS_UNSET) {
- ret = c->async.ret_val;
-
- c->async.ret_val = NETWORK_STATUS_UNSET;
-
- return ret;
- }
-
- /* open file if not already opened */
- if (-1 == c->file.fd) {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY /* | O_DIRECT */ | (srv->srvconf.use_noatime ? O_NOATIME : 0)))) {
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
-#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_SEQUENTIAL)
- /* tell the kernel that we want to stream the file */
- if (-1 == posix_fadvise(c->file.fd, c->file.start, c->file.length, POSIX_FADV_SEQUENTIAL)) {
- if (ENOSYS != errno) {
- ERROR("posix_fadvise(%s) failed: %s (%d)", c->file.name->ptr, strerror(errno), errno);
- }
- }
-#endif
- }
-
- if (c->async.written > 0) {
- /* the backend has written something */
-
- c->offset += c->async.written; /* global offset in the file */
- cq->bytes_out += c->async.written;
-
- /* this block is sent, get a new one */
- timing_log(srv, con, TIME_SEND_WRITE_END);
-
- timing_print(srv, con);
-
- c->async.written = -1;
- }
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
- } else {
- /* start this write */
- write_job *wj;
-
- timing_log(srv, con, TIME_SEND_WRITE_START);
- wj = write_job_init();
- wj->c = c;
- wj->con = con;
- wj->sock_fd = sock->fd;
-
- c->async.written = -1;
- c->async.ret_val = NETWORK_STATUS_UNSET;
-
- g_async_queue_push(srv->aio_write_queue, wj);
-
- timing_log(srv, con, TIME_SEND_ASYNC_READ_QUEUED);
-
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
- }
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/network_linux_aio.c b/src/network_linux_aio.c
deleted file mode 100644
index 23f64160..00000000
--- a/src/network_linux_aio.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* we need O_DIRECT */
-#endif
-
-#include "network_backends.h"
-
-#ifdef USE_LINUX_AIO_SENDFILE
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include <libaio.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "joblist.h"
-#include "status_counter.h"
-
-#include "sys-files.h"
-
-/* the completion handler */
-gpointer linux_aio_read_thread(gpointer _srv) {
- server *srv = (server *)_srv;
-
- /* */
- while (!srv->is_shutdown) {
- /* let's see what we have to stat */
- struct io_event event[16];
- struct timespec io_ts;
- int res;
-
- io_ts.tv_sec = 1;
- io_ts.tv_nsec = 0;
-
- if ((res = io_getevents(srv->linux_io_ctx, 1, 16, event, &io_ts)) > 0) {
- int i;
- for (i = 0; i < res; i++) {
- connection *con = event[i].data;
-
- if ((long)event[i].res <= 0) {
- TRACE("async-read failed with %d (%s), was asked for %s (fd = %d)",
- (int) event[i].res, strerror(-event[i].res), SAFE_BUF_STR(con->uri.path), con->sock->fd);
- }
-
- /* free the iocb */
- event[i].obj->data = NULL;
-
- joblist_async_append(srv, con);
- }
- } else if (res < 0) {
- TRACE("getevents - failed: %d: %s", res, strerror(-res));
- }
- }
-
- return NULL;
-}
-
-
-NETWORK_BACKEND_WRITE(linuxaiosendfile) {
- chunk *c, *tc;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc; tc = tc->next) {
- /* finished the chunk */
- if (tc->offset == (off_t) tc->mem->used - 1) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- } else {
- break;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- ssize_t r;
- int rounds = 8;
-
- /* open file if not already opened */
- if (-1 == c->file.fd) {
- mode_t mode = O_RDONLY;
- /*
- * Note: can't use O_DIRECT on files in "/dev/shm/". I hope all tempfiles
- * will be in shared memory filesystem. Also use O_NOATIME on tempfiles
- * since they will be deleted anyways.
- */
- if(c->file.is_temp) {
- mode |= O_NOATIME;
- } else {
- mode |= (O_DIRECT | (srv->srvconf.use_noatime ? O_NOATIME : 0));
- }
- if (-1 == (c->file.fd = open(c->file.name->ptr, mode))) {
- if (errno == EMFILE) return NETWORK_STATUS_WAIT_FOR_FD;
-
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
- }
-
- do {
- size_t toSend;
- const off_t max_toSend = 4 * 256 * 1024; /** should be larger than the send buffer */
- int file_fd;
- off_t offset;
-
- offset = c->file.start + c->offset;
-
- toSend = c->file.length - c->offset > max_toSend ?
- max_toSend : c->file.length - c->offset;
-
- if (!c->file.is_temp && (-1 == c->file.copy.fd || 0 == c->file.copy.length)) {
- long page_size = sysconf(_SC_PAGESIZE);
-
- int res;
- int async_error = 0;
-
- size_t iocb_ndx;
- struct iocb *iocb = NULL;
-
- c->file.copy.offset = 0;
- c->file.copy.length = toSend - (toSend % page_size); /* align to page-size */
-
- if (c->file.copy.length == 0) {
- async_error = 1;
- }
-
- /* if we reused the previous tmp-file we get overlaps
- *
- * 1 ... 3904 are ok
- * 3905 ... 4096 are replaces by 8001 ... 8192
- *
- * somehow the second read writes into the mmap() before
- * the sendfile is finished which is very strange.
- *
- * if someone finds the reason for this, feel free to remove
- * this if again and number of reduce the syscalls a bit.
- */
- if (-1 != c->file.copy.fd) {
- munmap(c->file.mmap.start, c->file.mmap.length);
-
- close(c->file.copy.fd);
- c->file.copy.fd = -1;
- }
-
- /* do we have a IOCB we can use ? */
-
- for (iocb_ndx = 0; async_error == 0 && iocb_ndx < srv->srvconf.max_read_threads; iocb_ndx++) {
- if (NULL == srv->linux_io_iocbs[iocb_ndx].data) {
- iocb = &srv->linux_io_iocbs[iocb_ndx];
- break;
- }
- }
-
- if (iocb_ndx == srv->srvconf.max_read_threads) {
- async_error = 1;
- }
-
-
- /* get mmap()ed mem-block in /dev/shm */
- if (async_error == 0 && -1 == c->file.copy.fd ) {
- char tmpfile_name[sizeof("/dev/shm/l-XXXXXX")];
-
- /* open a file in /dev/shm to write to */
- strcpy(tmpfile_name, "/dev/shm/l-XXXXXX");
- if (-1 == (c->file.copy.fd = mkstemp(tmpfile_name))) {
- async_error = 1;
-
- if (errno != EMFILE) {
- TRACE("mkstemp returned: %d (%s) for %s, falling back to sync-io",
- errno, strerror(errno), tmpfile_name);
- }
- }
-
- c->file.mmap.offset = 0;
- c->file.mmap.length = c->file.copy.length; /* align to page-size */
-
- if (!async_error) {
- unlink(tmpfile_name); /* remove the file again, we still keep it open */
- if (0 != ftruncate(c->file.copy.fd, c->file.mmap.length)) {
- /* disk full ... */
- async_error = 1;
-
- TRACE("ftruncate returned: %d (%s), falling back to sync-io",
- errno, strerror(errno));
- }
- }
-
- if (!async_error) {
-
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED, c->file.copy.fd, 0);
- if (c->file.mmap.start == MAP_FAILED) {
- async_error = 1;
- }
- }
- }
-
- /* can we be sure that offset is always aligned ? */
- if (async_error == 0 &&
- (((intptr_t)c->file.mmap.start) % page_size != 0 ||
- c->file.copy.length % page_size != 0 ||
- ((intptr_t)(c->file.start + c->offset)) % page_size != 0)) {
- /**
- * after a fallback to sendfile() the offset might be unaligned
- */
-
- async_error = 1;
- }
-
-
- /* looks like we couldn't get a temp-file [disk-full] */
- if (async_error == 0 && -1 != c->file.copy.fd) {
- struct iocb *iocbs[] = { iocb };
-
- assert(c->file.copy.length > 0);
-
- io_prep_pread(iocb, c->file.fd, c->file.mmap.start, c->file.copy.length, c->file.start + c->offset);
- iocb->data = con;
-
- if (1 == (res = io_submit(srv->linux_io_ctx, 1, iocbs))) {
- status_counter_inc(CONST_STR_LEN("server.io.linux-aio.async-read"));
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
- } else {
- iocb->data = NULL;
-
- if (-res != EAGAIN) {
- TRACE("io_submit returned: %d (%s), falling back to sync-io",
- res, strerror(-res));
- } else {
- TRACE("io_submit returned EAGAIN on (%d - %d), -> sync-io", c->file.fd, c->file.copy.fd);
- }
- }
- }
-
- /* oops, looks like the IO-queue is full
- *
- * fall-back to blocking sendfile()
- */
-
- if (c->file.mmap.start != MAP_FAILED) {
- munmap(c->file.mmap.start, c->file.mmap.length);
- c->file.mmap.start = MAP_FAILED;
- }
- if (c->file.copy.fd != -1) {
- close(c->file.copy.fd);
- c->file.copy.fd = -1;
- }
-
- c->file.copy.length = 0;
- c->file.copy.offset = 0;
- } else if (c->file.copy.offset == 0) {
- /* we are finished */
- }
-
- if (c->file.copy.fd == -1) {
- status_counter_inc(CONST_STR_LEN("server.io.linux-aio.sync-read"));
-
- file_fd = c->file.fd;
- } else {
- file_fd = c->file.copy.fd;
-
- offset = c->file.copy.offset;
- toSend = c->file.copy.length - offset;
- }
-
- /* send the tmp-file from /dev/shm/ */
- if (-1 == (r = sendfile(sock->fd, file_fd, &offset, toSend))) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "sendfile failed:", strerror(errno), sock->fd);
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- /* ... ooops */
- return NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
- c->offset += r; /* global offset in the file */
- cq->bytes_out += r;
-
- if (c->file.copy.fd == -1) {
- /* ... */
- } else {
- c->file.copy.offset += r; /* local offset in the mmap file */
-
- if (c->file.copy.offset == c->file.copy.length) {
- c->file.copy.length = 0; /* reset the length and let the next round fetch a new item */
- }
- }
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- if (c->file.copy.fd != -1) {
- close(c->file.copy.fd);
- c->file.copy.fd = -1;
- }
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
- }
-
- /* the chunk is larger and the current snippet is finished */
- } while (c->file.copy.length == 0 && chunk_finished == 0 && rounds-- > 0);
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
-#if 0
-network_linuxsendfile_init(void) {
- p->write = network_linuxsendfile_write_chunkset;
-}
-#endif
diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c
deleted file mode 100644
index 290f0304..00000000
--- a/src/network_linux_sendfile.c
+++ /dev/null
@@ -1,192 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* we need O_DIRECT */
-#endif
-
-#include "network_backends.h"
-
-#ifdef USE_LINUX_SENDFILE
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "sys-files.h"
-
-/* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
-#undef HAVE_POSIX_FADVISE
-
-NETWORK_BACKEND_WRITE(linuxsendfile) {
- chunk *c, *tc;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc && chunk_is_done(tc); tc = tc->next) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- ssize_t r;
- off_t offset;
- size_t toSend;
- stat_cache_entry *sce = NULL;
-
- offset = c->file.start + c->offset;
- /* limit the toSend to 2^31-1 bytes in a chunk */
- toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
- ((1 << 30) - 1) : c->file.length - c->offset;
-
- /* open file if not already opened */
- if (-1 == c->file.fd) {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY | (srv->srvconf.use_noatime ? O_NOATIME : 0)))) {
- switch (errno) {
- case EMFILE:
- return NETWORK_STATUS_WAIT_FOR_FD;
- default:
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- return -1;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
-#ifdef HAVE_POSIX_FADVISE
- /* tell the kernel that we want to stream the file */
- if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
- if (ENOSYS != errno) {
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "posix_fadvise failed:", strerror(errno), c->file.fd);
- }
- }
-#endif
- }
-
- if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- case ENOSYS:
- ERROR("sendfile(%s) is not implemented, use server.network-backend = \"writev\"",
- SAFE_BUF_STR(c->file.name));
- return NETWORK_STATUS_FATAL_ERROR;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "sendfile failed:", strerror(errno), sock->fd);
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- /* We got an event to write but we wrote nothing
- *
- * - the file shrinked -> error
- * - the remote side closed inbetween -> remote-close */
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- /* file is gone ? */
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (offset > sce->st.st_size) {
- /* file shrinked, close the connection */
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- return NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
-#ifdef HAVE_POSIX_FADVISE
-#if 0
-#define K * 1024
-#define M * 1024 K
-#define READ_AHEAD 4 M
- /* check if we need a new chunk */
- if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
- /* tell the kernel that we want to stream the file */
- if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "posix_fadvise failed:", strerror(errno), c->file.fd);
- }
- }
-#endif
-#endif
-
- c->offset += r;
- cq->bytes_out += r;
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- /* chunk_free() / chunk_reset() will cleanup for us but it is a ok to be faster :) */
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
- }
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
-#if 0
-network_linuxsendfile_init(void) {
- p->write = network_linuxsendfile_write_chunkset;
-}
-#endif
diff --git a/src/network_openssl.c b/src/network_openssl.c
deleted file mode 100644
index 7ffc8c47..00000000
--- a/src/network_openssl.c
+++ /dev/null
@@ -1,402 +0,0 @@
-#include "network_backends.h"
-
-#ifdef USE_OPENSSL
-#include <sys/types.h>
-#include "sys-socket.h"
-#include <sys/stat.h>
-#include <sys/time.h>
-#ifndef _WIN32
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <unistd.h>
-#include <netdb.h>
-#else
-#include <sys/types.h>
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-# include <openssl/ssl.h>
-# include <openssl/err.h>
-
-NETWORK_BACKEND_READ(openssl) {
- buffer *b;
- off_t len;
- int read_something = 0;
- off_t max_read = 256 * 1024;
- off_t start_bytes_in = cq->bytes_in;
- network_status_t res;
- int toread, read_offset;
-
- UNUSED(srv);
- UNUSED(con);
-
- /* use a chunk-size of 4k, append to last buffer if it has >= 1kb free */
-#define TOREAD 4096
-
- do {
- int oerrno;
-
- b = (cq->last) ? cq->last->mem : NULL;
-
- if (NULL == b || b->size - b->used < 1024) {
- b = chunkqueue_get_append_buffer(cq);
- buffer_prepare_copy(b, TOREAD+1);
- }
-
- read_offset = (b->used == 0) ? 0 : b->used - 1;
- toread = b->size - 1 - read_offset;
-
- ERR_clear_error();
- len = SSL_read(sock->ssl, b->ptr + read_offset, toread);
-
- /**
- * man SSL_read:
- *
- * >0 is success
- * 0 is connection close
- * <0 is error
- */
- if (len <= 0) {
- int r, ssl_err;
-
- oerrno = errno; /* store the errno for SSL_ERROR_SYSCALL */
- chunkqueue_remove_empty_last_chunk(cq);
-
- switch ((r = SSL_get_error(sock->ssl, len))) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
- 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 */
- ERROR("ssl-errors: %s", ERR_error_string(ssl_err, NULL));
- }
-
- if (len == 0) {
- return NETWORK_STATUS_CONNECTION_CLOSE;
- } else {
- switch(oerrno) {
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("last-errno: (%d) %s", oerrno, strerror(oerrno));
- break;
- }
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- case SSL_ERROR_ZERO_RETURN:
- if (len == 0) {
- /* clean shutdown on the remote side */
- return NETWORK_STATUS_CONNECTION_CLOSE;
- }
- /* fall through otherwise */
- default:
- res = NETWORK_STATUS_CONNECTION_CLOSE;
- while((ssl_err = ERR_get_error())) {
- switch (ERR_GET_REASON(ssl_err)) {
- case SSL_R_SSL_HANDSHAKE_FAILURE:
- case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
- case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
- case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
- if (!con->conf.log_ssl_noise) continue;
- break;
- default:
- res = NETWORK_STATUS_FATAL_ERROR;
- break;
- }
- /* get all errors from the error-queue */
- ERROR("ssl-errors: %s", ERR_error_string(ssl_err, NULL));
- }
-
- return res;
- }
- } else {
- if (b->used > 0) b->used--;
- b->used += len;
- b->ptr[b->used++] = '\0';
-
- read_something = 1;
- cq->bytes_in += len;
- }
-
- if (cq->bytes_in - start_bytes_in > max_read) break;
- } while (len == toread);
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-
-NETWORK_BACKEND_WRITE(openssl) {
- int ssl_r;
- chunk *c;
-
- /* this is a 64k sendbuffer
- *
- * it has to stay at the same location all the time to satisfy the needs
- * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
- *
- * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
- * -> we expect a 64k block to 'leak' in valgrind
- *
- *
- * In reality we would like to use mmap() but we don't have a guarantee that
- * we get the same mmap() address for each call. On openbsd the mmap() address
- * even randomized.
- * That means either we keep the mmap() open or we do a read() into a
- * constant buffer
- * */
-#define LOCAL_SEND_BUFSIZE (64 * 1024)
- static char *local_send_buffer = NULL;
-
- /* the remote side closed the connection before without shutdown request
- * - IE
- * - wget
- * if keep-alive is disabled */
-
- if (con->keep_alive == 0) {
- SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
- }
-
- for(c = cq->first; c; c = c->next) {
- int chunk_finished = 0;
-
- switch(c->type) {
- case MEM_CHUNK: {
- char * offset;
- size_t toSend;
- ssize_t r = 0;
-
- if (c->mem->used == 0) {
- chunk_finished = 1;
- break;
- }
-
- offset = c->mem->ptr + c->offset;
- toSend = c->mem->used - 1 - c->offset;
-
- /**
- * 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.
- *
- * SSL_write(..., 0) return 0 which is handle as an error (Success)
- * checking toSend and not calling SSL_write() is simpler
- */
-
- ERR_clear_error();
- if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
- unsigned long err;
-
- switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
- case SSL_ERROR_WANT_WRITE:
- break;
- case SSL_ERROR_SYSCALL:
- /* perhaps we have error waiting in our error-queue */
- if (0 != (err = ERR_get_error())) {
- do {
- ERROR("SSL_write(): SSL_get_error() = %d, SSL_write() = %zd, msg = %s",
- 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 NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("SSL_write(): SSL_get_error() = %d, SSL_write() = %zd, errmsg = %s (%d)",
- ssl_r, r,
- strerror(errno), errno);
- break;
- }
- } else {
- /* neither error-queue nor errno ? */
- ERROR("SSL_write(): SSL_get_error() = %d, SSL_write() = %zd, errmsg = %s (%d)",
- ssl_r, r,
- strerror(errno), errno);
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- case SSL_ERROR_ZERO_RETURN:
- /* clean shutdown on the remote side */
-
- if (r == 0) return NETWORK_STATUS_CONNECTION_CLOSE;
-
- /* fall through */
- default:
- while((err = ERR_get_error())) {
- ERROR("SSL_write(): SSL_get_error() = %d, SSL_write() = %zd, msg = %s",
- ssl_r, r,
- ERR_error_string(err, NULL));
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- } else {
- c->offset += r;
- cq->bytes_out += r;
- }
-
- if (c->offset == (off_t)c->mem->used - 1) {
- chunk_finished = 1;
- }
-
- break;
- }
- case FILE_CHUNK: {
- char *s;
- ssize_t r;
- stat_cache_entry *sce = NULL;
- int ifd;
- int write_wait = 0;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- ERROR("stat_cache_get_entry(%s) failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (NULL == local_send_buffer) {
- local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
- assert(local_send_buffer);
- }
-
- do {
- off_t offset = c->file.start + c->offset;
- off_t toSend = c->file.length - c->offset;
-
- if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
-
- if (-1 == (ifd = open(BUF_STR(c->file.name), O_RDONLY))) {
- ERROR("open(%s) failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
-
- lseek(ifd, offset, SEEK_SET);
- if (-1 == (toSend = read(ifd, local_send_buffer, toSend))) {
- close(ifd);
-
- ERROR("read(%s) failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- s = local_send_buffer;
-
- close(ifd);
-
- ERR_clear_error();
- if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
- unsigned long err;
-
- switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
- case SSL_ERROR_WANT_WRITE:
- write_wait = 1;
- break;
- case SSL_ERROR_SYSCALL:
- /* perhaps we have error waiting in our error-queue */
- if (0 != (err = ERR_get_error())) {
- do {
- ERROR("SSL_write(): ssl-error: %d (ret = %zd): %s",
- 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 NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("SSL_write(): ssl-error: %d (ret = %zd). errno=%d, %s",
- ssl_r, r, errno,
- strerror(errno));
- break;
- }
- } else {
- ERROR("SSL_write(): ssl-error: %d (ret = %zd). errno=%d, %s",
- ssl_r, r, errno,
- strerror(errno));
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- case SSL_ERROR_ZERO_RETURN:
- /* clean shutdown on the remote side */
-
- if (r == 0) return NETWORK_STATUS_CONNECTION_CLOSE;
-
- /* fall thourgh */
- default:
- while((err = ERR_get_error())) {
- ERROR("SSL_write(): ssl-error: %d (ret = %zd), %s",
- ssl_r, r,
- ERR_error_string(err, NULL));
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- } else {
- c->offset += r;
- cq->bytes_out += r;
- }
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
- }
- } while(!chunk_finished && !write_wait);
-
- break;
- }
- default:
- ERROR("type not known: %d", c->type);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-#endif
-
-#if 0
-network_openssl_init(void) {
- p->write_ssl = network_openssl_write_chunkset;
-}
-#endif
diff --git a/src/network_posix_aio.c b/src/network_posix_aio.c
deleted file mode 100644
index b77abb22..00000000
--- a/src/network_posix_aio.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* we need O_DIRECT */
-#endif
-
-#include "network_backends.h"
-
-#ifdef USE_POSIX_AIO
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include <aio.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "joblist.h"
-
-#include "sys-files.h"
-#include "status_counter.h"
-
-typedef struct {
- server *srv;
- connection *con;
-
- struct aiocb *iocb;
-
- chunk *c;
-} write_job;
-
-static write_job *write_job_init() {
- write_job *wj = calloc(1, sizeof(*wj));
-
- return wj;
-}
-
-static void write_job_free(write_job *wj) {
- if (!wj) return;
-
- free(wj);
-}
-
-#if (defined(__FreeBSD__) || defined(__DragonFly__))
-/* someone is wrong here, both (MacOS X and FreeBSD) reference POSIX 1003.1b but have
- * different names (in /usr/include/sys/signal.h) */
-#define sival_ptr sigval_ptr
-#endif
-
-/**
- * handle the completion of a AIO-read() operation
- *
- * Linux has 'union sigval' and 'sigval_t'
- * MacOS X and FreeBSD only 'union sigval'
- * */
-static void posix_aio_completion_handler(union sigval foo) {
- write_job *wj = (write_job *)foo.sival_ptr;
- server *srv = wj->srv;
- connection *con = wj->con;
- struct aiocb *iocb = wj->iocb;
- chunk *c = wj->c;
- int res;
-
- if (srv->is_shutdown) {
- write_job_free(wj);
-
- return;
- }
-
- res = aio_error(iocb);
-
- if (res != EINPROGRESS) {
- switch (res) {
- case ECANCELED:
- TRACE("aio-op was canceled, was asked for %s (fd = %d)",
- SAFE_BUF_STR(con->uri.path), con->sock->fd);
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- break;
- case 0:
- break;
- default:
- TRACE("aio-op failed with %d (%s), was asked for %s (fd = %d)",
- res, strerror(res), SAFE_BUF_STR(con->uri.path), con->sock->fd);
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- break;
- }
-
- if ((res = aio_return(iocb)) < 0) {
- /* we have an error */
-
- TRACE("aio-return returned %d (%s), was asked for %s (fd = %d)",
- res, strerror(res), SAFE_BUF_STR(con->uri.path), con->sock->fd);
-
- c->async.ret_val = NETWORK_STATUS_FATAL_ERROR;
- }
-
- joblist_async_append(srv, con);
-
- iocb->aio_nbytes = 0; /* mark the entry as unused */
- }
-
- write_job_free(wj);
-}
-
-NETWORK_BACKEND_WRITE(posixaio) {
- chunk *c, *tc;
-
- for(c = cq->first; c; c = c->next) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc && chunk_is_done(tc); tc = tc->next) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- ssize_t r;
- int rounds = 8;
-
- /* open file if not already opened */
- if (-1 == c->file.fd) {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY | /* O_DIRECT | */ (srv->srvconf.use_noatime ? O_NOATIME : 0)))) {
- if (errno == EMFILE) return NETWORK_STATUS_WAIT_FOR_FD;
-
- ERROR("opening '%s' failed: %s", SAFE_BUF_STR(c->file.name), strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
- }
-
- do {
- size_t toSend;
- const off_t max_toSend = 4 * 256 * 1024; /** should be larger than the send buffer */
- off_t offset;
-
- offset = c->file.start + c->offset;
-
- toSend = c->file.length - c->offset > max_toSend ?
- max_toSend : c->file.length - c->offset;
-
- if (0 == c->file.copy.length) {
- int async_error = 0;
-
- size_t iocb_ndx;
-
- c->file.copy.offset = 0;
- c->file.copy.length = 0;
-
- /* if we reused the previous tmp-file we get overlaps
- *
- * 1 ... 3904 are ok
- * 3905 ... 4096 are replaces by 8001 ... 8192
- *
- * somehow the second read writes into the mmap() before
- * the sendfile is finished which is very strange.
- *
- * if someone finds the reason for this, feel free to remove
- * this if again and number of reduce the syscalls a bit.
- */
- if (c->file.mmap.start) {
- munmap(c->file.mmap.start, c->file.mmap.length);
- c->file.mmap.start = MAP_FAILED;
- }
-
- if (-1 != c->file.copy.fd) {
- close(c->file.copy.fd);
- c->file.copy.fd = -1;
- }
-
- /* do we have a IOCB we can use ? */
-
- for (iocb_ndx = 0; async_error == 0 && iocb_ndx < srv->srvconf.max_read_threads; iocb_ndx++) {
- if (0 == srv->posix_aio_iocbs[iocb_ndx].aio_nbytes) {
- break;
- }
- }
-
- if (iocb_ndx == srv->srvconf.max_read_threads) {
- async_error = 1;
- }
-
-
- /* get mmap()ed mem-block in /dev/shm
- *
- * in case we don't have a iocb available, we still need the mmap() for the blocking
- * read()
- * */
-#if defined(HAVE_MEM_MMAP_ZERO)
- if (-1 == c->file.copy.fd ) {
- int mmap_fd = -1;
-
- /* open a file in /dev/shm to write to */
- if (-1 == (mmap_fd = open("/dev/zero", O_RDWR))) {
- async_error = 1;
-
- if (errno != EMFILE) {
- TRACE("open(/dev/zero) returned: %d (%s), falling back to sync-io",
- errno, strerror(errno));
- } else {
- return NETWORK_STATUS_WAIT_FOR_FD;
- }
- } else {
- c->file.mmap.offset = 0;
- c->file.mmap.length = toSend;
-
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, 0);
- if (c->file.mmap.start == MAP_FAILED) {
- async_error = 1;
- } else {
- c->file.copy.length = toSend;
- }
-
- close(mmap_fd);
- mmap_fd = -1;
-
- }
- }
-#elif defined(HAVE_MEM_MMAP_ANON)
- c->file.mmap.offset = 0;
- c->file.mmap.length = c->file.copy.length; /* align to page-size */
- c->file.mmap.start = mmap(0, c->file.mmap.length,
- PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
-
- if (c->file.mmap.start == MAP_FAILED) {
- async_error = 1;
- }
-#else
-#error hmm, does your system support mmap(/dev/zero) or mmap(MAP_ANON)
-#endif
-
- /* looks like we couldn't get a temp-file [disk-full]
- *
- * if we only have 4k to send we can fall back to sync-read as either the read-ahead
- * or the stat() has put the data into the fs-buffers
- *
- * the 4kbyte are guessed ... someone should benchmark it.
- *
- * */
- if (async_error == 0 && c->file.mmap.start != MAP_FAILED && c->file.length > 4 * 1024) {
- struct aiocb *iocb = NULL;
- write_job *wj;
-
- assert(c->file.copy.length > 0);
-
- iocb = &srv->posix_aio_iocbs[iocb_ndx];
-
- memset(iocb, 0, sizeof(*iocb));
-
- iocb->aio_fildes = c->file.fd;
- iocb->aio_buf = c->file.mmap.start;
- iocb->aio_nbytes = c->file.copy.length;
- iocb->aio_offset = c->file.start + c->offset;
-
- wj = write_job_init();
- wj->srv = srv;
- wj->con = con;
- wj->iocb = iocb;
-
- iocb->aio_sigevent.sigev_notify_function = posix_aio_completion_handler;
- iocb->aio_sigevent.sigev_notify_attributes = NULL;
- iocb->aio_sigevent.sigev_value.sival_ptr = wj;
- iocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
-
- if (0 == aio_read(iocb)) {
- status_counter_inc(CONST_STR_LEN("server.io.posix-aio.async-read"));
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
- } else {
- if (errno != EAGAIN) {
- TRACE("aio_read returned: %d (%s), falling back to sync-io",
- errno, strerror(errno));
- } else {
- TRACE("aio_read returned EAGAIN on (%d - %d), -> sync-io", c->file.fd, c->file.copy.fd);
- }
- }
- }
-
- /* fall back to a blocking read */
-
- if (c->file.mmap.start != MAP_FAILED) {
- status_counter_inc(CONST_STR_LEN("server.io.posix-aio.sync-read"));
-
- assert(c->file.copy.length > 0);
-
- lseek(c->file.fd, c->file.start + c->offset, SEEK_SET);
-
- if (-1 == (r = read(c->file.fd, c->file.mmap.start, c->file.copy.length))) {
- switch(errno) {
- default:
- ERROR("reading file failed: %d (%s)", errno, strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- ERROR("read() returned 0 ... not good: %s", "");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (r != c->file.copy.length) {
- ERROR("read() returned %zd instead of %jd", r, (intmax_t) c->file.copy.length);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- } else {
- ERROR("the mmap() failed, no way for a fallback: %s", "");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- } else if (c->file.copy.offset == 0) {
-#if 0
- /**
- * aio_write only creates extra-trouble
- *
- * instead we use the classic non-blocking-io write() call on the socket
- */
- size_t iocb_ndx;
- struct aiocb *iocb = NULL;
-
- /* the aio_read() is finished, send it */
-
- /* do we have a IOCB we can use ? */
-
- for (iocb_ndx = 0; iocb_ndx < POSIX_AIO_MAX_IOCBS; iocb_ndx++) {
- if (NULL == srv->posix_aio_data[iocb_ndx]) {
- break;
- }
- }
-
- assert(iocb_ndx != POSIX_AIO_MAX_IOCBS);
-
- iocb = &srv->posix_aio_iocbs[iocb_ndx];
- memset(iocb, 0, sizeof(*iocb));
-
- iocb->aio_fildes = sock->fd;
- iocb->aio_buf = c->file.mmap.start;
- iocb->aio_nbytes = c->file.copy.length;
- iocb->aio_offset = 0;
-
- /* the write should only return when it is finished */
- fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL) & ~O_NONBLOCK);
-
- if (0 != aio_write(iocb)) {
- TRACE("aio-write failed: %d (%s)", errno, strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- srv->have_aio_waiting++;
-
- srv->posix_aio_iocbs_watch[iocb_ndx] = iocb;
- srv->posix_aio_data[iocb_ndx] = con;
-
- /* in case we come back: we have written everything */
- c->file.copy.offset = c->file.copy.length;
-
- return NETWORK_STATUS_WAIT_FOR_AIO_EVENT;
-#endif
- }
-
- if (-1 == (r = write(sock->fd, c->file.mmap.start + c->file.copy.offset, c->file.copy.length - c->file.copy.offset))) {
- switch (errno) {
- case EINTR:
- case EAGAIN:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("write failed: %d (%s) [%jd, %p, %jd]",
- errno, strerror(errno), (intmax_t) c->file.copy.length,
- c->file.mmap.start, (intmax_t) c->file.copy.offset);
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- return NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
- c->file.copy.offset += r; /* offset in the copy-chunk */
-
- c->offset += r; /* global offset in the file */
- cq->bytes_out += r;
-
- if ((off_t) c->file.mmap.length == c->file.copy.offset) {
- munmap(c->file.mmap.start, c->file.mmap.length);
- c->file.mmap.start = MAP_FAILED;
- c->file.copy.length = 0;
- }
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- if (c->file.copy.fd != -1) {
- close(c->file.copy.fd);
- c->file.copy.fd = -1;
- }
-
- if (c->file.fd != -1) {
- close(c->file.fd);
- c->file.fd = -1;
- }
- }
-
- /* the chunk is larger and the current snippet is finished */
- } while (c->file.copy.length == 0 && chunk_finished == 0 && rounds-- > 0);
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
-
diff --git a/src/network_solaris_sendfilev.c b/src/network_solaris_sendfilev.c
deleted file mode 100644
index 1a0aa965..00000000
--- a/src/network_solaris_sendfilev.c
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "network_backends.h"
-
-#ifdef USE_SOLARIS_SENDFILEV
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-#ifndef UIO_MAXIOV
-#define UIO_MAXIOV IOV_MAX
-#endif
-
-/**
- * a very simple sendfilev() interface for solaris which can be optimised a lot more
- * as solaris sendfilev() supports 'sending everythin in one syscall()'
- *
- * If you want such an interface and need the performance, just give me an account on
- * a solaris box.
- * - jan@kneschke.de
- */
-
-
-NETWORK_BACKEND_WRITE(solarissendfilev) {
- chunk *c, *tc;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc; tc = tc->next) {
- /* finished the chunk */
- if (tc->offset == tc->mem->used - 1) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- } else {
- break;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- ssize_t r;
- off_t offset;
- size_t toSend, written = 0;
- sendfilevec_t fvec;
- stat_cache_entry *sce = NULL;
- int ifd;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), c->file.name);
- return -1;
- }
-
- offset = c->file.start + c->offset;
- toSend = c->file.length - c->offset;
-
- if (offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
-
- return -1;
- }
-
- if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
- return -1;
- }
-
- fvec.sfv_fd = ifd;
- fvec.sfv_flag = 0;
- fvec.sfv_off = offset;
- fvec.sfv_len = toSend;
-
- /* Solaris sendfilev() */
- if (-1 == (r = sendfilev(sock->fd, &fvec, 1, &written))) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- break;
- default:
- ERROR("sendfilev() failed: %s (errno=%d)", strerror(errno), errno);
-
- close(ifd);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- r = 0;
- }
-
- close(ifd);
- c->offset += written;
- cq->bytes_out += written;
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
- }
-
- break;
- }
- default:
- ERROR("chunk-type '%s' is not known", c->type);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/network_win32_send.c b/src/network_win32_send.c
deleted file mode 100644
index 0ee3f4aa..00000000
--- a/src/network_win32_send.c
+++ /dev/null
@@ -1,265 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-#include "sys-socket.h"
-#include "sys-files.h"
-
-#include "network_backends.h"
-
-#ifdef USE_WIN32_SEND
-/**
-* fill the chunkqueue will all the data that we can get
-*
-* this might be optimized into a readv() which uses the chunks
-* as vectors
-*
-* - This is pretty much a copy of the generic network_read receiver.
-*
-*/
-NETWORK_BACKEND_READ(win32recv)
-{
- int toread, read_offset;
- buffer *b;
- off_t r, start_bytes_in;
- off_t max_read = 256 * 1024;
-
- /**
- * a EAGAIN is a successful read if we already read something to the chunkqueue
- */
- int read_something = 0;
-
- UNUSED(srv);
- UNUSED(con);
-
- start_bytes_in = cq->bytes_in;
-
- /* use a chunk-size of 4k, append to last buffer if it has >= 1kb free */
-#define TOREAD 4096
-
- do {
- b = (cq->last) ? cq->last->mem : NULL;
-
- if (NULL == b || b->size - b->used < 1024) {
- b = chunkqueue_get_append_buffer(cq);
- buffer_prepare_copy(b, TOREAD+1);
- }
-
- read_offset = (b->used == 0) ? 0 : b->used - 1;
- toread = b->size - 1 - read_offset;
-
- if (-1 == (r = recv(sock->fd, b->ptr + read_offset, toread, 0))) {
- switch (light_sock_errno()) {
- case EAGAIN:
- case EWOULDBLOCK:
- /* remove the last chunk from the chunkqueue */
- chunkqueue_remove_empty_last_chunk(cq);
- return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- chunkqueue_remove_empty_last_chunk(cq);
- return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
- read_something = 1;
-
- if (b->used > 0) b->used--;
- b->used += r;
- b->ptr[b->used++] = '\0';
-
- cq->bytes_in += r;
-
- if (cq->bytes_in - start_bytes_in > max_read) break;
- } while (r == toread);
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-NETWORK_BACKEND_WRITE(win32send)
-{
- chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next)
- {
- int chunk_finished = 0;
-
- switch(c->type)
- {
- case MEM_CHUNK:
- {
- char * offset;
- size_t toSend;
- ssize_t r;
-
- if (c->mem->used == 0) {
- chunk_finished = 1;
- break;
- }
-
- offset = c->mem->ptr + c->offset;
- toSend = c->mem->used - 1 - c->offset;
-
- if ((r = send(sock->fd, offset, toSend, 0)) < 0)
- {
- errno = WSAGetLastError();
-
- switch(errno)
- {
- case WSAEWOULDBLOCK:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case WSAECONNABORTED:
- case WSAECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- log_error_write(srv, __FILE__, __LINE__, "sdd", "send to socket:", errno, sock->fd);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- c->offset += r;
- cq->bytes_out += r;
-
- if (c->offset == (off_t)c->mem->used - 1) {
- chunk_finished = 1;
- }
-
- break;
- }
- case FILE_CHUNK:
- {
- ssize_t r;
- off_t offset;
-
- stat_cache_entry *sce = NULL;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce))
- {
- log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), c->file.name);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- offset = c->file.start + c->offset;
-
- if (offset > sce->st.st_size)
- {
- log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
-
- if (-1 == c->file.fd)
- {
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY|O_BINARY|O_SEQUENTIAL)))
- {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (-1 == lseek(c->file.fd, offset, SEEK_SET))
- {
- log_error_write(srv, __FILE__, __LINE__, "ss", "lseek failed: ", strerror(errno));
- }
-
- while(1)
- {
- off_t haveRead = 0;
- int finished = 0;
- int toSend;
-
- /* only send 64k blocks */
- toSend = c->file.length - c->offset > 256 * 1024 ? 256 * 1024 : c->file.length - c->offset;
-
- /* BMH. Not 100% sure about this */
- if ( toSend == 0 )
- break;
-
- buffer_prepare_copy(srv->tmp_buf, toSend);
-
- if (-1 == (haveRead = read(c->file.fd, srv->tmp_buf->ptr, toSend)))
- {
- log_error_write(srv, __FILE__, __LINE__, "ss", "read from file: ", strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, haveRead, 0)))
- {
- errno = WSAGetLastError();
-
- switch(errno)
- {
- case WSAEWOULDBLOCK:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case WSAECONNABORTED:
- case WSAECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- log_error_write(srv, __FILE__, __LINE__, "sd", "send to socket:", errno);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- c->offset += r;
- cq->bytes_out += r;
-
- /* BMH: I don't understand this */
- if (r != haveRead)
- {
- break;
- }
- }
-
- if (c->offset == c->file.length)
- {
- chunk_finished = 1;
- }
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished)
- {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
-
- chunks_written++;
- }
- /* fprintf(stderr, "%s.%d: chunks_written: %d\r\n", __FILE__, __LINE__, chunks_written); */
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/network_write.c b/src/network_write.c
deleted file mode 100644
index 5de91927..00000000
--- a/src/network_write.c
+++ /dev/null
@@ -1,227 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-#include "sys-socket.h"
-#include "sys-files.h"
-
-#include "network_backends.h"
-
-#ifdef USE_WRITE
-
-#ifdef HAVE_SYS_FILIO_H
-# include <sys/filio.h>
-#endif
-
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
-
-/**
-* fill the chunkqueue will all the data that we can get
-*
-* this might be optimized into a readv() which uses the chunks
-* as vectors
-*/
-NETWORK_BACKEND_READ(read) {
- int toread, read_offset;
- buffer *b;
- off_t r, start_bytes_in;
- off_t max_read = 256 * 1024;
-
- /**
- * a EAGAIN is a successful read if we already read something to the chunkqueue
- */
- int read_something = 0;
-
- UNUSED(srv);
- UNUSED(con);
-
- start_bytes_in = cq->bytes_in;
-
- /* use a chunk-size of 4k, append to last buffer if it has >= 1kb free */
-#define TOREAD 4096
-
- do {
- b = (cq->last) ? cq->last->mem : NULL;
-
- if (NULL == b || b->size - b->used < 1024) {
- b = chunkqueue_get_append_buffer(cq);
- buffer_prepare_copy(b, TOREAD+1);
- }
-
- read_offset = (b->used == 0) ? 0 : b->used - 1;
- toread = b->size - 1 - read_offset;
-
- if (-1 == (r = read(sock->fd, b->ptr + read_offset, toread))) {
- switch (errno) {
- case EAGAIN:
- /* remove the last chunk from the chunkqueue */
- chunkqueue_remove_empty_last_chunk(cq);
- return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- if (r == 0) {
- chunkqueue_remove_empty_last_chunk(cq);
- return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
- }
-
- read_something = 1;
-
- if (b->used > 0) b->used--;
- b->used += r;
- b->ptr[b->used++] = '\0';
-
- cq->bytes_in += r;
-
- if (cq->bytes_in - start_bytes_in > max_read) break;
- } while (r == toread);
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-NETWORK_BACKEND_WRITE(write) {
- chunk *c;
-
- for(c = cq->first; c; c = c->next) {
- int chunk_finished = 0;
-
- switch(c->type) {
- case MEM_CHUNK: {
- char * offset;
- size_t toSend;
- ssize_t r;
-
- if (c->mem->used == 0) {
- chunk_finished = 1;
- break;
- }
-
- offset = c->mem->ptr + c->offset;
- toSend = c->mem->used - 1 - c->offset;
-
- if ((r = write(sock->fd, offset, toSend)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- c->offset += r;
- cq->bytes_out += r;
-
- if (c->offset == (off_t)c->mem->used - 1) {
- chunk_finished = 1;
- }
-
- break;
- }
- case FILE_CHUNK: {
-#ifdef USE_MMAP
- char *p = NULL;
-#endif
- ssize_t r;
- off_t offset;
- size_t toSend;
- stat_cache_entry *sce = NULL;
- int ifd;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), c->file.name);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- offset = c->file.start + c->offset;
- toSend = c->file.length - c->offset;
-
- if (offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
-#if defined USE_MMAP
- if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
-
- close(ifd);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- close(ifd);
-
- if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
- munmap(p, sce->st.st_size);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- munmap(p, sce->st.st_size);
-#else
- buffer_prepare_copy(srv->tmp_buf, toSend);
-
- lseek(ifd, offset, SEEK_SET);
- if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
- close(ifd);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- close(ifd);
-
- if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#endif
- c->offset += r;
- cq->bytes_out += r;
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
- }
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/network_writev.c b/src/network_writev.c
deleted file mode 100644
index 63c5dd46..00000000
--- a/src/network_writev.c
+++ /dev/null
@@ -1,356 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* we need O_DIRECT */
-#endif
-
-#include "network_backends.h"
-
-#ifdef USE_WRITEV
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "sys-files.h"
-
-#ifndef UIO_MAXIOV
-# if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
-/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
-# define UIO_MAXIOV 1024
-# elif defined(__sgi)
-/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
-# define UIO_MAXIOV 512
-# elif defined(__sun)
-/* Solaris (and SunOS?) defines IOV_MAX instead */
-# ifndef IOV_MAX
-# define UIO_MAXIOV 16
-# else
-# define UIO_MAXIOV IOV_MAX
-# endif
-# elif defined(IOV_MAX)
-# define UIO_MAXIOV IOV_MAX
-# else
-# error UIO_MAXIOV nor IOV_MAX are defined
-# endif
-#endif
-
-#if 0
-#define LOCAL_BUFFERING 1
-#endif
-
-NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
- char * offset;
- size_t toSend;
- ssize_t r;
-
- size_t num_chunks, i;
- struct iovec chunks[UIO_MAXIOV];
- chunk *tc; /* transfer chunks */
- size_t num_bytes = 0;
-
- UNUSED(con);
- /* we can't send more then SSIZE_MAX bytes in one chunk */
-
- /* build writev list
- *
- * 1. limit: num_chunks < UIO_MAXIOV
- * 2. limit: num_bytes < SSIZE_MAX
- */
- for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
-
- for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
- if (tc->mem->used == 0) {
- chunks[i].iov_base = tc->mem->ptr;
- chunks[i].iov_len = 0;
- } else {
- offset = tc->mem->ptr + tc->offset;
- toSend = tc->mem->used - 1 - tc->offset;
-
- chunks[i].iov_base = offset;
-
- /* protect the return value of writev() */
- if (toSend > SSIZE_MAX ||
- num_bytes + toSend > SSIZE_MAX) {
- chunks[i].iov_len = SSIZE_MAX - num_bytes;
-
- num_chunks = i + 1;
- break;
- } else {
- chunks[i].iov_len = toSend;
- }
-
- num_bytes += toSend;
- }
- }
-
- if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
- switch (errno) {
- case EAGAIN:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case EINTR:
- return NETWORK_STATUS_INTERRUPTED;
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "writev failed:", strerror(errno), sock->fd);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- cq->bytes_out += r;
-
- /* check which chunks have been written */
-
- for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
- if (r >= (ssize_t)chunks[i].iov_len) {
- /* written */
- r -= chunks[i].iov_len;
- tc->offset += chunks[i].iov_len;
- } else {
- /* partially written */
-
- tc->offset += r;
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- /* all chunks have been pushed out */
- return NETWORK_STATUS_SUCCESS;
-}
-
-NETWORK_BACKEND_WRITE(writev) {
- chunk *c, *tc;
-
- for(c = cq->first; c; c = c->next) {
- int chunk_finished = 0;
- network_status_t ret;
-
- switch(c->type) {
- case MEM_CHUNK:
- ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
-
- /* check which chunks are finished now */
- for (tc = c; tc && chunk_is_done(tc); tc = tc->next) {
- /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
- if (chunk_finished) {
- c = c->next;
- } else {
- chunk_finished = 1;
- }
- }
-
- if (ret != NETWORK_STATUS_SUCCESS) {
- return ret;
- }
-
- break;
- case FILE_CHUNK: {
- ssize_t r;
- off_t abs_offset;
- off_t toSend;
- stat_cache_entry *sce = NULL;
-
-#define KByte * 1024
-#define MByte * 1024 KByte
-#define GByte * 1024 MByte
- const off_t we_want_to_mmap = 512 KByte;
- char *start = NULL;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), c->file.name);
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- abs_offset = c->file.start + c->offset;
-
- if (abs_offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "file was shrinked:", c->file.name);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- /* 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 we_want_to_send;
- size_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 */
- we_want_to_send = c->file.length - c->offset;
- to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset;
-
- /* we have more to send than we can mmap() at once */
- if (abs_offset + we_want_to_send > c->file.mmap.offset + we_want_to_mmap) {
- we_want_to_send = (c->file.mmap.offset + we_want_to_mmap) - abs_offset;
- to_mmap = we_want_to_mmap;
- }
-
- if (-1 == c->file.fd) { /* open the file if not already open */
- if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY | (srv->srvconf.use_noatime ? O_NOATIME : 0) ))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-#ifdef FD_CLOEXEC
- fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
-#endif
- }
-
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
- /* close it here, otherwise we'd have to set FD_CLOEXEC */
-
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
- strerror(errno), c->file.name, c->file.fd);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- c->file.mmap.length = to_mmap;
-#ifdef LOCAL_BUFFERING
- buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
-#else
-#ifdef HAVE_MADVISE
- /* don't advise files < 64Kb */
- if (c->file.mmap.length > (64 KByte)) {
- /* darwin 7 is returning EINVAL all the time and I don't know how to
- * detect this at runtime.i
- *
- * ignore the return value for now */
- madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED);
- }
-#endif
-#endif
-
- /* 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 < 0) {
- log_error_write(srv, __FILE__, __LINE__, "soooo",
- "toSend is negative:",
- toSend,
- c->file.mmap.length,
- abs_offset,
- c->file.mmap.offset);
- assert(toSend < 0);
- }
-
-#ifdef LOCAL_BUFFERING
- start = c->mem->ptr;
-#else
- start = c->file.mmap.start;
-#endif
-
- if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- case EPIPE:
- case ECONNRESET:
- return NETWORK_STATUS_CONNECTION_CLOSE;
- default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "write failed:", strerror(errno), sock->fd);
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
- }
-
- c->offset += r;
- cq->bytes_out += r;
-
- if (c->offset == c->file.length) {
- chunk_finished = 1;
-
- /* we don't need the mmaping anymore */
- if (c->file.mmap.start != MAP_FAILED) {
- munmap(c->file.mmap.start, c->file.mmap.length);
- c->file.mmap.start = MAP_FAILED;
- }
- }
-
- break;
- }
- default:
-
- log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
- return NETWORK_STATUS_FATAL_ERROR;
- }
-
- if (!chunk_finished) {
- /* not finished yet */
-
- return NETWORK_STATUS_WAIT_FOR_EVENT;
- }
- }
-
- return NETWORK_STATUS_SUCCESS;
-}
-
-#endif
diff --git a/src/plugin.c b/src/plugin.c
deleted file mode 100644
index 98ccae82..00000000
--- a/src/plugin.c
+++ /dev/null
@@ -1,592 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-
-#include <stdio.h>
-
-#include "plugin.h"
-#include "log.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sys-files.h"
-
-#ifndef _WIN32
-#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_RESPONSE_DONE,
- PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
- PLUGIN_FUNC_HANDLE_TRIGGER,
- PLUGIN_FUNC_HANDLE_SIGHUP,
- PLUGIN_FUNC_HANDLE_START_BACKEND,
- PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT,
- PLUGIN_FUNC_HANDLE_RESPONSE_HEADER,
- PLUGIN_FUNC_HANDLE_READ_RESPONSE_CONTENT,
- PLUGIN_FUNC_HANDLE_FILTER_RESPONSE_CONTENT,
- PLUGIN_FUNC_HANDLE_JOBLIST,
- 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));
-
- p->required_plugins = array_init();
-
- return p;
-}
-
-static void plugin_free(plugin *p) {
- int use_dlclose = 1;
-
- if (p->name) buffer_free(p->name);
-
- array_free(p->required_plugins);
-
- /* if we are running under valgrind,
- * don't unload the plugins to keep the symbols intact */
- if (RUNNING_ON_VALGRIND) use_dlclose = 0;
-
-#ifndef LIGHTTPD_STATIC
- if (use_dlclose && p->lib) {
-#ifdef _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));
- 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));
- }
-
- ps = srv->plugins.ptr;
- ps[srv->plugins.used++] = p;
-
- return 0;
-}
-
-/**
- *
- *
- *
- */
-
-#ifdef LIGHTTPD_STATIC
-
-#define PLUGIN_STATIC(x) int x ## _plugin_init(plugin *p)
-
-PLUGIN_STATIC(mod_access);
-PLUGIN_STATIC(mod_accesslog);
-PLUGIN_STATIC(mod_alias);
-PLUGIN_STATIC(mod_auth);
-PLUGIN_STATIC(mod_cgi);
-PLUGIN_STATIC(mod_dirlisting);
-PLUGIN_STATIC(mod_evasive);
-PLUGIN_STATIC(mod_evhost);
-PLUGIN_STATIC(mod_expire);
-PLUGIN_STATIC(mod_deflate);
-PLUGIN_STATIC(mod_compress);
-PLUGIN_STATIC(mod_flv_streaming);
-PLUGIN_STATIC(mod_chunked);
-PLUGIN_STATIC(mod_indexfile);
-PLUGIN_STATIC(mod_mysql_vhost);
-PLUGIN_STATIC(mod_postgresql_vhost);
-PLUGIN_STATIC(mod_proxy_backend_ajp13);
-PLUGIN_STATIC(mod_proxy_backend_fastcgi);
-PLUGIN_STATIC(mod_proxy_backend_http);
-PLUGIN_STATIC(mod_proxy_backend_scgi);
-PLUGIN_STATIC(mod_proxy_core);
-PLUGIN_STATIC(mod_redirect);
-PLUGIN_STATIC(mod_rewrite);
-PLUGIN_STATIC(mod_secdownload);
-PLUGIN_STATIC(mod_setenv);
-PLUGIN_STATIC(mod_simple_vhost);
-PLUGIN_STATIC(mod_sql_vhost_core);
-PLUGIN_STATIC(mod_ssi);
-PLUGIN_STATIC(mod_staticfile);
-PLUGIN_STATIC(mod_status);
-PLUGIN_STATIC(mod_trigger_b4_dl);
-PLUGIN_STATIC(mod_uploadprogress);
-PLUGIN_STATIC(mod_userdir);
-PLUGIN_STATIC(mod_usertrack);
-PLUGIN_STATIC(mod_webdav);
-PLUGIN_STATIC(mod_magnet);
-
-#undef PLUGIN_STATIC
-
-#define PLUGIN_STATIC(x) { #x, x ## _plugin_init }
-
-struct {
- const char *name;
- int (*init)(plugin *pl);
-} const static_plugins[] = {
-PLUGIN_STATIC(mod_access),
-PLUGIN_STATIC(mod_accesslog),
-PLUGIN_STATIC(mod_alias),
-PLUGIN_STATIC(mod_auth),
-PLUGIN_STATIC(mod_cgi),
-PLUGIN_STATIC(mod_dirlisting),
-PLUGIN_STATIC(mod_evasive),
-PLUGIN_STATIC(mod_evhost),
-PLUGIN_STATIC(mod_expire),
-PLUGIN_STATIC(mod_deflate),
-PLUGIN_STATIC(mod_compress),
-PLUGIN_STATIC(mod_flv_streaming),
-PLUGIN_STATIC(mod_chunked),
-PLUGIN_STATIC(mod_indexfile),
-PLUGIN_STATIC(mod_mysql_vhost),
-PLUGIN_STATIC(mod_postgresql_vhost),
-PLUGIN_STATIC(mod_proxy_backend_ajp13),
-PLUGIN_STATIC(mod_proxy_backend_fastcgi),
-PLUGIN_STATIC(mod_proxy_backend_http),
-PLUGIN_STATIC(mod_proxy_backend_scgi),
-PLUGIN_STATIC(mod_proxy_core),
-PLUGIN_STATIC(mod_redirect),
-PLUGIN_STATIC(mod_rewrite),
-PLUGIN_STATIC(mod_secdownload),
-PLUGIN_STATIC(mod_setenv),
-PLUGIN_STATIC(mod_simple_vhost),
-PLUGIN_STATIC(mod_sql_vhost_core),
-PLUGIN_STATIC(mod_ssi),
-PLUGIN_STATIC(mod_staticfile),
-PLUGIN_STATIC(mod_status),
-PLUGIN_STATIC(mod_trigger_b4_dl),
-PLUGIN_STATIC(mod_uploadprogress),
-PLUGIN_STATIC(mod_userdir),
-PLUGIN_STATIC(mod_usertrack),
-PLUGIN_STATIC(mod_webdav),
-PLUGIN_STATIC(mod_magnet),
-
- { NULL, NULL }
-};
-
-#undef PLUGIN_STATIC
-
-#endif
-
-int plugins_load(server *srv) {
- plugin *p;
- int (*init)(plugin *pl);
-
- const char *error;
- size_t i, j, k;
-
- for (i = 0; i < srv->srvconf.modules->used; i++) {
- data_string *d = (data_string *)srv->srvconf.modules->data[i];
- char *modules = d->value->ptr;
-
- p = plugin_init();
-
-#ifdef LIGHTTPD_STATIC
- for (j = 0; static_plugins[j].name; j++) {
- if (0 == strcmp(BUF_STR(d->value), static_plugins[j].name)) {
- init = static_plugins[j].init;
-
- break;
- }
- }
-
- if (static_plugins[j].name == NULL) {
- ERROR("the plugin '%s' is not compiled in", SAFE_BUF_STR(d->value));
- return -1;
- }
-#else
- buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
-
- if (strlen(srv->srvconf.modules_dir->ptr) != 0) buffer_append_string(srv->tmp_buf, DIR_SEPERATOR_STR);
- buffer_append_string(srv->tmp_buf, modules);
-#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
-
-#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_reset(srv->tmp_buf);
- buffer_copy_string(srv->tmp_buf, modules);
- buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
-
-#ifdef _WIN32
- init = (int (*)(plugin *pl)) 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 ((error = dlerror()) != NULL) {
- ERROR("dlsym(%s) failed: %s", SAFE_BUF_STR(srv->tmp_buf), error);
-
- plugin_free(p);
- return -1;
- }
-
-#endif
-#endif
- if ((*init)(p)) {
- ERROR("plugin-init failed for %s", SAFE_BUF_STR(d->value));
-
- plugin_free(p);
- return -1;
- }
-
- /* check if the required plugin is loaded */
- for (k = 0; k < p->required_plugins->used; k++) {
- data_string *req = (data_string *)p->required_plugins->data[k];
-
- for (j = 0; j < i; j++) {
- data_string *mod = (data_string *)srv->srvconf.modules->data[j];
-
- if (buffer_is_equal(req->value, mod->value)) break;
- }
-
- if (j == i) {
- /* not found */
- log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
-
- plugin_free(p);
-
- return -1;
- }
- }
- plugins_register(srv, p);
- }
-
- return 0;
-}
-
-#define PLUGIN_TO_SLOT(x, y) \
- handler_t plugins_call_##y(server *srv, connection *con) {\
- 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, 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:\
- if (con->conf.log_request_handling) TRACE("-- plugins_call_...: plugin '%s' returns %d", SAFE_BUF_STR(p->name), r); \
- return r;\
- default:\
- ERROR("-- plugins_call_...: plugin '%s' returns %d (unexpected)", SAFE_BUF_STR(p->name), r); \
- 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_DOCROOT, handle_docroot)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_HEADER, handle_response_header)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_READ_RESPONSE_CONTENT, handle_read_response_content)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_FILTER_RESPONSE_CONTENT, handle_filter_response_content)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done)
-PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
-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
-
-#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));
-
- 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));\
- ((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_DOCROOT, handle_docroot);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_HEADER, handle_response_header);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_READ_RESPONSE_CONTENT, handle_read_response_content);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_FILTER_RESPONSE_CONTENT, handle_filter_response_content)
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
-
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
- 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);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
-#undef PLUGIN_TO_SLOT
-
- if (p->init) {
- if (NULL == (p->data = p->init(srv))) {
- 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;
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * get the config-storage of the named plugin
- */
-void *plugin_get_config(server *srv, const char *name) {
- size_t i;
-
- for (i = 0; i < srv->plugins.used; i++) {
- plugin *p = ((plugin **)srv->plugins.ptr)[i];
-
- if (buffer_is_equal_string(p->name, name, strlen(name))) {
- return p->data;
- }
- }
-
- return NULL;
-}
-
-void plugins_free(server *srv) {
- size_t i;
- plugins_call_cleanup(srv);
-
- for (i = 0; i < srv->plugins.used; i++) {
- plugin *p = ((plugin **)srv->plugins.ptr)[i];
-
- plugin_free(p);
- }
-
- for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
- plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
-
- if (slot) free(slot);
- }
-
- free(srv->plugin_slots);
- srv->plugin_slots = NULL;
-
- free(srv->plugins.ptr);
- srv->plugins.ptr = NULL;
- srv->plugins.used = 0;
-}
diff --git a/src/plugin.h b/src/plugin.h
deleted file mode 100644
index 112c4f7c..00000000
--- a/src/plugin.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef _PLUGIN_H_
-#define _PLUGIN_H_
-
-#include "settings.h"
-#include "base.h"
-#include "buffer.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(server *srv)
-/*
- * The PATCH_OPTION() macro is used in the patch_connection() functions
- * of the modules to update the config object for the current request.
- */
-#define PATCH_OPTION(x) \
- p->conf.x = s->x
-
-#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 JOBLIST_FUNC CONNECTION_FUNC
-#define PHYSICALPATH_FUNC CONNECTION_FUNC
-#define REQUESTDONE_FUNC CONNECTION_FUNC
-#define URIHANDLER_FUNC CONNECTION_FUNC
-
-#define PLUGIN_DATA size_t id
-
-/**
- * we have 4 states on the connection:
- * - read-header
- * - read-content
- * - write-header
- * - write-content
- */
-
-typedef struct {
- size_t version;
-
- buffer *name; /* name of the plugin */
-
- void *(* init) (server *srv);
- handler_t (* set_defaults) (server *srv, void *p_d);
- handler_t (* cleanup) (server *srv, void *p_d);
- /* is called ... */
- handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
- handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
-
- handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set (mod_rewrite) */
- handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set (mod_access, mod_auth) */
- handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root (e.g. mod_simple_vhost) */
- handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path (e.g. mod_alias, mod_proxy_core) */
- handler_t (* handle_start_backend) (server *srv, connection *con, void *p_d); /* file exists locally (e.g. mod_staticfile) */
- handler_t (* handle_send_request_content)(server *srv, connection *con, void *p_d); /* a handler for the request content */
- handler_t (* handle_response_header) (server *srv, connection *con, void *p_d); /* a handler for the request content */
- handler_t (* handle_read_response_content)(server *srv, connection *con, void *p_d); /* read the content from the source and push it to the next queue */
- handler_t (* handle_filter_response_content)(server *srv, connection *con, void *p_d); /* apply filters to response content (compression/chunk encoding/ etc..) */
- handler_t (* handle_response_done) (server *srv, connection *con, void *p_d); /* after the response is sent (e.g. mod_accesslog) */
- handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* end of a request-response cycle (mod_acceslog, mod_proxy_core) */
- handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection [remove-me ?] */
- handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled [remove-me ?] */
-
- void *data;
-
- /* dlopen handle */
- void *lib;
-
- array *required_plugins;
-} plugin;
-
-LI_EXPORT int plugins_load(server *srv);
-LI_EXPORT void plugins_free(server *srv);
-
-LI_EXPORT handler_t plugins_call_handle_uri_raw(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_docroot(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_physical(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_start_backend(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_send_request_content(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_response_header(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_read_response_content(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_filter_response_content(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_response_done(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_connection_close(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_handle_joblist(server *srv, connection *con);
-LI_EXPORT handler_t plugins_call_connection_reset(server *srv, connection *con);
-
-LI_EXPORT handler_t plugins_call_handle_trigger(server *srv);
-LI_EXPORT handler_t plugins_call_handle_sighup(server *srv);
-
-LI_EXPORT handler_t plugins_call_init(server *srv);
-LI_EXPORT handler_t plugins_call_set_defaults(server *srv);
-LI_EXPORT handler_t plugins_call_cleanup(server *srv);
-
-LI_EXPORT int config_insert_values_global(server *srv, array *ca, const config_values_t *cv);
-LI_EXPORT int config_insert_values_internal(server *srv, array *ca, const config_values_t *cv);
-LI_EXPORT int config_setup_connection(server *srv, connection *con);
-LI_EXPORT int config_patch_connection(server *srv, connection *con, comp_key_t comp);
-LI_EXPORT int config_check_cond(server *srv, connection *con, data_config *dc);
-LI_EXPORT int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
-LI_EXPORT int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
-
-LI_EXPORT void* plugin_get_config(server *srv, const char *name);
-
-#endif
diff --git a/src/proc_open.c b/src/proc_open.c
deleted file mode 100644
index 7e010922..00000000
--- a/src/proc_open.c
+++ /dev/null
@@ -1,395 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include "proc_open.h"
-
-#ifdef _WIN32
-#include <io.h>
-#include <fcntl.h>
-#else
-#include <sys/wait.h>
-#include <unistd.h>
-#endif
-
-
-#ifdef _WIN32
-/* {{{ win32 stuff */
-# define SHELLENV "ComSpec"
-# define SECURITY_DC , SECURITY_ATTRIBUTES *security
-# define SECURITY_CC , security
-# define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
-static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
-{
- HANDLE copy, self = GetCurrentProcess();
-
- if (!DuplicateHandle(self, src, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS |
- (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
- return NULL;
- return copy;
-}
-# define close_descriptor(fd) CloseHandle(fd)
-static void pipe_close_parent(pipe_t *p) {
- /* don't let the child inherit the parent side of the pipe */
- p->parent = dup_handle(p->parent, FALSE, TRUE);
-}
-static void pipe_close_child(pipe_t *p) {
- close_descriptor(p->child);
- p->fd = _open_osfhandle((long)p->parent,
- (p->fd == 0 ? O_RDONLY : O_WRONLY)|O_BINARY);
-}
-/* }}} */
-#else /* _WIN32 */
-/* {{{ unix way */
-# define SHELLENV "SHELL"
-# define SECURITY_DC
-# define SECURITY_CC
-# define close_descriptor(fd) close(fd)
-static void pipe_close_parent(pipe_t *p) {
- /* don't close stdin */
- close_descriptor(p->parent);
- if (dup2(p->child, p->fd) != p->fd) {
- perror("pipe_child dup2");
- } else {
- close_descriptor(p->child);
- p->child = p->fd;
- }
-}
-static void pipe_close_child(pipe_t *p) {
- close_descriptor(p->child);
- p->fd = p->parent;
-}
-/* }}} */
-#endif /* _WIN32 */
-
-/* {{{ pipe_close */
-static void pipe_close(pipe_t *p) {
- close_descriptor(p->parent);
- close_descriptor(p->child);
-#ifdef _WIN32
- close(p->fd);
-#endif
-}
-/* }}} */
-/* {{{ pipe_open */
-static int pipe_open(pipe_t *p, int fd SECURITY_DC) {
- descriptor_t newpipe[2];
-
- if (0 != pipe(newpipe)) {
- fprintf(stderr, "can't open pipe");
- return -1;
- }
- if (0 == fd) {
- p->parent = newpipe[1]; /* write */
- p->child = newpipe[0]; /* read */
- } else {
- p->parent = newpipe[0]; /* read */
- p->child = newpipe[1]; /* write */
- }
- p->fd = fd;
-
- return 0;
-}
-/* }}} */
-
-/* {{{ proc_open_pipes */
-static int proc_open_pipes(proc_handler_t *proc SECURITY_DC) {
- if (pipe_open(&(proc->in), 0 SECURITY_CC) != 0) {
- return -1;
- }
- if (pipe_open(&(proc->out), 1 SECURITY_CC) != 0) {
- return -1;
- }
- if (pipe_open(&(proc->err), 2 SECURITY_CC) != 0) {
- return -1;
- }
- return 0;
-}
-/* }}} */
-/* {{{ proc_close_pipes */
-static void proc_close_pipes(proc_handler_t *proc) {
- pipe_close(&proc->in);
- pipe_close(&proc->out);
- pipe_close(&proc->err);
-}
-/* }}} */
-/* {{{ proc_close_parents */
-static void proc_close_parents(proc_handler_t *proc) {
- pipe_close_parent(&proc->in);
- pipe_close_parent(&proc->out);
- pipe_close_parent(&proc->err);
-}
-/* }}} */
-/* {{{ proc_close_childs */
-static void proc_close_childs(proc_handler_t *proc) {
- pipe_close_child(&proc->in);
- pipe_close_child(&proc->out);
- pipe_close_child(&proc->err);
-}
-/* }}} */
-
-#ifdef _WIN32
-/* {{{ proc_close */
-int proc_close(proc_handler_t *proc) {
- proc_pid_t child = proc->child;
- DWORD wstatus;
-
- proc_close_pipes(proc);
- WaitForSingleObject(child, INFINITE);
- GetExitCodeProcess(child, &wstatus);
- CloseHandle(child);
-
- return wstatus;
-}
-/* }}} */
-/* {{{ proc_open */
-int proc_open(proc_handler_t *proc, const char *command) {
- PROCESS_INFORMATION pi;
- STARTUPINFO si;
- BOOL procok;
- SECURITY_ATTRIBUTES security;
- const char *shell = NULL;
- const char *windir = NULL;
- buffer *cmdline;
-
- if (NULL == (shell = getenv(SHELLENV)) &&
- NULL == (windir = getenv("SystemRoot")) &&
- NULL == (windir = getenv("windir"))) {
- fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
- return -1;
- }
-
- /* we use this to allow the child to inherit handles */
- memset(&security, 0, sizeof(security));
- security.nLength = sizeof(security);
- security.bInheritHandle = TRUE;
- security.lpSecurityDescriptor = NULL;
-
- if (proc_open_pipes(proc, &security) != 0) {
- return -1;
- }
- proc_close_parents(proc);
-
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = proc->in.child;
- si.hStdOutput = proc->out.child;
- si.hStdError = proc->err.child;
-
- memset(&pi, 0, sizeof(pi));
-
- cmdline = buffer_init();
- if (shell) {
- buffer_append_string(cmdline, shell);
- } else {
- buffer_append_string(cmdline, windir);
- buffer_append_string_len(cmdline, CONST_STR_LEN("\\system32\\cmd.exe"));
- }
- buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
- buffer_append_string(cmdline, command);
- procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
- NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
-
- if (FALSE == procok) {
- fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
- buffer_free(cmdline);
- return -1;
- }
- buffer_free(cmdline);
-
- proc->child = pi.hProcess;
- CloseHandle(pi.hThread);
-
- proc_close_childs(proc);
-
- return 0;
-}
-/* }}} */
-#else /* _WIN32 */
-/* {{{ proc_close */
-int proc_close(proc_handler_t *proc) {
- pid_t child = proc->child;
- int wstatus;
- pid_t wait_pid;
-
- proc_close_pipes(proc);
-
- do {
- wait_pid = waitpid(child, &wstatus, 0);
- } while (wait_pid == -1 && errno == EINTR);
-
- if (wait_pid == -1) {
- return -1;
- } else {
- if (WIFEXITED(wstatus))
- wstatus = WEXITSTATUS(wstatus);
- }
-
- return wstatus;
-}
-/* }}} */
-/* {{{ proc_open */
-int proc_open(proc_handler_t *proc, const char *command) {
- pid_t child;
- const char *shell;
-
- if (NULL == (shell = getenv(SHELLENV))) {
- shell = "/bin/sh";
- }
-
- if (proc_open_pipes(proc) != 0) {
- return -1;
- }
-
- /* the unix way */
-
- child = fork();
-
- if (child == 0) {
- /* this is the child process */
-
- /* close those descriptors that we just opened for the parent stuff,
- * dup new descriptors into required descriptors and close the original
- * cruft
- */
- proc_close_parents(proc);
-
- execl(shell, shell, "-c", command, (char *)NULL);
- _exit(127);
-
- } else if (child < 0) {
- fprintf(stderr, "failed to forking");
- proc_close(proc);
- return -1;
-
- } else {
- proc->child = child;
- proc_close_childs(proc);
- return 0;
- }
-}
-/* }}} */
-#endif /* _WIN32 */
-
-/* {{{ proc_read_fd_to_buffer */
-static void proc_read_fd_to_buffer(int fd, buffer *b) {
- int s; /* win32 has not ssize_t */
-
- for (;;) {
- buffer_prepare_append(b, 512);
- if ((s = read(fd, (void *)(b->ptr + b->used), 512 - 1)) <= 0) {
- break;
- }
- b->used += s;
- }
- b->ptr[b->used] = '\0';
-}
-/* }}} */
-/* {{{ proc_open_buffer */
-int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err) {
- proc_handler_t proc;
-
- if (proc_open(&proc, command) != 0) {
- return -1;
- }
-
- if (in) {
- if (write(proc.in.fd, (void *)in->ptr, in->used) < 0) {
- perror("error writing pipe");
- return -1;
- }
- }
- pipe_close(&proc.in);
-
- if (out) {
- proc_read_fd_to_buffer(proc.out.fd, out);
- }
- pipe_close(&proc.out);
-
- if (err) {
- proc_read_fd_to_buffer(proc.err.fd, err);
- }
- pipe_close(&proc.err);
-
- proc_close(&proc);
-
- return 0;
-}
-/* }}} */
-
-/* {{{ test */
-#ifdef DEBUG_PROC_OPEN
-int main() {
- proc_handler_t proc;
- buffer *in = buffer_init(), *out = buffer_init(), *err = buffer_init();
- int wstatus;
-
-#define FREE() do { \
- buffer_free(in); \
- buffer_free(out); \
- buffer_free(err); \
-} while (0)
-
-#define RESET() do { \
- buffer_reset(in); \
- buffer_reset(out); \
- buffer_reset(err); \
- wstatus = proc_close(&proc); \
- if (0&&wstatus != 0) { \
- fprintf(stdout, "exitstatus %d\n", wstatus); \
- return __LINE__ - 200; \
- } \
-} while (0)
-
-#define ERROR_OUT() do { \
- fprintf(stdout, "failed opening proc\n"); \
- wstatus = proc_close(&proc); \
- fprintf(stdout, "exitstatus %d\n", wstatus); \
- FREE(); \
- return __LINE__ - 300; \
-} while (0)
-
-#ifdef _WIN32
-#define CMD_CAT "pause"
-#else
-#define CMD_CAT "cat"
-#endif
-
- do {
- fprintf(stdout, "test: echo 123 without read\n");
- if (proc_open(&proc, "echo 321") != 0) {
- ERROR_OUT();
- }
- close_descriptor(proc.in.parent);
- close_descriptor(proc.out.parent);
- close_descriptor(proc.err.parent);
- RESET();
-
- fprintf(stdout, "test: echo 321 with read\n"); fflush(stdout);
- if (proc_open_buffer("echo 321", NULL, out, err) != 0) {
- ERROR_OUT();
- }
- fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
- RESET();
-
- fprintf(stdout, "test: echo 123 | " CMD_CAT "\n"); fflush(stdout);
- buffer_copy_string_len(in, CONST_STR_LEN("123\n"));
- if (proc_open_buffer(CMD_CAT, in, out, err) != 0) {
- ERROR_OUT();
- }
- fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
- RESET();
- } while (0);
-
-#undef RESET
-#undef ERROR_OUT
-
- fprintf(stdout, "ok\n");
-
- FREE();
- return 0;
-}
-#endif /* DEBUG_PROC_OPEN */
-/* }}} */
-
diff --git a/src/proc_open.h b/src/proc_open.h
deleted file mode 100644
index 57a54b51..00000000
--- a/src/proc_open.h
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#include "buffer.h"
-
-#ifdef _WIN32
-#include <windows.h>
-typedef HANDLE descriptor_t;
-typedef HANDLE proc_pid_t;
-#else
-typedef int descriptor_t;
-typedef pid_t proc_pid_t;
-#endif
-
-typedef struct {
- descriptor_t parent, child;
- int fd;
-} pipe_t;
-
-typedef struct {
- pipe_t in, out, err;
- proc_pid_t child;
-} proc_handler_t;
-
-LI_EXPORT int proc_close(proc_handler_t *ht);
-LI_EXPORT int proc_open(proc_handler_t *ht, const char *command);
-LI_EXPORT int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err);
diff --git a/src/request.c b/src/request.c
deleted file mode 100644
index 816b5368..00000000
--- a/src/request.c
+++ /dev/null
@@ -1,599 +0,0 @@
-#include <sys/stat.h>
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "request.h"
-#include "keyvalue.h"
-#include "log.h"
-#include "http_req.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;
- 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
- */
-
- /* no Host: */
- if (buffer_is_empty(host)) return 0;
- if (host->used < 1) return 0;
-
- host_len = host->used - 1;
-
- /* IPv6 adress */
- if (host->ptr[0] == '[') {
- char *c = host->ptr + 1;
- int colon_cnt = 0;
-
- /* check portnumber */
- for (; *c && *c != ']'; c++) {
- if (*c == ':') {
- if (++colon_cnt > 7) {
- return -1;
- }
- } else if (!light_isxdigit(*c)) {
- return -1;
- }
- }
-
- /* missing ] */
- if (!*c) {
- return -1;
- }
-
- /* check port */
- if (*(c+1) == ':') {
- for (c += 2; *c; c++) {
- if (!light_isdigit(*c)) {
- return -1;
- }
- }
- }
- return 0;
- }
-
- if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
- char *c = colon + 1;
-
- /* check portnumber */
- for (; *c; c++) {
- if (!light_isdigit(*c)) return -1;
- }
-
- /* remove the port from the host-len */
- host_len = colon - host->ptr;
- }
-
- /* Host is empty */
- if (host_len == 0) return -1;
-
- /* if the hostname ends in a "." strip it */
- if (host->ptr[host_len-1] == '.') {
- /* shift port info one left */
- if (NULL != colon) memmove(colon-1, colon, host->used - host_len);
- else host->ptr[host_len-1] = '\0';
- host_len -= 1;
- host->used -= 1;
- }
-
- if (host_len == 0) return -1;
-
- /* scan from the right and skip the \0 */
- for (i = host_len; 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;
-}
-
-#if 0
-#define DUMP_HEADER
-#endif
-
-static int http_request_split_value(array *vals, buffer *b) {
- char *s;
- size_t i;
- int state = 0;
- /*
- * parse
- *
- * val1, val2, val3, val4
- *
- * into a array (more or less a explode() incl. striping of whitespaces
- */
-
- if (b->used == 0) return 0;
-
- s = b->ptr;
-
- for (i =0; i < b->used - 1; ) {
- char *start = NULL, *end = NULL;
- data_string *ds;
-
- switch (state) {
- case 0: /* ws */
-
- /* skip ws */
- for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
-
-
- state = 1;
- break;
- case 1: /* value */
- start = s;
-
- for (; *s != ',' && i < b->used - 1; i++, s++);
- end = s - 1;
-
- for (; (*end == ' ' || *end == '\t') && end > start; end--);
-
- if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
- ds = data_string_init();
- }
-
- buffer_copy_string_len(ds->value, start, end-start+1);
- array_insert_unique(vals, (data_unset *)ds);
-
- if (*s == ',') {
- state = 0;
- i++;
- s++;
- } else {
- /* end of string */
-
- state = 2;
- }
- break;
- default:
- i++;
- break;
- }
- }
- return 0;
-}
-
-int http_request_parse(server *srv, connection *con, http_req *req) {
- size_t i;
- enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_CLOSE, HTTP_CONNECTION_KEEPALIVE } keep_alive_set = HTTP_CONNECTION_UNSET;
-
- if (req->protocol == HTTP_VERSION_UNSET) {
- con->http_status = 505; /* Version not Supported */
- return 0;
- }
-
- if (req->method == HTTP_METHOD_UNSET) {
- con->http_status = 405; /* Method not allowed */
- return 0;
- }
-
- if (buffer_is_empty(req->uri_raw)) {
- con->http_status = 400;
- return 0;
- }
-
- /* strip absolute URLs
- * */
-
- buffer_copy_string_buffer(con->request.orig_uri, req->uri_raw);
- if (req->uri_raw->ptr[0] == '/') {
- buffer_copy_string_buffer(con->request.uri, req->uri_raw);
- } else if (req->uri_raw->ptr[0] == '*') {
- if (req->method != HTTP_METHOD_OPTIONS) {
- con->http_status = 400;
- return 0;
- }
- buffer_copy_string_buffer(con->request.uri, req->uri_raw);
- } else {
- /* GET http://www.example.org/foobar */
- char *sl;
- int l;
-
- if (0 == strncmp(BUF_STR(req->uri_raw), "https://", 8)) {
- l = 8;
- } else if (0 == strncmp(BUF_STR(req->uri_raw), "http://", 7)) {
- l = 7;
- } else {
- con->http_status = 400;
- return 0;
- }
-
- if (NULL == (sl = strchr(BUF_STR(req->uri_raw) + l, '/'))) {
- con->http_status = 400;
- return 0;
- }
-
- buffer_copy_string(con->request.uri, sl);
- buffer_copy_string_len(con->request.http_host, BUF_STR(req->uri_raw) + l, sl - BUF_STR(req->uri_raw) - l);
-
- if (request_check_hostname(con->request.http_host)) {
- if (srv->srvconf.log_request_header_on_error) {
- TRACE("Host header is invalid (Status: 400), was %s", SAFE_BUF_STR(con->request.http_host));
- }
- con->http_status = 400;
- con->keep_alive = 0;
-
- buffer_reset(con->request.http_host);
-
- return 0;
- }
- }
-
- con->request.http_method = req->method;
- con->request.http_version = req->protocol;
-
- for (i = 0; i < req->headers->used; i++) {
- data_string *ds = (data_string *)req->headers->data[i];
- data_string *hdr;
- int cmp;
-
- /* this list is sorted */
- if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
- array *vals;
- size_t vi;
- /* Connection: Keep-Alive, ... */
-
- vals = srv->split_vals;
-
- array_reset(vals);
- http_request_split_value(vals, ds->value);
-
- for (vi = 0; vi < vals->used; vi++) {
- data_string *dsv = (data_string *)vals->data[vi];
-
- if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
- keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
-
- break;
- } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
- keep_alive_set = HTTP_CONNECTION_CLOSE;
-
- break;
- }
- }
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
- char *err;
- off_t r;
-
- /* ignore the header, if it is a duplicate */
- if (con->request.content_length != -1) continue;
-
- r = str_to_off_t(ds->value->ptr, &err, 10);
-
- if (*err != '\0') {
- TRACE("content-length is not a number: %s (Status: 400)", err);
-
- con->http_status = 400;
-
- return 0;
- }
-
- /**
- * check if we had a over- or underrun in the string conversion
- */
- if (r == STR_OFF_T_MIN ||
- r == STR_OFF_T_MAX) {
- if (errno == ERANGE) {
- con->http_status = 413;
-
- return 0;
- }
- }
-
- /**
- * negative content-length is not supported
- * and is a bad request
- */
- if (r < 0) {
- con->http_status = 400;
-
- return 0;
- }
-
- /* don't handle more the SSIZE_MAX bytes in content-length */
- if (r > SSIZE_MAX) {
- con->http_status = 413;
-
- ERROR("request-size too long: %s (Status: 413)", SAFE_BUF_STR(ds->value));
-
- return 0;
- }
-
- con->request.content_length = r;
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
- /* HTTP 2616 8.2.3
- * Expect: 100-continue
- *
- * -> (10.1.1) 100 (read content, process request, send final status-code)
- * -> (10.4.18) 417 (close)
- *
- *
- */
-
- if (0 != buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
- /* we only support 100-continue */
- con->http_status = 417;
- return 0;
- }
-
- if (con->request.http_version != HTTP_VERSION_1_1) {
- /* only HTTP/1.1 clients can send us this header */
- con->http_status = 417;
- return 0;
- }
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
- if (request_check_hostname(ds->value)) {
- TRACE("Host header is invalid (Status: 400), was %s", SAFE_BUF_STR(ds->value));
- con->http_status = 400;
- con->keep_alive = 0;
-
- return 0;
- }
-
- if (!buffer_is_empty(con->request.http_host) && !buffer_is_equal(con->request.http_host, ds->value)) {
- TRACE("%s", "Host header is duplicate (Status: 400)");
- con->http_status = 400;
-
- return 0;
- }
-
- buffer_copy_string_buffer(con->request.http_host, ds->value);
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
- data_string *old;
-
- if (NULL != (old = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("If-Modified-Since")))) {
- if (0 != buffer_caseless_compare(CONST_BUF_LEN(old->value), CONST_BUF_LEN(ds->value))) {
- /* duplicate header and different timestamps */
- con->http_status = 400;
-
- TRACE("%s", "If-Modified-Since is duplicate (Status: 400)");
-
- return 0;
- }
- }
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
- data_string *old;
- /* if dup, only the first one will survive */
- if (NULL != (old = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("If-None-Match")))) {
- continue;
- }
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
- if (NULL != array_get_element(con->request.headers, CONST_STR_LEN("Range"))) {
- /* duplicate Range header */
-
- TRACE("%s", "Range: header is duplicate (Status: 400)");
-
- con->http_status = 400;
- con->keep_alive = 0;
-
- return 0;
- }
- }
-
- if (NULL == (hdr = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
- hdr = data_string_init();
- }
-
- buffer_copy_string_buffer(hdr->key, ds->key);
- buffer_copy_string_buffer(hdr->value, ds->value);
-
- array_insert_unique(con->request.headers, (data_unset *)hdr);
- }
-
-
- con->header_len = i;
-
- /* do some post-processing */
-
- if (con->request.http_version == HTTP_VERSION_1_1) {
- if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
- /* no Connection-Header sent */
-
- /* HTTP/1.1 -> keep-alive default TRUE */
- con->keep_alive = 1;
- } else {
- con->keep_alive = 0;
- }
-
- /* RFC 2616, 14.23 */
- if (buffer_is_empty(con->request.http_host)) {
- con->http_status = 400;
- con->response.keep_alive = 0;
- con->keep_alive = 0;
-
- 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);
- }
- return 0;
- }
- } else {
- if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
- /* no Connection-Header sent */
-
- /* HTTP/1.0 -> keep-alive default FALSE */
- con->keep_alive = 1;
- } else {
- con->keep_alive = 0;
- }
- }
-
- switch(con->request.http_method) {
- case HTTP_METHOD_GET:
- case HTTP_METHOD_HEAD:
- /* content-length is forbidden for those */
- if (con->request.content_length != -1) {
- /* content-length is missing */
- if (srv->srvconf.log_request_header_on_error) {
- ERROR("GET/HEAD with content-length: %d", 400);
- }
-
- con->keep_alive = 0;
- con->http_status = 400;
- return 0;
- }
- break;
- case HTTP_METHOD_POST:
- /* content-length is required for them */
- if (con->request.content_length == -1) {
- /* content-length is missing */
- if (srv->srvconf.log_request_header_on_error) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "POST-request, but content-length missing -> 411");
- }
-
- con->keep_alive = 0;
- con->http_status = 411;
- return 0;
-
- }
- break;
- default:
- /* the may have a content-length */
- break;
- }
-
-
- /* check if we have read post data */
- if (con->request.content_length != -1) {
- /* divide by 1024 as srvconf.max_request_size is in kBytes */
- if (srv->srvconf.max_request_size != 0 &&
- ((size_t)(con->request.content_length >> 10)) > srv->srvconf.max_request_size) {
- /* the request body itself is larger then
- * our our max_request_size
- */
-
- con->http_status = 413;
- con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "sos",
- "request-size too long:", con->request.content_length, "-> 413");
- return 0;
- }
- }
-
- return 0;
-}
-
-
diff --git a/src/request.h b/src/request.h
deleted file mode 100644
index e5cc87c2..00000000
--- a/src/request.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _REQUEST_H_
-#define _REQUEST_H_
-
-#include "base.h"
-#include "http_req.h"
-
-LI_EXPORT int http_request_parse(server *srv, connection *con, http_req *req);
-
-#endif
diff --git a/src/response.c b/src/response.c
deleted file mode 100644
index 6dfc4e62..00000000
--- a/src/response.c
+++ /dev/null
@@ -1,794 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <limits.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include <stdio.h>
-
-#include "settings.h"
-
-#include "response.h"
-#include "keyvalue.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "chunk.h"
-
-#include "connections.h"
-
-#include "plugin.h"
-
-#include "sys-socket.h"
-#include "sys-files.h"
-#include "sys-strings.h"
-
-int http_response_write_header(server *srv, connection *con, chunkqueue *raw) {
- buffer *b;
- size_t i;
- int have_date = 0;
- int have_server = 0;
- int allow_keep_alive = 0;
-
- b = chunkqueue_get_prepend_buffer(raw);
-
- 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 "));
- }
- buffer_append_long(b, con->http_status);
- buffer_append_string_len(b, CONST_STR_LEN(" "));
- buffer_append_string(b, get_http_status_name(con->http_status));
-
- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
- allow_keep_alive = 1;
- } else if ((con->http_status >= 100 && con->http_status < 200) ||
- con->http_status == 204 ||
- con->http_status == 304) {
- /* 1xx, 204 and 304 never have a content-body ->
- * never have a Content-Length and are always
- * able to do keep-alive
- */
- allow_keep_alive = 1;
- } else if (con->response.content_length >= 0) {
- buffer_copy_off_t(srv->tmp_buf, con->response.content_length);
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
-
- allow_keep_alive = 1;
- }
-
- /* keep-alive needs Content-Length or chunked encoding. */
- if (!allow_keep_alive) con->keep_alive = 0;
-
- /* disable keep-alive if requested */
- if (con->request_count > con->conf.max_keep_alive_requests || 0 == con->conf.max_keep_alive_idle) {
- con->keep_alive = 0;
- } else {
- con->keep_alive_idle = con->conf.max_keep_alive_idle;
- }
-
- if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
- if (con->keep_alive) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
- } else {
- response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
- }
- }
-
-
- /* add all headers */
- for (i = 0; i < con->response.headers->used; i++) {
- data_string *ds;
-
- ds = (data_string *)con->response.headers->data[i];
-
- if (ds->value->used && ds->key->used &&
- 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-")) &&
- 0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
- if (0 == strcasecmp(ds->key->ptr, "Date")) have_date = 1;
- if (0 == strcasecmp(ds->key->ptr, "Server")) have_server = 1;
-
- 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 0
- log_error_write(srv, __FILE__, __LINE__, "bb",
- ds->key, ds->value);
-#endif
- }
- }
-
- if (!have_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_prepare_copy(srv->ts_date_str, 255);
-
- strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
-
- srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
-
- srv->last_generated_date_ts = srv->cur_ts;
- }
-
- buffer_append_string_buffer(b, srv->ts_date_str);
- }
-
- if (!have_server) {
- if (buffer_is_empty(con->conf.server_tag)) {
- buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_NAME "/" PACKAGE_VERSION));
- } else {
- buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: "));
- buffer_append_string_buffer(b, con->conf.server_tag);
- }
- }
-
- buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
-
-
- con->bytes_header = b->used - 1;
- raw->bytes_in += b->used - 1;
-
- if (con->conf.log_response_header) {
- log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
- }
-
- return 0;
-}
-
-#ifdef USE_OPENSSL
-static void https_add_ssl_entries(connection *con) {
- X509 *xs;
- X509_NAME *xn;
- X509_NAME_ENTRY *xe;
- if (
- SSL_get_verify_result(con->sock->ssl) != X509_V_OK
- || !(xs = SSL_get_peer_certificate(con->sock->ssl))
- ) {
- return;
- }
-
- xn = X509_get_subject_name(xs);
- for (int i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
- int xobjnid;
- const char * xobjsn;
- data_string *envds;
-
- if (!(xe = X509_NAME_get_entry(xn, i))) {
- continue;
- }
- xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
- xobjsn = OBJ_nid2sn(xobjnid);
- if (!xobjsn) {
- continue;
- }
-
- if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
- envds = data_string_init();
- }
- buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
- buffer_append_string(envds->key, xobjsn);
- buffer_copy_string_len(
- envds->value,
- (const char *)xe->value->data, xe->value->length
- );
- /* pick one of the exported values as "authed user", for example
- * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID" or "SSL_CLIENT_S_DN_emailAddress"
- */
- if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) {
- buffer_copy_string_buffer(con->authed_user, envds->value);
- }
- array_insert_unique(con->environment, (data_unset *)envds);
- }
- if (con->conf.ssl_verifyclient_export_cert) {
- BIO *bio;
- if (NULL != (bio = BIO_new(BIO_s_mem()))) {
- data_string *envds;
- int n;
-
- PEM_write_bio_X509(bio, xs);
- n = BIO_pending(bio);
-
- if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
- envds = data_string_init();
- }
-
- buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
- buffer_prepare_copy(envds->value, n+1);
- BIO_read(bio, envds->value->ptr, n);
- BIO_free(bio);
- envds->value->ptr[n] = '\0';
- envds->value->used = n+1;
- array_insert_unique(con->environment, (data_unset *)envds);
- }
- }
- X509_free(xs);
-}
-#endif
-
-
-handler_t handle_get_backend(server *srv, connection *con) {
- handler_t r;
-
- /* looks like someone has already made a decision */
- if (con->mode == DIRECT &&
- (con->http_status != 0 && con->http_status != 200)) {
- /* remove a packets in the queue */
-
- return HANDLER_FINISHED;
- }
-
- /* no decision yet, build conf->filename */
- if (con->mode == DIRECT && con->physical.path->used == 0) {
- char *qstr;
-
- /* we only come here when we have to 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->conf.log_condition_handling) {
- TRACE("run condition: %s", "");
- }
- config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
-
- /**
- * prepare strings
- *
- * - uri.path_raw
- * - uri.path (secure)
- * - uri.query
- *
- */
-
- /**
- * Name according to RFC 2396
- *
- * - scheme
- * - authority
- * - path
- * - query
- *
- * (scheme)://(authority)(path)?(query)#fragment
- *
- *
- */
-
- if (con->conf.is_ssl) {
- buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
- } else {
- buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
- }
- buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
- buffer_to_lower(con->uri.authority);
-
- config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */
- config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
- config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */
- config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
- config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent: */
- config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
- config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */
-
- /** their might be a fragment which has to be cut away */
- if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
- con->request.uri->used = qstr - con->request.uri->ptr;
- con->request.uri->ptr[con->request.uri->used++] = '\0';
- }
-
- /** extract query string from request.uri */
- if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
- buffer_copy_string (con->uri.query, qstr + 1);
- buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr);
- } else {
- buffer_reset (con->uri.query);
- buffer_copy_string_buffer(con->uri.path_raw, con->request.uri);
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "splitting Request-URI");
- TRACE("Request-URI : %s", SAFE_BUF_STR(con->request.uri));
- TRACE("URI-scheme : %s", SAFE_BUF_STR(con->uri.scheme));
- TRACE("URI-authority: %s", SAFE_BUF_STR(con->uri.authority));
- TRACE("URI-path : %s", SAFE_BUF_STR(con->uri.path_raw));
- TRACE("URI-query : %s", SAFE_BUF_STR(con->uri.query));
- }
-
- if (srv->sockets_disabled) {
- con->keep_alive = 0;
- }
-
-
- /**
- *
- * 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:
- ERROR("plugins_call_handle_uri_raw() returned unexpected: %d", r);
- break;
- }
-
- /* build filename
- *
- * - decode url-encodings (e.g. %20 -> ' ')
- * - remove path-modifiers (e.g. /../)
- */
-
-
-
- if (con->request.http_method == HTTP_METHOD_OPTIONS &&
- con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
- /* OPTIONS * ... */
- buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
- } else {
- buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
- buffer_urldecode_path(srv->tmp_buf);
- buffer_path_simplify(con->uri.path, srv->tmp_buf);
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "sanitizing URI");
- TRACE("URI-path : %s", SAFE_BUF_STR(con->uri.path));
- }
-
-#ifdef USE_OPENSSL
- if (con->conf.is_ssl && con->conf.ssl_verifyclient) {
- https_add_ssl_entries(con);
- }
-#endif
-
- /**
- *
- * call plugins
- *
- * - based on the clean URL
- *
- */
-
- config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
- config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */
-
- /* do we have to downgrade to 1.0 ? */
- if (!con->conf.allow_http11) {
- con->request.http_version = HTTP_VERSION_1_0;
- }
-
- switch(r = plugins_call_handle_uri_clean(srv, con)) {
- case HANDLER_GO_ON:
- break;
- case HANDLER_FINISHED:
- case HANDLER_COMEBACK:
- case HANDLER_WAIT_FOR_EVENT:
- case HANDLER_ERROR:
- return r;
- default:
- ERROR("plugins_call_handle_uri_clean() returned unexpected: %d", r);
- break;
- }
-
- if (con->request.http_method == HTTP_METHOD_OPTIONS &&
- con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
- /* option requests are handled directly without checking the path */
-
- response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
-
- con->http_status = 200;
- /* no more content to send */
- con->send->is_closed = 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_string_buffer(con->physical.doc_root, con->conf.document_root);
- buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
-
- filename_unix2local(con->physical.rel_path);
-#if defined(_WIN32) || defined(__CYGWIN__)
- /* strip dots and spaces from the end
- *
- * windows/dos handle those filenames as the same file
- *
- * foo == foo. == foo..... == "foo... " == "foo.. ./"
- *
- * This will affect PATHINFO in some cases
- *
- * on native windows we could prepend the filename with \\?\ to circumvent
- * this behaviour. I have no idea how to push this through cygwin
- *
- * */
-
- if (con->physical.rel_path->used > 1) {
- buffer *b = con->physical.rel_path;
- size_t i;
-
- if (b->used > 2 &&
- b->ptr[b->used-2] == '/' &&
- (b->ptr[b->used-3] == ' ' ||
- b->ptr[b->used-3] == '.')) {
- b->ptr[b->used--] = '\0';
- }
-
- for (i = b->used - 2; b->used > 1; i--) {
- if (b->ptr[i] == ' ' ||
- b->ptr[i] == '.') {
- b->ptr[b->used--] = '\0';
- } else {
- break;
- }
- }
- }
-#endif
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "before doc_root");
- TRACE("Doc-Root : %s", SAFE_BUF_STR(con->physical.doc_root));
- TRACE("Rel-Path : %s", SAFE_BUF_STR(con->physical.rel_path));
- TRACE("Path : %s", SAFE_BUF_STR(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:
- ERROR("plugins_call_handle_docroot() returned unexpected: %d", r);
- break;
- }
-
- /* The default Mac OS X and Windows filesystems can't distiguish between
- * upper- and lowercase, so convert to lowercase
- */
- 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_is_empty(con->server_name)) {
- buffer_copy_string_buffer(con->server_name, con->uri.authority);
- }
-
- /**
- * create physical filename
- * -> physical.path = docroot + rel_path
- *
- */
-
- buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
- PATHNAME_APPEND_SLASH(con->physical.path);
- buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
- if (con->physical.rel_path->used &&
- con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
- buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
- } else {
- buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
- }
-
- /* win32: directories can't have a trailing slash */
- if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
- con->physical.path->ptr[con->physical.path->used - 2] = '\0';
- con->physical.path->used--;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "after doc_root");
- TRACE("Doc-Root : %s", SAFE_BUF_STR(con->physical.doc_root));
- TRACE("Rel-Path : %s", SAFE_BUF_STR(con->physical.rel_path));
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
- 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:
- ERROR("plugins_call_handle_physical() returned unexpected: %d", r);
- break;
- }
-
- config_patch_connection(srv, con, COMP_PHYSICAL_PATH); /* physical-path */
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "logical -> physical");
- TRACE("Doc-Root : %s", SAFE_BUF_STR(con->physical.doc_root));
- TRACE("Rel-Path : %s", SAFE_BUF_STR(con->physical.rel_path));
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
- }
-
- /*
- * No one took the file away from the normal path of execution yet (like mod_access)
- *
- * we don't have a backend yet, try to resolve the physical path and go on
- *
- */
-
- if (con->mode == DIRECT) {
- char *slash = NULL;
- char *pathinfo = NULL;
- int found = 0;
- stat_cache_entry *sce = NULL;
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "handling physical path");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
- switch ((r = stat_cache_get_entry_async(srv, con, con->physical.path, &sce))) {
- case HANDLER_GO_ON:
- /* file exists */
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "file found");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
-#ifdef HAVE_LSTAT
- if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "access denied due symlink restriction");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- };
-#endif
-
- if (S_ISDIR(sce->st.st_mode)) {
- if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
- /* redirect to .../ */
-
- http_response_redirect_to_directory(srv, con);
-
- return HANDLER_FINISHED;
- }
-#ifdef HAVE_LSTAT
- } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
-#else
- } else if (!S_ISREG(sce->st.st_mode)) {
-#endif
- /* any special handling of non-reg files ?*/
-
-
- }
- break;
- case HANDLER_WAIT_FOR_EVENT:
- return HANDLER_WAIT_FOR_EVENT;
- case HANDLER_ERROR:
- switch (errno) {
- case EACCES:
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "access denied");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- case ENOENT:
- con->http_status = 404;
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "file not found");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- case ENOTDIR:
- /* PATH_INFO ! :) */
- break;
- case EMFILE:
- return HANDLER_WAIT_FOR_FD;
- default:
- /* we have no idea what happened, so tell the user. */
- con->http_status = 500;
-
- ERROR("checking file '%s' (%s) failed: %d (%s) -> sending status 500",
- SAFE_BUF_STR(con->uri.path),
- SAFE_BUF_STR(con->physical.path),
- errno, strerror(errno));
-
- buffer_reset(con->physical.path);
-
- return HANDLER_FINISHED;
- }
-
- /* not found, perhaps PATHINFO */
-
- buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
-
- do {
- if (slash) {
- buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
- } else {
- buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
- }
-
- if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- found = S_ISREG(sce->st.st_mode);
- break;
- }
-
- if (pathinfo != NULL) {
- *pathinfo = '\0';
- }
- slash = strrchr(srv->tmp_buf->ptr, '/');
-
- if (pathinfo != NULL) {
- /* restore '/' */
- *pathinfo = '/';
- }
-
- if (slash) pathinfo = slash;
- } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));
-
- if (found == 0) {
- /* no, it really doesn't exists */
- con->http_status = 404;
-
- if (con->conf.log_file_not_found) {
- TRACE("file not found: %s -> %s",
- SAFE_BUF_STR(con->uri.path),
- SAFE_BUF_STR(con->physical.path));
- }
-
- buffer_reset(con->physical.path);
-
- return HANDLER_FINISHED;
- }
-
-#ifdef HAVE_LSTAT
- if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
- log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
- }
-
- buffer_reset(con->physical.path);
- return HANDLER_FINISHED;
- };
-#endif
-
- /* we have a PATHINFO */
- if (pathinfo) {
- buffer_copy_string(con->request.pathinfo, pathinfo);
-
- /*
- * shorten uri.path
- */
-
- con->uri.path->used -= strlen(pathinfo);
- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "after pathinfo check");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- TRACE("URI : %s", SAFE_BUF_STR(con->uri.path));
- TRACE("Pathinfo : %s", SAFE_BUF_STR(con->request.pathinfo));
- }
- break;
- default:
- ERROR("stat_cache_get_entry_async() returned unexpected: %d", r);
- break;
- }
-
- config_patch_connection(srv, con, COMP_PHYSICAL_PATH_EXISTS); /* physical-path */
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "handling subrequest");
- TRACE("Path : %s", SAFE_BUF_STR(con->physical.path));
- }
-
- /* call the handlers */
- switch(r = plugins_call_handle_start_backend(srv, con)) {
- case HANDLER_GO_ON:
- break;
- case HANDLER_FINISHED:
- case HANDLER_COMEBACK:
- case HANDLER_WAIT_FOR_EVENT:
- case HANDLER_ERROR:
- return r;
-
- default:
- ERROR("plugins_call_handle_start_backend() returned unexpected: %d", r);
- return r;
- }
-
- if (con->conf.log_request_handling) {
- TRACE("-- %s", "subrequest finished");
- }
- }
-
- if (con->mode == DIRECT) {
- /* if we are still here, no one wanted the file; status 403 is ok I think */
- con->http_status = 403;
-
- if (con->conf.log_request_handling) {
- TRACE("%s", "aaaaaaah, sending 403");
- }
-
- return HANDLER_FINISHED;
- } else {
- return HANDLER_GO_ON;
- }
-}
-
-
-
diff --git a/src/response.h b/src/response.h
deleted file mode 100644
index 0a35debc..00000000
--- a/src/response.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _RESPONSE_H_
-#define _RESPONSE_H_
-
-#include <time.h>
-
-#include "settings.h"
-
-#include "server.h"
-
-LI_API int http_response_parse(server *srv, connection *con);
-LI_API int http_response_write_header(server *srv, connection *con, chunkqueue *cq);
-
-LI_API int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
-LI_API int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
-LI_API int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
-
-LI_API handler_t handle_get_backend(server *srv, connection *con);
-LI_API int http_response_redirect_to_directory(server *srv, connection *con);
-LI_API int http_response_handle_cachable(server *srv, connection *con, buffer * mtime);
-
-LI_API buffer * strftime_cache_get(server *srv, time_t last_mod);
-#endif
diff --git a/src/server.c b/src/server.c
deleted file mode 100644
index be0accc3..00000000
--- a/src/server.c
+++ /dev/null
@@ -1,1792 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#else
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-#endif
-
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <time.h>
-#include <signal.h>
-#include <assert.h>
-#include <locale.h>
-
-#include <stdio.h>
-
-#include "settings.h"
-#include "server.h"
-#include "buffer.h"
-#include "network.h"
-#include "network_backends.h"
-#include "log.h"
-#include "keyvalue.h"
-#include "response.h"
-#include "request.h"
-#include "chunk.h"
-#include "fdevent.h"
-#include "connections.h"
-#include "stat_cache.h"
-#include "plugin.h"
-#include "joblist.h"
-#include "status_counter.h"
-
-/**
- * stack-size of the aio-threads
- *
- * the default is 8Mbyte which is a bit to much. Reducing it to 64k seems to be fine
- * If you experience random segfaults, increase it.
- */
-
-#define LI_THREAD_STACK_SIZE (64 * 1024)
-
-
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#ifdef _WIN32
-#include "xgetopt.h"
-#endif
-#endif
-
-#include "valgrind/valgrind.h"
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#ifdef HAVE_PWD_H
-#include <grp.h>
-#include <pwd.h>
-#endif
-
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
-#ifdef HAVE_SYS_PRCTL_H
-#include <sys/prctl.h>
-#endif
-
-#ifdef USE_OPENSSL
-#include <openssl/err.h>
-#endif
-
-#ifndef __sgi
-/* IRIX doesn't like the alarm based time() optimization */
-/* #define USE_ALARM */
-#endif
-
-#ifdef _WIN32
-#undef HAVE_SIGNAL
-#endif
-
-#include "sys-files.h"
-#include "sys-process.h"
-#include "sys-socket.h"
-
-#ifdef HAVE_GETUID
-# ifndef HAVE_ISSETUGID
-
-static int l_issetugid() {
- return (geteuid() != getuid() || getegid() != getgid());
-}
-
-# define issetugid l_issetugid
-# endif
-#endif
-
-static volatile sig_atomic_t srv_shutdown = 0;
-static volatile sig_atomic_t graceful_shutdown = 0;
-static volatile sig_atomic_t graceful_restart = 0;
-static volatile sig_atomic_t handle_sig_alarm = 1;
-static volatile sig_atomic_t handle_sig_hup = 0;
-static volatile siginfo_t last_sigterm_info;
-static volatile siginfo_t last_sighup_info;
-
-#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
-static void sigaction_handler(int sig, siginfo_t *si, void *context) {
- static siginfo_t empty_siginfo;
- UNUSED(context);
-
- if (!si) si = &empty_siginfo;
-
- switch (sig) {
- case SIGTERM:
- srv_shutdown = 1;
- memcpy((siginfo_t*) &last_sigterm_info, si, sizeof(*si));
- break;
- case SIGINT:
- if (graceful_shutdown) {
- srv_shutdown = 1;
- } else {
- graceful_shutdown = 1;
- }
-
- memcpy((siginfo_t*) &last_sigterm_info, si, sizeof(*si));
-
- break;
- case SIGALRM:
- handle_sig_alarm = 1;
- break;
- case SIGHUP:
- handle_sig_hup = 1;
- memcpy((siginfo_t*) &last_sighup_info, si, sizeof(*si));
- break;
- case SIGCHLD:
- break;
- }
-}
-#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
-static void signal_handler(int sig) {
- switch (sig) {
- case SIGTERM: srv_shutdown = 1; break;
- case SIGINT:
- if (graceful_shutdown) srv_shutdown = 1;
- else graceful_shutdown = 1;
-
- break;
- case SIGALRM: handle_sig_alarm = 1; break;
- case SIGHUP: handle_sig_hup = 1; break;
- case SIGCHLD: break;
- }
-}
-#endif
-
-#ifdef HAVE_FORK
-static void daemonize(void) {
-#ifdef SIGTTOU
- signal(SIGTTOU, SIG_IGN);
-#endif
-#ifdef SIGTTIN
- signal(SIGTTIN, SIG_IGN);
-#endif
-#ifdef SIGTSTP
- signal(SIGTSTP, SIG_IGN);
-#endif
- if (0 != fork()) exit(0);
-
- if (-1 == setsid()) exit(0);
-
- signal(SIGHUP, SIG_IGN);
-
- if (0 != fork()) exit(0);
-
- if (0 != chdir("/")) exit(0);
-}
-#endif
-
-static server *server_init(void) {
- int i;
- FILE *frandom = NULL;
-
- server *srv = calloc(1, sizeof(*srv));
- assert(srv);
-
- srv->max_fds = 1024;
-#define CLEAN(x) \
- srv->x = buffer_init();
-
- CLEAN(response_header);
- CLEAN(parse_full_path);
- CLEAN(ts_debug_str);
- CLEAN(ts_date_str);
- 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(tmp_chunk_len);
-#undef CLEAN
-
-#define CLEAN(x) \
- srv->x = array_init();
-
- CLEAN(config_context);
- CLEAN(config_touched);
-#undef CLEAN
-
- for (i = 0; i < FILE_CACHE_MAX; i++) {
- srv->mtime_cache[i].mtime = (time_t)-1;
- srv->mtime_cache[i].str = buffer_init();
- }
-
- if ((NULL != (frandom = fopen("/dev/urandom", "rb")) || NULL != (frandom = fopen("/dev/random", "rb")))
- && 1 == fread(srv->entropy, sizeof(srv->entropy), 1, frandom)) {
- srand(*(unsigned int*)srv->entropy);
- srv->is_real_entropy = 1;
- } else {
- unsigned int j;
- srand(time(NULL) ^ getpid());
- srv->is_real_entropy = 0;
- for (j = 0; j < sizeof(srv->entropy); j++)
- srv->entropy[j] = rand();
- }
- if (frandom) fclose(frandom);
-
- srv->cur_ts = time(NULL);
- srv->startup_ts = srv->cur_ts;
-
- srv->conns = calloc(1, sizeof(*srv->conns));
- assert(srv->conns);
-
- srv->joblist = calloc(1, sizeof(*srv->joblist));
- assert(srv->joblist);
-
- srv->joblist_prev = calloc(1, sizeof(*srv->joblist));
- assert(srv->joblist_prev);
-
- srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
- assert(srv->fdwaitqueue);
-
- srv->srvconf.modules = array_init();
- srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
- srv->srvconf.network_backend = buffer_init();
- srv->srvconf.upload_tempdirs = array_init();
-
- srv->split_vals = array_init();
-
-#ifdef USE_LINUX_AIO_SENDFILE
- srv->linux_io_ctx = NULL;
- /**
- * we can't call io_setup before the fork() in daemonize()
- */
-#endif
-
- 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);
- }
-
-
-#ifdef USE_LINUX_AIO_SENDFILE
- if (srv->linux_io_ctx) {
- io_destroy(srv->linux_io_ctx);
- }
-#endif
-
-#define CLEAN(x) \
- buffer_free(srv->x);
-
- CLEAN(response_header);
- CLEAN(parse_full_path);
- CLEAN(ts_debug_str);
- CLEAN(ts_date_str);
- 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(tmp_chunk_len);
-#undef CLEAN
-
-#ifdef USE_GTHREAD
- fdevent_unregister(srv->ev, srv->wakeup_iosocket);
- iosocket_free(srv->wakeup_iosocket);
-#endif
-
-#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->ssl_pemfile);
- buffer_free(s->ssl_ca_file);
- buffer_free(s->error_handler);
- buffer_free(s->errorfile_prefix);
- array_free(s->mimetypes);
- buffer_free(s->ssl_cipher_list);
- buffer_free(s->ssl_verifyclient_username);
-#ifdef USE_OPENSSL
- SSL_CTX_free(s->ssl_ctx);
-#endif
-
- free(s);
- }
- free(srv->config_storage);
- srv->config_storage = NULL;
- }
-
-#define CLEAN(x) \
- array_free(srv->x);
-
- CLEAN(config_context);
- CLEAN(config_touched);
- CLEAN(srvconf.upload_tempdirs);
-#undef CLEAN
-
- joblist_free(srv, srv->joblist);
- joblist_free(srv, srv->joblist_prev);
- fdwaitqueue_free(srv, srv->fdwaitqueue);
-
- if (srv->stat_cache) {
- stat_cache_free(srv->stat_cache);
- }
-
- array_free(srv->srvconf.modules);
- array_free(srv->split_vals);
-#ifdef USE_OPENSSL
- if (srv->ssl_is_init) {
- CRYPTO_cleanup_all_ex_data();
- ERR_free_strings();
- ERR_remove_state(0);
- EVP_cleanup();
- }
-#endif
- free(srv);
-}
-
-static void show_version (void) {
-#ifdef USE_OPENSSL
-# define TEXT_SSL " (ssl)"
-#else
-# define TEXT_SSL
-#endif
- char *b = PACKAGE_NAME "-" PACKAGE_VERSION TEXT_SSL \
-" - a light and fast webserver\n" \
-"Build-Date: " __DATE__ " " __TIME__ "\n";
-;
-#undef TEXT_SSL
- if (-1 == write(STDOUT_FILENO, b, strlen(b))) {
- /* what to do if this happens ? */
-
- exit(-1);
- }
-}
-
-static void show_features (void) {
- const fdevent_handler_info_t *handler;
- const network_backend_info_t *backend;
-
- const char *features =
-#ifdef HAVE_IPV6
- "\t+ IPv6 support\n"
-#else
- "\t- IPv6 support\n"
-#endif
-#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
- "\t+ zlib support\n"
-#else
- "\t- zlib support\n"
-#endif
-#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
- "\t+ bzip2 support\n"
-#else
- "\t- bzip2 support\n"
-#endif
-#ifdef HAVE_LIBCRYPT
- "\t+ crypt support\n"
-#else
- "\t- crypt support\n"
-#endif
-#ifdef USE_OPENSSL
- "\t+ SSL Support\n"
-#else
- "\t- SSL Support\n"
-#endif
-#ifdef HAVE_LIBPCRE
- "\t+ PCRE support\n"
-#else
- "\t- PCRE support\n"
-#endif
-#ifdef HAVE_MYSQL
- "\t+ MySQL support\n"
-#else
- "\t- MySQL support\n"
-#endif
-#if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
- "\t+ LDAP support\n"
-#else
- "\t- LDAP support\n"
-#endif
-#ifdef HAVE_MEMCACHE_H
- "\t+ memcached support\n"
-#else
- "\t- memcached support\n"
-#endif
-#ifdef HAVE_FAM_H
- "\t+ FAM support\n"
-#else
- "\t- FAM support\n"
-#endif
-#ifdef HAVE_LUA_H
- "\t+ LUA support\n"
-#else
- "\t- LUA support\n"
-#endif
-#ifdef HAVE_LIBXML_H
- "\t+ xml support\n"
-#else
- "\t- xml support\n"
-#endif
-#ifdef HAVE_SQLITE3_H
- "\t+ SQLite support\n"
-#else
- "\t- SQLite support\n"
-#endif
-#ifdef HAVE_GDBM_H
- "\t+ GDBM support\n"
-#else
- "\t- GDBM support\n"
-#endif
- ;
-
- show_version();
-
- printf("\nEvent Handlers:\n\n");
- for (handler = fdevent_get_handlers(); handler->name; handler++) {
- printf("\t%c %s", handler->init ? '+' : '-', handler->name);
- if (handler->description) {
- printf(": %s\n", handler->description);
- }
- else {
- printf("\n");
- }
- }
-
- printf("\nNetwork Backends:\n\n");
- for (backend = network_get_backends(); backend->name; backend++) {
- printf("\t%c %s", backend->write_handler ? '+' : '-', backend->name);
- if (backend->description) {
- printf(": %s\n", backend->description);
- }
- else {
- printf("\n");
- }
- }
-
-#ifdef USE_MMAP
- printf("\t+ (mmap) support\n");
-#else
- printf("\t- (mmap) support\n");
-#endif
- printf("\nFeatures:\n\n%s", features);
-}
-
-static void show_help (void) {
-#ifdef USE_OPENSSL
-# define TEXT_SSL " (ssl)"
-#else
-# define TEXT_SSL
-#endif
- char *b = PACKAGE_NAME "-" PACKAGE_VERSION TEXT_SSL " ("__DATE__ " " __TIME__ ")" \
-" - a light and fast webserver\n" \
-"usage:\n" \
-" -f <name> filename of the config-file\n" \
-" -m <name> module directory (default: "LIBRARY_DIR")\n" \
-" -p print the parsed config-file in internal form, and exit\n" \
-" -t test the config-file, and exit\n" \
-" -D don't go to background (default: go to background)\n" \
-" -I go to background on SIGINT (useful with -D)\n" \
-" has no effect when using kqueue or /dev/poll\n" \
-" -v show version\n" \
-" -V show compile-time features\n" \
-" -h show this help\n" \
-"\n"
-;
-#undef TEXT_SSL
-#undef TEXT_IPV6
- if (-1 == write(STDOUT_FILENO, b, strlen(b))) {
- exit(-1);
- }
-}
-
-/**
- * call this function whenever you get a EMFILE or ENFILE as return-value
- *
- * after each socket(), accept(), connect() or open() call
- *
- */
-int server_out_of_fds(server *srv, connection *con) {
- /* we get NULL of accept() ran out of FDs */
-
- if (con) {
- fdwaitqueue_append(srv, con);
- }
-
- return 0;
-}
-
-static int lighty_mainloop(server *srv) {
- fdevent_revents *revents = fdevent_revents_init();
- int poll_errno;
- size_t conns_user_at_sockets_disabled = 0;
-
- /* the getevents and the poll() have to run in parallel
- * as soon as one has data, it has to interrupt the otherone */
-
- /* 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;
-
-#if 0
- pid_t pid;
-
- /* send the old process into a graceful-shutdown and start a
- * new process right away
- *
- * BUGS:
- * - if webserver is running on port < 1024 (e.g. 80, 433)
- * we don't have the permissions to bind to that port anymore
- *
- *
- * */
- if (0 == (pid = fork())) {
- execve(argv[0], argv, envp);
-
- exit(-1);
- } else if (pid == -1) {
-
- } else {
- /* parent */
-
- graceful_shutdown = 1; /* shutdown without killing running connections */
- graceful_restart = 1; /* don't delete pid file */
- }
-#else
- /* 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()) {
- log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
-
- return -1;
- } else {
- TRACE("logfiles cycled by UID=%d, PID=%d",
- last_sighup_info.si_uid,
- last_sighup_info.si_pid);
- }
-#endif
- }
-
- if (handle_sig_alarm) {
- /* a new second */
-
-#ifdef USE_ALARM
- /* reset notification */
- handle_sig_alarm = 0;
-#endif
-
- /* get current time */
- min_ts = time(NULL);
-
- if (min_ts != srv->cur_ts) {
- int cs = 0;
- connections *conns = srv->conns;
- handler_t r;
-
- switch(r = plugins_call_handle_trigger(srv)) {
- case HANDLER_GO_ON:
- break;
- 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;
- }
-
- /* trigger waitpid */
- srv->cur_ts = min_ts;
-
- /* cleanup stat-cache */
- stat_cache_trigger_cleanup(srv);
- /**
- * check all connections for timeouts
- *
- */
- for (ndx = 0; ndx < conns->used; ndx++) {
- int changed = 0;
- connection *con;
- int t_diff;
-
- con = conns->ptr[ndx];
-
- switch (con->state) {
- case CON_STATE_READ_REQUEST_HEADER:
- case CON_STATE_READ_REQUEST_CONTENT:
- if (con->recv->is_closed) {
- if (srv->cur_ts - con->read_idle_ts > con->conf.max_connection_idle) {
- /* time - out */
-#if 0
- TRACE("(connection process timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
-#endif
- connection_set_state(srv, con, CON_STATE_ERROR);
- changed = 1;
- }
- }
-
- if (con->request_count == 1) {
- if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
- /* time - out */
-#if 0
- TRACE("(initial read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
-#endif
- 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 0
- TRACE("(keep-alive read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
-#endif
- connection_set_state(srv, con, CON_STATE_ERROR);
- changed = 1;
- }
- }
- break;
- case CON_STATE_WRITE_RESPONSE_HEADER:
- case CON_STATE_WRITE_RESPONSE_CONTENT:
-
-
- if (con->write_request_ts != 0 &&
- 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__, "sbsosds",
- "NOTE: a request 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;
- }
- break;
- default:
- /* the other ones are uninteresting */
- break;
- }
- /* 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;
- }
-
- if (changed) {
- connection_state_machine(srv, con);
- }
- con->bytes_written_cur_second = 0;
- *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
-
-#if 0
- if (cs == 0) {
- fprintf(stderr, "connection-state: ");
- cs = 1;
- }
-
- fprintf(stderr, "c[%d,%d]: %s ",
- con->fd,
- con->fcgi.fd,
- connection_get_state(con->state));
-#endif
- }
-
- if (cs == 1) fprintf(stderr, "\n");
- }
- }
-
- if (srv->sockets_disabled) {
- /* our server sockets are disabled, why ? */
-
- if ((srv->fdwaitqueue->used == 0) &&
- (srv->conns->used <= srv->max_conns * 9 / 10) &&
- (0 == graceful_shutdown)) {
- size_t i;
-
- for (i = 0; i < srv->srv_sockets.used; i++) {
- server_socket *srv_socket = srv->srv_sockets.ptr[i];
- fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
- }
-
- TRACE("[note] sockets enabled again%s", "");
-
- srv->sockets_disabled = 0;
- }
- } else {
- if ((srv->fdwaitqueue->used) || /* looks like some cons are waiting for FDs*/
- (srv->conns->used >= srv->max_conns) || /* out of connections */
- (graceful_shutdown)) { /* graceful_shutdown */
- size_t i;
-
- /* disable server-fds */
-
- for (i = 0; i < srv->srv_sockets.used; i++) {
- server_socket *srv_socket = srv->srv_sockets.ptr[i];
-
- fdevent_event_del(srv->ev, srv_socket->sock);
-
- if (graceful_shutdown) {
- /* we don't want this socket anymore,
- *
- * closing it right away will make it possible for
- * the next lighttpd to take over (graceful restart)
- * */
-
- fdevent_unregister(srv->ev, srv_socket->sock);
- closesocket(srv_socket->sock->fd);
- srv_socket->sock->fd = -1;
-
-#ifdef HAVE_FORK
- /* FreeBSD kqueue could possibly work with rfork(RFFDG)
- * while Solaris /dev/poll would require re-registering
- * all fd */
- if (srv->srvconf.daemonize_on_shutdown &&
- srv->event_handler != FDEVENT_HANDLER_FREEBSD_KQUEUE &&
- srv->event_handler != FDEVENT_HANDLER_SOLARIS_DEVPOLL) {
- daemonize();
- }
-#endif
-
- /* network_close() will cleanup after us */
- }
- }
-
- if (graceful_shutdown) {
- TRACE("[note] graceful shutdown started by UID=%d, PID=%d", last_sigterm_info.si_uid, last_sigterm_info.si_pid);
- } else if (srv->fdwaitqueue->used) {
- TRACE("[note] out of FDs, server-socket get disabled for a while, we have %zu connections open and they are waiting for %zu FDs",
- srv->conns->used, srv->fdwaitqueue->used);
- } else if (srv->conns->used >= srv->max_conns) {
- TRACE("[note] we reached our connection limit of %zu connections. Disabling server-sockets for a while", srv->max_conns);
- }
-
- srv->sockets_disabled = 1;
-
- /* we count the number of free fds indirectly.
- *
- * instead of checking the fds we only check the connection handles we free'd since
- * the server-sockets got disabled
- * */
- conns_user_at_sockets_disabled = srv->conns->used;
- }
- }
-
- 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;
- continue;
- }
-
- /* we still have some fds to share */
- if (!srv_shutdown && srv->fdwaitqueue->used) {
- /* ok, we are back to the problem of 'how many fds do we have available ?' */
- connection *con;
- int fd;
- int avail_fds = conns_user_at_sockets_disabled - srv->conns->used;
-
- if (-1 == (fd = open("/dev/null", O_RDONLY))) {
- switch (errno) {
- case EMFILE:
- avail_fds = 0;
-
- break;
- default:
- break;
- }
- } else {
- close(fd);
-
- /* we have at least one FD as we just checked */
- if (!avail_fds) avail_fds++;
- }
-
-
- TRACE("conns used: %zu, fd-waitqueue has %zu entries, fds to share: %d", srv->conns->used, srv->fdwaitqueue->used, avail_fds);
-
- while (avail_fds-- && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue))) {
- connection_state_machine(srv, con);
- }
- }
- n = fdevent_poll(srv->ev, 1000);
- poll_errno = errno;
-#ifdef USE_GTHREAD
- g_atomic_int_set(&srv->did_wakeup, 0);
-#endif
-
- if (n > 0) {
- /* n is the number of events */
- size_t i;
- fdevent_get_revents(srv->ev, n, revents);
-
- /* handle client connections first
- *
- * this is a bit of a hack, but we have to make sure than we handle
- * close-events before the connection is reused for a keep-alive
- * request
- *
- * this is mostly an issue for mod_proxy_core, but you never know
- *
- */
-
- for (i = 0; i < revents->used; i++) {
- fdevent_revent *revent = revents->ptr[i];
- handler_t r;
-
- /* skip server-fds */
- if (revent->handler == network_server_handle_fdevent) continue;
-
- switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
- case HANDLER_WAIT_FOR_FD:
- server_out_of_fds(srv, NULL);
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- case HANDLER_WAIT_FOR_EVENT:
- break;
- case HANDLER_ERROR:
- /* should never happen */
- SEGFAULT("got HANDLER_ERROR from a plugin: %s", "dieing");
- break;
- default:
- ERROR("got handler_t(%d) from a plugin: ignored", r);
- break;
- }
- }
-
- for (i = 0; i < revents->used; i++) {
- fdevent_revent *revent = revents->ptr[i];
- handler_t r;
-
- /* server fds only */
- if (revent->handler != network_server_handle_fdevent) continue;
-
- switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
- case HANDLER_WAIT_FOR_FD:
- server_out_of_fds(srv, NULL);
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- case HANDLER_WAIT_FOR_EVENT:
- break;
- case HANDLER_ERROR:
- /* should never happen */
- SEGFAULT("got HANDLER_ERROR from a plugin: %s", "dieing");
- break;
- default:
- ERROR("got handler_t(%d) from a plugin: ignored", r);
- break;
- }
- }
-
- } else if (n < 0 && poll_errno != EINTR) {
- ERROR("fdevent_poll failed: %s", strerror(poll_errno));
- }
-
- /*
- * Note: Two joblist's are needed so a connection can be added back into the joblist
- * without getting stuck inside the for loop.
- */
-#ifdef USE_GTHREAD
- {
- connection *con;
- while (NULL != (con = g_async_queue_try_pop(srv->joblist_queue))) {
- joblist_append(srv, con);
- }
- }
-#endif
- if(srv->joblist->used > 0) {
- connections *joblist = srv->joblist;
- /* switch joblist queues. */
- srv->joblist = srv->joblist_prev;
- srv->joblist_prev = joblist;
- }
- for (ndx = 0; ndx < srv->joblist_prev->used; ndx++) {
- connection *con = srv->joblist_prev->ptr[ndx];
- handler_t r;
-
- con->in_joblist = 0;
- connection_state_machine(srv, con);
-
- switch(r = plugins_call_handle_joblist(srv, con)) {
- case HANDLER_FINISHED:
- case HANDLER_GO_ON:
- break;
- default:
- ERROR("got handler_t(%d) from a plugin: ignored", r);
- break;
- }
- }
-
- srv->joblist_prev->used = 0;
- }
-
- fdevent_revents_free(revents);
-
- return 0;
-}
-
-#ifdef USE_GTHREAD
-static handler_t wakeup_handle_fdevent(void *s, void *context, int revent) {
- server *srv = (server *)s;
- connection *con = context;
- char buf[16];
- UNUSED(con);
- UNUSED(revent);
-
- (void) read(srv->wakeup_iosocket->fd, buf, sizeof(buf));
- return HANDLER_GO_ON;
-}
-#endif
-
-int main (int argc, char **argv, char **envp) {
- server *srv = NULL;
- int print_config = 0;
- int test_config = 0;
- int i_am_root;
- int o;
- int num_childs = 0;
- int pid_fd = -1, fd;
- size_t i;
-#ifdef USE_GTHREAD
- GThread **stat_cache_threads;
- GThread **aio_write_threads = NULL;
-#ifdef USE_LINUX_AIO_SENDFILE
- GThread *linux_aio_read_thread_id = NULL;
-#endif
- GError *gerr = NULL;
-#endif
-
-#ifdef HAVE_SIGACTION
- struct sigaction act;
-#endif
-#ifdef HAVE_GETRLIMIT
- struct rlimit rlim;
-#endif
-
-#ifdef USE_ALARM
- struct itimerval interval;
-
- interval.it_interval.tv_sec = 1;
- interval.it_interval.tv_usec = 0;
- interval.it_value.tv_sec = 1;
- interval.it_value.tv_usec = 0;
-#endif
-
- UNUSED(envp);
-
- log_init();
- status_counter_init();
-
- /* for nice %b handling in strfime() */
- setlocale(LC_TIME, "C");
-
- if (NULL == (srv = server_init())) {
- fprintf(stderr, "did this really happen?\n");
- return -1;
- }
-
- /* init structs done */
-
- srv->srvconf.port = 0;
-#ifdef HAVE_GETUID
- i_am_root = (getuid() == 0);
-#else
- i_am_root = 0;
-#endif
- srv->srvconf.dont_daemonize = 0;
- srv->srvconf.daemonize_on_shutdown = 0;
- srv->srvconf.max_stat_threads = 4;
- srv->srvconf.max_read_threads = 8;
-
- while(-1 != (o = getopt(argc, argv, "f:m:hvVDIpt"))) {
- switch(o) {
- case 'f':
- if (config_read(srv, optarg)) {
- server_free(srv);
- return -1;
- }
- break;
- case 'm':
- buffer_copy_string(srv->srvconf.modules_dir, optarg);
- break;
- case 'p': print_config = 1; break;
- case 't': test_config = 1; break;
- case 'D': srv->srvconf.dont_daemonize = 1; break;
- case 'I': srv->srvconf.daemonize_on_shutdown = 1; break;
- case 'v': show_version(); return 0;
- case 'V': show_features(); return 0;
- case 'h': show_help(); return 0;
- default:
- show_help();
- server_free(srv);
- return -1;
- }
- }
-
- if (!srv->config_storage) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "No configuration available. Try using -f option.");
-
- server_free(srv);
- return -1;
- }
-
- if (print_config) {
- data_unset *dc = srv->config_context->data[0];
- if (dc) {
- dc->print(dc, 0);
- fprintf(stdout, "\n");
- } else {
- /* shouldn't happend */
- fprintf(stdout, "global config not found\n");
- }
- }
-
- if (test_config) {
- printf("Syntax OK\n");
- }
-
- if (test_config || print_config) {
- server_free(srv);
- return 0;
- }
-
- /* close stdin and stdout, as they are not needed */
- /* move stdin to /dev/null */
- if (-1 != (fd = open("/dev/null", O_RDONLY))) {
- close(STDIN_FILENO);
- dup2(fd, STDIN_FILENO);
- close(fd);
- }
-
- /* move stdout to /dev/null */
- if (-1 != (fd = open("/dev/null", O_WRONLY))) {
- close(STDOUT_FILENO);
- dup2(fd, STDOUT_FILENO);
- close(fd);
- }
-
- if (0 != config_set_defaults(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "setting default values failed");
- server_free(srv);
- return -1;
- }
-
- /* UID handling */
-#ifdef HAVE_GETUID
- if (!i_am_root && issetugid()) {
- /* we are setuid-root */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "Are you nuts ? Don't apply a SUID bit to this binary");
-
- server_free(srv);
- return -1;
- }
-#endif
-
- /* check document-root */
- if (srv->config_storage[0]->document_root->used <= 1) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "document-root is not set\n");
-
- server_free(srv);
-
- return -1;
- }
-
- if (plugins_load(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "loading plugins finally failed");
-
- plugins_free(srv);
- server_free(srv);
-
- return -1;
- }
-
-#ifndef _WIN32
- /* open pid file BEFORE chroot */
- if (srv->srvconf.pid_file->used) {
- if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
- 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 = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
- return -1;
- }
- }
- }
-#endif
- 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
- * */
- fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
- srv->max_fds = FD_SETSIZE - 4;
- } else {
- srv->max_fds = 4096;
- }
-
- if (i_am_root) {
- struct group *grp = NULL;
- struct passwd *pwd = NULL;
- int use_rlimit = 1;
-
- /* valgrind only supports 1024 fds */
- if (RUNNING_ON_VALGRIND) use_rlimit = 0;
-
-#ifdef HAVE_GETRLIMIT
- if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
- log_error_write(srv, __FILE__, __LINE__,
- "ss", "couldn't get 'max filedescriptors'",
- strerror(errno));
- return -1;
- }
-
- if (use_rlimit && srv->srvconf.max_fds) {
- /* set rlimits */
-
- rlim.rlim_cur = srv->srvconf.max_fds;
- rlim.rlim_max = srv->srvconf.max_fds;
-
- if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
- log_error_write(srv, __FILE__, __LINE__,
- "ss", "couldn't set 'max filedescriptors'",
- strerror(errno));
- return -1;
- }
- }
-
- if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
- srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
- } else {
- srv->max_fds = rlim.rlim_cur;
- }
-
- /* 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
- if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
- /* don't raise the limit above FD_SET_SIZE */
- if (srv->max_fds > ((int)FD_SETSIZE) - 200) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "can't raise max filedescriptors above", FD_SETSIZE - 200,
- "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
- return -1;
- }
- }
-
-
-#ifdef HAVE_PWD_H
- /* set user and group */
- if (srv->srvconf.username->used) {
- if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "can't find username", srv->srvconf.username);
- return -1;
- }
-
- if (pwd->pw_uid == 0) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "I will not set uid to 0\n");
- return -1;
- }
- }
-
- if (srv->srvconf.groupname->used) {
- if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "can't find groupname", srv->srvconf.groupname);
- return -1;
- }
- if (grp->gr_gid == 0) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "I will not set gid to 0\n");
- return -1;
- }
- }
-#endif
- /* we need root-perms for port < 1024 */
- if (0 != network_init(srv)) {
- plugins_free(srv);
- server_free(srv);
-
- return -1;
- }
-
-#ifdef HAVE_PWD_H
- /**
- * initgroups() has to be called before chroot()
- */
- if (srv->srvconf.groupname->used) {
- setgid(grp->gr_gid);
- setgroups(0, NULL);
- if (srv->srvconf.username->used) {
- initgroups(srv->srvconf.username->ptr, grp->gr_gid);
- }
- }
-#endif
-#ifdef HAVE_CHROOT
- if (srv->srvconf.changeroot->used) {
- tzset();
-
- 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 (srv->srvconf.username->used) setuid(pwd->pw_uid);
-#endif
-#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
- /**
- * IRIX 6.5.x has prctl() but no PR_SET_DUMPABLE
- */
- if (srv->srvconf.enable_cores) {
- prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
- }
-#endif
- } else {
-
-#ifdef HAVE_GETRLIMIT
- if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
- log_error_write(srv, __FILE__, __LINE__,
- "ss", "couldn't get 'max filedescriptors'",
- strerror(errno));
- return -1;
- }
-
- if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
- srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
- } else {
- srv->max_fds = rlim.rlim_cur;
- }
-
- /* set core file rlimit, if enable_cores is set */
- if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
- rlim.rlim_cur = rlim.rlim_max;
- setrlimit(RLIMIT_CORE, &rlim);
- }
-
-#endif
- if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
- /* don't raise the limit above FD_SET_SIZE */
- if (srv->max_fds > ((int)FD_SETSIZE) - 4) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "can't raise max filedescriptors above", FD_SETSIZE - 4,
- "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
- return -1;
- }
- }
-
- if (0 != network_init(srv)) {
- plugins_free(srv);
- server_free(srv);
-
- return -1;
- }
- }
-
- /* set max-conns */
- if (srv->srvconf.max_conns > srv->max_fds/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;
- }
-
- if (HANDLER_GO_ON != plugins_call_init(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
-
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
-
- return -1;
- }
-
-#ifdef HAVE_FORK
- /* network is up, let's deamonize ourself */
- if (srv->srvconf.dont_daemonize == 0) daemonize();
-#endif
-
-#ifdef HAVE_PWD_H
- srv->gid = getgid();
- srv->uid = getuid();
-#endif
-
- /* write pid file */
- if (pid_fd != -1) {
- buffer_copy_long(srv->tmp_buf, getpid());
- buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
- if (-1 == write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1)) {
- ERROR("writing to PID to '%s' failed: %s, ignored", "...", strerror(errno));
- }
- close(pid_fd);
- pid_fd = -1;
- }
-
- if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
-
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
-
- return -1;
- }
-
- /* dump unused config-keys */
- for (i = 0; i < srv->config_context->used; i++) {
- array *config = ((data_config *)srv->config_context->data[i])->value;
- 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(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) {
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
-
- return -1;
- }
-
- if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.breakagelog_file, srv->srvconf.errorlog_use_syslog, srv->srvconf.dont_daemonize)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "opening errorlog failed, dying");
-
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
- return -1;
- }
-
-#ifdef HAVE_SIGACTION
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &act, NULL);
-# if defined(SA_SIGINFO)
- 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(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);
-#endif
-
-#ifdef USE_ALARM
- signal(SIGALRM, signal_handler);
-
- /* setup periodic timer (1 second) */
- if (setitimer(ITIMER_REAL, &interval, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
- return -1;
- }
-
- getitimer(ITIMER_REAL, &interval);
-#endif
-
-#ifdef HAVE_FORK
- /* start watcher and workers */
- num_childs = srv->srvconf.max_worker;
- if (num_childs > 0) {
- int child = 0;
- while (!child && !srv_shutdown) {
- if (num_childs > 0) {
- switch (fork()) {
- case -1:
- return -1;
- case 0:
- child = 1;
- break;
- default:
- num_childs--;
- break;
- }
- } else {
- int status;
-
- if (-1 != wait(&status)) {
- /* a child terminated, restart it */
- num_childs++;
- } else {
- /* we got interrupted */
-
- switch (errno) {
- case EINTR:
- /**
- * we got asked to rotate the logs
- *
- * as we are just the parent and have no main-loop we have to fix it ourself
- */
- if (handle_sig_hup) {
- handle_sig_hup = 0;
-
- log_error_cycle();
- }
- break;
- default:
- TRACE("(angel) wait() failed with: %s (errno=%d)", strerror(errno), errno);
- break;
- }
- }
- }
- }
-
- if (srv_shutdown) {
- /* kill all childs */
- kill(0, SIGTERM);
- }
-
- /* if we are the parent, leave here */
- if (!child) return 0;
- }
-#endif
-
- if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
- log_error_write(srv, __FILE__, __LINE__,
- "s", "fdevent_init failed");
- return -1;
- }
- /*
- * kqueue() is called here, select resets its internals,
- * all server sockets get their handlers
- *
- * */
- if (0 != network_register_fdevents(srv)) {
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
-
- return -1;
- }
-
-#ifdef USE_GTHREAD
- if (pipe(srv->wakeup_pipe) == -1) {
- log_error_write(srv, __FILE__, __LINE__, "s", "pipe() failed");
- return -1;
- }
- srv->wakeup_iosocket = iosocket_init();
- srv->wakeup_iosocket->type = IOSOCKET_TYPE_PIPE;
- srv->wakeup_iosocket->fd = srv->wakeup_pipe[0];
- srv->did_wakeup = 0;
- fdevent_fcntl_set(srv->ev, srv->wakeup_iosocket);
- /* block on write */
-#ifdef FD_CLOEXEC
- /* close fd on exec (cgi) */
- fcntl(srv->wakeup_pipe[1], F_SETFD, FD_CLOEXEC);
-#endif
- fdevent_register(srv->ev, srv->wakeup_iosocket, wakeup_handle_fdevent, NULL);
- fdevent_event_add(srv->ev, srv->wakeup_iosocket, FDEVENT_IN);
-#endif
-
- /* might fail if user is using fam (not gamin) and famd isn't running */
- if (NULL == (srv->stat_cache = stat_cache_init())) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "stat-cache could not be setup, dieing.");
- return -1;
- }
-
-#ifdef USE_GTHREAD
- g_thread_init(NULL);
-
- srv->stat_queue = g_async_queue_new();
- srv->joblist_queue = g_async_queue_new();
- srv->aio_write_queue = g_async_queue_new();
-#ifdef HAVE_SYS_INOTIFY_H
- if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_INOTIFY) {
- srv->stat_cache->sock->fd = inotify_init();
-
- fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
- fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
- }
-#endif
- stat_cache_threads = calloc(srv->srvconf.max_stat_threads, sizeof(*stat_cache_threads));
-
- for (i = 0; i < srv->srvconf.max_stat_threads; i++) {
- stat_cache_threads[i] = g_thread_create(stat_cache_thread, srv, 1, &gerr);
- if (gerr) {
- ERROR("g_thread_create failed: %s", gerr->message);
-
- return -1;
- }
- }
-
-#ifndef _WIN32
- switch (srv->network_backend) {
- case NETWORK_BACKEND_GTHREAD_AIO:
- aio_write_threads = calloc(srv->srvconf.max_read_threads, sizeof(*aio_write_threads));
- for (i = 0; i < srv->srvconf.max_read_threads; i++) {
- aio_write_threads[i] = g_thread_create_full(network_gthread_aio_read_thread, srv, LI_THREAD_STACK_SIZE, 1, TRUE, G_THREAD_PRIORITY_NORMAL, &gerr);
- if (gerr) {
- ERROR("g_thread_create failed: %s", gerr->message);
-
- return -1;
- }
- }
- break;
-#ifdef USE_GTHREAD_SENDFILE
- case NETWORK_BACKEND_GTHREAD_SENDFILE:
- aio_write_threads = calloc(srv->srvconf.max_read_threads, sizeof(*aio_write_threads));
- for (i = 0; i < srv->srvconf.max_read_threads; i++) {
- aio_write_threads[i] = g_thread_create_full(network_gthread_sendfile_read_thread, srv, LI_THREAD_STACK_SIZE, 1, TRUE, G_THREAD_PRIORITY_NORMAL, &gerr);
- if (gerr) {
- ERROR("g_thread_create failed: %s", gerr->message);
-
- return -1;
- }
- }
- break;
-#endif
-#ifdef USE_GTHREAD_FREEBSD_SENDFILE
- case NETWORK_BACKEND_GTHREAD_FREEBSD_SENDFILE:
- aio_write_threads = calloc(srv->srvconf.max_read_threads, sizeof(*aio_write_threads));
- for (i = 0; i < srv->srvconf.max_read_threads; i++) {
- aio_write_threads[i] = g_thread_create_full(network_gthread_freebsd_sendfile_read_thread, srv, LI_THREAD_STACK_SIZE, 1, TRUE, G_THREAD_PRIORITY_NORMAL, &gerr);
- if (gerr) {
- ERROR("g_thread_create failed: %s", gerr->message);
-
- return -1;
- }
- }
- break;
-#endif
-#ifdef USE_POSIX_AIO
- case NETWORK_BACKEND_POSIX_AIO:
- srv->posix_aio_iocbs = calloc(srv->srvconf.max_read_threads, sizeof(*srv->posix_aio_iocbs));
- break;
-#endif
-#ifdef USE_LINUX_AIO_SENDFILE
- case NETWORK_BACKEND_LINUX_AIO_SENDFILE:
- TRACE("WARNING: You selected the experimental network.backend '%s'", "linux-aio-sendfile");
- srv->linux_io_iocbs = calloc(srv->srvconf.max_read_threads, sizeof(*srv->linux_io_iocbs));
- if (0 != (i = io_setup(srv->srvconf.max_read_threads, &(srv->linux_io_ctx)))) {
- ERROR("io-setup() failed somehow %s", strerror(-i));
-
- return -1;
- }
- linux_aio_read_thread_id = g_thread_create(linux_aio_read_thread, srv, 1, &gerr);
- if (gerr) {
- ERROR("g_thread_create failed: %s", gerr->message);
-
- return -1;
- }
- break;
-#endif
- default:
- break;
- }
-#endif /* ifndef _WIN32 */
-
-#endif /* USE_GTHREAD */
-
- for (i = 0; i < srv->srv_sockets.used; i++) {
- server_socket *srv_socket = srv->srv_sockets.ptr[i];
- if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
- return -1;
- }
- }
-
- lighty_mainloop(srv);
-
- if (0 == graceful_restart &&
- srv->srvconf.pid_file->used &&
- srv->srvconf.changeroot->used == 0) {
- if (0 != unlink(srv->srvconf.pid_file->ptr)) {
- if (errno != EACCES && errno != EPERM) {
- log_error_write(srv, __FILE__, __LINE__, "sbds",
- "unlink failed for:",
- srv->srvconf.pid_file,
- errno,
- strerror(errno));
- }
- }
- }
-
- /* kill the threads */
-
- srv->is_shutdown = 1;
-#ifdef USE_GTHREAD
-#ifdef USE_LINUX_AIO_SENDFILE
- if (srv->network_backend == NETWORK_BACKEND_LINUX_AIO_SENDFILE) {
- g_thread_join(linux_aio_read_thread_id);
- free(srv->linux_io_iocbs);
- }
-#endif
-#ifdef USE_POSIX_AIO
- if (srv->network_backend == NETWORK_BACKEND_POSIX_AIO) {
- free(srv->posix_aio_iocbs);
- }
-#endif
- if (aio_write_threads != NULL) {
- for (i = 0; i < srv->srvconf.max_read_threads; i++) {
- g_thread_join(aio_write_threads[i]);
- }
- free(aio_write_threads);
- }
-
- for (i = 0; i < srv->srvconf.max_stat_threads; i++) {
- g_async_queue_push(srv->stat_queue, (void *) 1);
- }
-
- for (i = 0; i < srv->srvconf.max_stat_threads; i++) {
- g_thread_join(stat_cache_threads[i]);
- }
-
- /* the ref-count should be 0 now */
- g_async_queue_unref(srv->stat_queue);
- g_async_queue_unref(srv->joblist_queue);
- g_async_queue_unref(srv->aio_write_queue);
-#endif
- /* clean-up */
- network_close(srv);
- connections_free(srv);
- plugins_free(srv);
- server_free(srv);
-
- TRACE("server stopped by UID=%d, PID=%d", last_sigterm_info.si_uid, last_sigterm_info.si_pid);
-
- log_free();
- status_counter_free();
-
-#ifdef USE_GTHREAD
- free(stat_cache_threads);
-#endif
-
- chunkpool_free();
-
- return 0;
-}
diff --git a/src/server.h b/src/server.h
deleted file mode 100644
index c6fddf97..00000000
--- a/src/server.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _SERVER_H_
-#define _SERVER_H_
-
-#include "base.h"
-
-typedef enum { CONFIG_UNSET, CONFIG_DOCUMENT_ROOT } config_var_t;
-
-LI_EXPORT int config_read(server *srv, const char *fn);
-LI_EXPORT int config_set_defaults(server *srv);
-LI_EXPORT buffer * config_get_value_buffer(server *srv, connection *con, config_var_t field);
-
-#ifdef USE_GTHREAD
-gpointer stat_cache_thread(gpointer );
-gpointer network_gthread_aio_read_thread(gpointer );
-gpointer network_gthread_sendfile_read_thread(gpointer );
-gpointer network_gthread_freebsd_sendfile_read_thread(gpointer );
-gpointer linux_aio_read_thread(gpointer );
-#endif
-
-#endif
diff --git a/src/settings.h b/src/settings.h
deleted file mode 100644
index 4724e83d..00000000
--- a/src/settings.h
+++ /dev/null
@@ -1,183 +0,0 @@
-#ifndef _LIGHTTPD_SETTINGS_H_
-#define _LIGHTTPD_SETTINGS_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define BV(x) (1 << x)
-
-#define INET_NTOP_CACHE_MAX 4
-#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)
-
-/**
- * max size of the HTTP request header
- *
- * 32k should be enough for everything (just a guess)
- *
- */
-#define MAX_HTTP_REQUEST_HEADER (32 * 1024)
-
-#ifdef HAVE_GLIB_H
-#include <glib.h>
-#endif
-
-/**
- * if glib supports threads we will use it for async file-io
- */
-#ifdef G_THREADS_ENABLED
-# ifndef USE_GTHREAD
-# define USE_GTHREAD
-# endif
-#endif
-
-
-/* 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 HAVE_WRITEV && defined(__linux__) && !defined HAVE_SENDFILE_BROKEN
-# define USE_LINUX_SENDFILE
-# include <sys/sendfile.h>
-# include <sys/uio.h>
-#endif
-
-/* all the Async IO backends need GTHREAD support */
-#if defined(USE_GTHREAD)
-# if defined(USE_LINUX_SENDFILE)
-# if defined(HAVE_LIBAIO_H)
- /** disabled for now as not all FSs are async-io capable */
-# define USE_LINUX_AIO_SENDFILE
-# endif
-# define USE_GTHREAD_SENDFILE
-# endif
-# if defined(HAVE_AIO_H) && (!defined(__FreeBSD__))
-/* FreeBSD has no SIGEV_THREAD for us */
-# define USE_POSIX_AIO
-# include <sys/types.h> /* macosx wants it */
-# include <aio.h>
-# endif
-# ifdef HAVE_MMAP
-# define USE_GTHREAD_AIO
-# endif
-#endif
-
-#if defined HAVE_SYS_UIO_H && defined HAVE_SENDFILE && defined HAVE_WRITEV && (defined(__FreeBSD__) || defined(__DragonFly__))
-# define USE_FREEBSD_SENDFILE
-# include <sys/uio.h>
-#endif
-
-#if defined(USE_FREEBSD_SENDFILE) && defined(USE_GTHREAD)
-# define USE_GTHREAD_FREEBSD_SENDFILE
-#endif
-
-
-#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined HAVE_WRITEV && defined(__sun)
-# define USE_SOLARIS_SENDFILEV
-# include <sys/sendfile.h>
-# include <sys/uio.h>
-#endif
-
-#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV
-# define USE_WRITEV
-# include <sys/uio.h>
-#endif
-
-#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP
-# define USE_MMAP
-# include <sys/mman.h>
-/* NetBSD 1.3.x needs it */
-# ifndef MAP_FAILED
-# define MAP_FAILED -1
-# endif
-
-#if defined(MAP_ANON)
-#define HAVE_MEM_MMAP_ANON
-#else
-/* let's try /dev/zero */
-#define HAVE_MEM_MMAP_ZERO
-#endif
-
-#endif
-
-#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV && defined HAVE_SEND_FILE && defined(__aix)
-# define USE_AIX_SENDFILE
-#endif
-
-
-/**
-* unix can use read/write or recv/send on sockets
-* win32 only recv/send
-*/
-#ifdef _WIN32
-
-# define WIN32_LEAN_AND_MEAN
-# define NOGDI
-# define USE_WIN32_SEND
-/* wait for async-io support
-# define USE_WIN32_TRANSMITFILE
-*/
-#else
-# define USE_WRITE
-#endif
-
-
-typedef enum { HANDLER_UNSET,
- HANDLER_GO_ON,
- HANDLER_FINISHED,
- HANDLER_COMEBACK,
- HANDLER_WAIT_FOR_EVENT,
- HANDLER_ERROR,
- HANDLER_WAIT_FOR_FD
-} handler_t;
-
-/* Shared library support */
-#ifdef _WIN32
- #define LI_IMPORT __declspec(dllimport)
- #define LI_EXPORT __declspec(dllexport)
- #define LI_DLLLOCAL
- #define LI_DLLPUBLIC
-#else
- #define LI_IMPORT
- #ifdef GCC_HASCLASSVISIBILITY
- #define LI_EXPORT __attribute__ ((visibility("default")))
- #define LI_DLLLOCAL __attribute__ ((visibility("hidden")))
- #define LI_DLLPUBLIC __attribute__ ((visibility("default")))
- #else
- #define LI_EXPORT
- #define LI_DLLLOCAL
- #define LI_DLLPUBLIC
- #endif
-#endif
-
-#ifdef LI_DECLARE_EXPORTS
-#define LI_API LI_EXPORT
-#else
-#define LI_API LI_IMPORT
-#endif
-
-/* Throwable classes must always be visible on GCC in all binaries */
-#ifdef _WIN32
- #define LI_EXCEPTIONAPI(api) api
-#elif defined(GCC_HASCLASSVISIBILITY)
- #define LI_EXCEPTIONAPI(api) LI_EXPORT
-#else
- #define LI_EXCEPTIONAPI(api)
-#endif
-
-#ifdef UNUSED_PARAM
-#elif defined(__GNUC__)
-# define UNUSED_PARAM(x) UNUSED_ ## x __attribute__((unused))
-#elif defined(__LCLINT__)
-# define UNUSED_PARAM(x) /*@unused@*/ x
-#else
-# define UNUSED_PARAM(x) x
-#endif
-
-
-#endif
diff --git a/src/splaytree.c b/src/splaytree.c
deleted file mode 100644
index 5d6a2b40..00000000
--- a/src/splaytree.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- 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 <stdlib.h>
-#include <assert.h>
-#include "splaytree.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, root_size, l_size, r_size;
-
- if (t == NULL) return t;
- N.left = N.right = NULL;
- l = r = &N;
- root_size = node_size(t);
- l_size = r_size = 0;
-
- for (;;) {
- comp = compare(i, t->key);
- if (comp < 0) {
- 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 */
- }
-}
-
-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;
- }
- }
-}
-
-
diff --git a/src/splaytree.h b/src/splaytree.h
deleted file mode 100644
index e9c1c68e..00000000
--- a/src/splaytree.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _SPLAY_TREE_H_
-#define _SPLAY_TREE_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;
-
-
-LI_EXPORT splay_tree * splaytree_splay (splay_tree *t, int key);
-LI_EXPORT splay_tree * splaytree_insert(splay_tree *t, int key, void *data);
-LI_EXPORT splay_tree * splaytree_delete(splay_tree *t, int key);
-LI_EXPORT 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/src/stat_cache.c b/src/stat_cache.c
deleted file mode 100644
index 55587ec2..00000000
--- a/src/stat_cache.c
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * make sure _GNU_SOURCE is defined
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "log.h"
-#include "stat_cache.h"
-#include "fdevent.h"
-#include "etag.h"
-#include "server.h"
-#include "joblist.h"
-
-#ifdef HAVE_ATTR_ATTRIBUTES_H
-#include <attr/attributes.h>
-#endif
-
-#include "sys-mmap.h"
-#include "sys-files.h"
-#include "sys-strings.h"
-
-#undef HAVE_FAM_H
-#undef HAVE_SYS_INOTIFY_H
-
-#if 0
-/* enables debug code for testing if all nodes in the stat-cache as accessable */
-#define DEBUG_STAT_CACHE
-#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
- */
-#ifdef USE_GTHREAD
-typedef struct {
- buffer *name;
-
- void *con;
-} stat_job;
-
-static stat_job *stat_job_init() {
- stat_job *sj = calloc(1, sizeof(*sj));
-
- sj->name = buffer_init();
-
- return sj;
-}
-
-static void stat_job_free(stat_job *sj) {
- if (!sj) return;
-
- buffer_free(sj->name);
-
- free(sj);
-}
-
-gpointer stat_cache_thread(gpointer _srv) {
- server *srv = (server *)_srv;
- stat_job *sj = NULL;
-
- /* take the stat-job-queue */
- GAsyncQueue * inq;
-
- g_async_queue_ref(srv->stat_queue);
-
- inq = srv->stat_queue;
-
- /* */
- while (!srv->is_shutdown) {
- /* let's see what we have to stat */
- struct stat st;
-
- if ((sj = g_async_queue_pop(inq))) {
- if(sj == (stat_job *) 1)
- continue; /* just notifying us that srv->is_shutdown changed */
-
- /* don't care about the return code for now */
- stat(sj->name->ptr, &st);
-
- joblist_async_append(srv, sj->con);
- stat_job_free(sj);
- }
- }
-
- g_async_queue_unref(srv->stat_queue);
-
- return NULL;
-}
-#endif
-
-#ifdef HAVE_GLIB_H
-static guint sc_key_hash(gconstpointer v) {
- buffer *b = (buffer *)v;
-
- return g_str_hash(b->ptr);
-}
-
-static gboolean sc_key_equal(gconstpointer v1, gconstpointer v2) {
- buffer *b1 = (buffer *)v1;
- buffer *b2 = (buffer *)v2;
-
- return buffer_is_equal(b1, b2);
-}
-#endif
-
-stat_cache *stat_cache_init(void) {
- stat_cache *fc = NULL;
-
- fc = calloc(1, sizeof(*fc));
-
- fc->dir_name = buffer_init();
- fc->hash_key = buffer_init();
-
-#if defined(HAVE_SYS_INOTIFY_H)
- fc->sock = iosocket_init();
-#endif
-#ifdef HAVE_GLIB_H
- fc->files = g_hash_table_new(sc_key_hash, sc_key_equal);
-#endif
-
- return fc;
-}
-
-static stat_cache_entry * stat_cache_entry_init(void) {
- stat_cache_entry *sce = NULL;
-
- sce = calloc(1, sizeof(*sce));
-
- sce->name = buffer_init();
- sce->etag = buffer_init();
- sce->content_type = buffer_init();
-
- return sce;
-}
-
-static void stat_cache_entry_free(void *data) {
- stat_cache_entry *sce = data;
- if (!sce) return;
-
- buffer_free(sce->etag);
- buffer_free(sce->name);
- buffer_free(sce->content_type);
-
- free(sce);
-}
-
-#ifdef HAVE_GLIB_H
-static gboolean stat_cache_free_hrfunc(gpointer _key, gpointer _value, gpointer _user_data) {
- stat_cache_entry *sce = _value;
- buffer *b = _key;
- UNUSED(_user_data);
-
- buffer_free(b);
- stat_cache_entry_free(sce);
-
- return TRUE;
-}
-#endif
-
-void stat_cache_free(stat_cache *sc) {
-#ifdef HAVE_GLIB_H
- g_hash_table_foreach_remove(sc->files, stat_cache_free_hrfunc, NULL);
- g_hash_table_destroy(sc->files);
-#endif
-
- buffer_free(sc->dir_name);
- buffer_free(sc->hash_key);
-
-#if defined(HAVE_SYS_INOTIFY_H)
- if (sc->sock) iosocket_free(sc->sock);
-#endif
-
- free(sc);
-}
-
-#ifdef HAVE_XATTR
-static int stat_cache_attr_get(buffer *buf, char *name) {
- int attrlen;
- int ret;
-
- attrlen = 1024;
- buffer_prepare_copy(buf, attrlen);
- attrlen--;
- if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) {
- buf->used = attrlen + 1;
- buf->ptr[attrlen] = '\0';
- }
- return ret;
-}
-#endif
-
-handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
- server *srv = _srv;
-
- switch (srv->srvconf.stat_cache_engine) {
-#ifdef HAVE_SYS_INOTIFY_H
- case STAT_CACHE_ENGINE_INOTIFY:
- return stat_cache_handle_fdevent_inotify(_srv, _fce, revent);
-#else
- UNUSED(_fce);
- UNUSED(revent);
-#endif
- default:
- return HANDLER_GO_ON;
- }
-}
-#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
-
-static int stat_cache_entry_is_current(server *srv, stat_cache_entry *sce) {
- struct stat st;
- UNUSED(srv);
- UNUSED(sce);
-
- if (-1 == stat(sce->name->ptr, &st)) {
- return 0;
- }
- /* still existing */
-
- if (st.st_dev != sce->st.st_dev || st.st_ino != sce->st.st_ino) {
- return 0; /* different file */
- }
-
- /* same file, still existing: update other stats: */
- sce->st = st;
- /* need to check other properties before this: sce->stat_ts = srv->cur_ts; */
- return 1;
-}
-
-static void stat_cache_remove_entry(stat_cache *sc, buffer *hash_key, stat_cache_entry *sce) {
-#ifdef HAVE_GLIB_H
- gpointer orig_key;
- if (!g_hash_table_lookup_extended(sc->files, hash_key, &orig_key, NULL))
- return;
- g_hash_table_remove(sc->files, hash_key);
- stat_cache_entry_free(sce);
- buffer_free((buffer*) orig_key);
-#else
- stat_cache_entry_free(sce);
-#endif
-}
-
-/***
- *
- *
- *
- * returns:
- * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
- * - HANDLER_ERROR on stat() failed -> see errno for problem
- *
- *
- * glib: if glib is not available, we don't cache
- */
-
-static handler_t stat_cache_get_entry_internal(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce, int async) {
- stat_cache_entry *sce = NULL;
- stat_cache *sc;
- struct stat st;
- size_t k;
- int fd;
- struct stat lst;
-
- *ret_sce = NULL;
-
- /*
- * check if the directory for this file has changed
- */
-
- sc = srv->stat_cache;
-
- buffer_copy_string_buffer(sc->hash_key, name);
- buffer_append_long(sc->hash_key, con->conf.follow_symlink);
-
-#ifdef HAVE_GLIB_H
- if ((sce = (stat_cache_entry *)g_hash_table_lookup(sc->files, sc->hash_key))) {
- /* know this entry already */
-
- if (sce->state == STAT_CACHE_ENTRY_STAT_FINISHED &&
- stat_cache_entry_is_current(srv, sce)) {
- /* verify that this entry is still fresh */
-
- *ret_sce = sce;
-
- return HANDLER_GO_ON;
- }
- }
-
- if (!sce) {
- sce = stat_cache_entry_init();
-
- buffer_copy_string_buffer(sce->name, name);
-
- g_hash_table_insert(sc->files, buffer_init_string(BUF_STR(sc->hash_key)), sce);
- }
-#else
- /**
- * we don't have glib, but we still have to store the sce somewhere to not loose it
- */
- sce = stat_cache_entry_init();
-
- buffer_copy_string_buffer(sce->name, name);
-#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
- *
- * */
-
- /* pass a job to the stat-queue */
-#ifdef USE_GTHREAD
- if (async &&
- srv->srvconf.max_stat_threads > 0 &&
- sce->state == STAT_CACHE_ENTRY_UNSET) {
- stat_job *sj = stat_job_init();
-
- buffer_copy_string_buffer(sj->name, name);
- sj->con = con;
-
- g_async_queue_push(srv->stat_queue, sj);
-
- sce->state = STAT_CACHE_ENTRY_ASYNC_STAT;
-
- /* the response for this will be in the stat-cache,
- * a second call will just fetch the data from the stat-cache */
-
- return HANDLER_WAIT_FOR_EVENT;
- }
-#endif
- /*
- * O_NONBLOCK skips named pipes and locked files
- *
- * O_NOATIME leads to EPERM on SYMLINKS
- * */
-#ifndef O_NONBLOCK
-#define O_NONBLOCK 0
-#endif
- if (-1 == (fd = open(name->ptr, O_NONBLOCK | O_RDONLY | (srv->srvconf.use_noatime ? O_NOATIME : 0)))) {
- if (srv->srvconf.use_noatime && errno == EPERM) {
- if (-1 == (fd = open(name->ptr, O_NONBLOCK | O_RDONLY))) {
- stat_cache_remove_entry(sc, sc->hash_key, sce);
- return HANDLER_ERROR;
- }
- } else {
- stat_cache_remove_entry(sc, sc->hash_key, sce);
- return HANDLER_ERROR;
- }
- }
-
- if (-1 == fstat(fd, &st)) {
- close(fd);
- stat_cache_remove_entry(sc, sc->hash_key, sce);
- return HANDLER_ERROR;
- }
-
- close(fd);
-
- sce->st = st;
- sce->stat_ts = srv->cur_ts;
- sce->state = STAT_CACHE_ENTRY_STAT_FINISHED;
-
- /* 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 (!con->conf.follow_symlink) {
- if (stat_cache_lstat(srv, name, &lst) == 0) {
-#ifdef DEBUG_STAT_CACHE
- TRACE("found symlink in %s", SAFE_BUF_STR(name));
-#endif
- sce->is_symlink = 1;
- }
-
- /*
- * we assume "/" can not be symlink, so
- * skip the symlink stuff if our path is /
- **/
- else if ((name->used > 2)) {
- buffer *dname;
- char *s_cur;
-
- dname = buffer_init();
- buffer_copy_string_buffer(dname, name);
-
- while ((s_cur = strrchr(dname->ptr,'/'))) {
- *s_cur = '\0';
- dname->used = s_cur - dname->ptr + 1;
- if (dname->ptr == s_cur) {
-#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
-#endif
- break;
- }
-#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "checking if", dname, "is a symlink");
-#endif
- if (stat_cache_lstat(srv, dname, &lst) == 0) {
- sce->is_symlink = 1;
-#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "found symlink", dname);
-#endif
- break;
- }
- }
- buffer_free(dname);
- }
- }
-#endif
-
- if (S_ISREG(st.st_mode)) {
- /* determine mimetype */
- buffer_reset(sce->content_type);
-#ifdef HAVE_XATTR
- if (con->conf.use_xattr) {
- stat_cache_attr_get(sce->content_type, name->ptr);
- }
-#endif
- /* xattr did not set a content-type. ask the config */
- if (buffer_is_empty(sce->content_type)) {
- for (k = 0; k < con->conf.mimetypes->used; k++) {
- data_string *ds = (data_string *)con->conf.mimetypes->data[k];
- buffer *type = ds->key;
-
- if (type->used == 0) continue;
-
- /* check if the right side is the same */
- if (type->used > name->used) continue;
-
- if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) {
- buffer_copy_string_buffer(sce->content_type, ds->value);
- break;
- }
- }
- }
- etag_create(sce->etag, &(sce->st), con->etag_flags);
- } else if (S_ISDIR(st.st_mode)) {
- etag_create(sce->etag, &(sce->st), con->etag_flags);
- }
-
- *ret_sce = sce;
-
- return HANDLER_GO_ON;
-}
-
-
-handler_t stat_cache_get_entry_async(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce) {
- return stat_cache_get_entry_internal(srv, con, name, ret_sce, 1);
-}
-
-handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce) {
- return stat_cache_get_entry_internal(srv, con, name, ret_sce, 0);
-}
-
-/**
- * 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
- */
-
-#ifdef HAVE_GLIB_H
-static gboolean stat_cache_remove_old_entry(gpointer _key, gpointer _value, gpointer user_data) {
- server *srv = user_data;
- buffer *key = _key;
- stat_cache_entry *sce = _value;
-
- if (sce->state == STAT_CACHE_ENTRY_STAT_FINISHED &&
- srv->cur_ts - sce->stat_ts > 10) {
- buffer_free(key);
- stat_cache_entry_free(sce);
-
- return TRUE;
- }
-
- return FALSE;
-}
-#endif
-
-int stat_cache_trigger_cleanup(server *srv) {
- stat_cache *sc;
-
- sc = srv->stat_cache;
-
-#ifdef HAVE_GLIB_H
- if (!sc->files) return 0;
-
- g_hash_table_foreach_remove(sc->files, stat_cache_remove_old_entry, srv);
-#endif
-
- return 0;
-}
diff --git a/src/stat_cache.h b/src/stat_cache.h
deleted file mode 100644
index 3790edcf..00000000
--- a/src/stat_cache.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _FILE_CACHE_H_
-#define _FILE_CACHE_H_
-
-#include "base.h"
-
-LI_EXPORT stat_cache * stat_cache_init(void);
-LI_EXPORT void stat_cache_free(stat_cache *fc);
-
-LI_EXPORT handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **fce);
-LI_EXPORT handler_t stat_cache_get_entry_async(server *srv, connection *con, buffer *name, stat_cache_entry **fce);
-LI_EXPORT handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent);
-
-LI_EXPORT int stat_cache_trigger_cleanup(server *srv);
-#endif
diff --git a/src/status_counter.c b/src/status_counter.c
deleted file mode 100644
index 6a3233f4..00000000
--- a/src/status_counter.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <stdlib.h>
-
-#include "status_counter.h"
-/**
- * The status array can carry all the status information you want
- * the key to the array is <module-prefix>.<name>
- * and the values are counters
- *
- * example:
- * fastcgi.backends = 10
- * fastcgi.active-backends = 6
- * fastcgi.backend.<key>.load = 24
- * fastcgi.backend.<key>....
- *
- * fastcgi.backend.<key>.disconnects = ...
- */
-
-static array *counters = NULL;
-
-void status_counter_init(void) {
- counters = array_init();
-}
-void status_counter_free(void) {
- array_free(counters);
-}
-
-array *status_counter_get_array(void) {
- return counters;
-}
-
-data_integer *status_counter_get_counter(const char *s, size_t len) {
- data_integer *di;
- array *status = status_counter_get_array();
-
- if (NULL == (di = (data_integer *)array_get_element(status, s, len))) {
- /* not found, create it */
-
- if (NULL == (di = (data_integer *)array_get_unused_element(status, TYPE_INTEGER))) {
- di = data_integer_init();
- }
- buffer_copy_string_len(di->key, s, len);
- di->value = 0;
-
- array_insert_unique(status, (data_unset *)di);
- }
- return di;
-}
-
-/* dummies of the statistic framework functions
- * they will be moved to a statistics.c later */
-int status_counter_inc(const char *s, size_t len) {
- data_integer *di = status_counter_get_counter(s, len);
-
- di->value++;
-
- return 0;
-}
-
-int status_counter_dec(const char *s, size_t len) {
- data_integer *di = status_counter_get_counter(s, len);
-
- if (di->value > 0) di->value--;
-
- return 0;
-}
-
-int status_counter_set(const char *s, size_t len, int val) {
- data_integer *di = status_counter_get_counter(s, len);
-
- di->value = val;
-
- return 0;
-}
-
-
diff --git a/src/status_counter.h b/src/status_counter.h
deleted file mode 100644
index 34d39a76..00000000
--- a/src/status_counter.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _STATUS_COUNTER_H_
-#define _STATUS_COUNTER_H_
-
-#include <sys/types.h>
-
-#include "array.h"
-
-LI_EXPORT void status_counter_init(void);
-LI_EXPORT void status_counter_free(void);
-LI_EXPORT array * status_counter_get_array(void);
-LI_EXPORT data_integer * status_counter_get_counter(const char *s, size_t len);
-LI_EXPORT int status_counter_inc(const char *s, size_t len);
-LI_EXPORT int status_counter_dec(const char *s, size_t len);
-LI_EXPORT int status_counter_set(const char *s, size_t len, int val);
-
-#define COUNTER_INC(di) if (di) di->value++;
-#define COUNTER_DEC(di) if (di && di->value > 0) di->value--;
-#define COUNTER_SET(di, val) if (di) di->value = val;
-
-#endif
diff --git a/src/stream.c b/src/stream.c
deleted file mode 100644
index e4b52875..00000000
--- a/src/stream.c
+++ /dev/null
@@ -1,107 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-
-#include "stream.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sys-mmap.h"
-#include "sys-files.h"
-
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-int stream_open(stream *f, buffer *fn) {
- struct stat st;
-#ifdef HAVE_MMAP
- int fd;
-#elif defined _WIN32
- HANDLE *fh, *mh;
- void *p;
-#endif
-
- f->start = NULL;
-
- if (-1 == stat(fn->ptr, &st)) {
- return -1;
- }
-
- f->size = st.st_size;
-
-#ifdef HAVE_MMAP
- if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
- return -1;
- }
-
- f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
-
- close(fd);
-
- if (MAP_FAILED == f->start) {
- return -1;
- }
-
-#elif defined _WIN32
- fh = CreateFile(fn->ptr,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_READONLY,
- NULL);
-
- if (fh == INVALID_HANDLE_VALUE) return -1;
-
- mh = CreateFileMapping( fh,
- NULL,
- PAGE_READONLY,
- (sizeof(off_t) > 4) ? f->size >> 32 : 0,
- f->size & 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 );
-*/
- return -1;
- }
-
- p = MapViewOfFile(mh,
- FILE_MAP_READ,
- 0,
- 0,
- 0);
- CloseHandle(mh);
- CloseHandle(fh);
-
- f->start = p;
-#else
-# error no mmap found
-#endif
-
- return 0;
-}
-
-int stream_close(stream *f) {
-#ifdef HAVE_MMAP
- if (f->start) munmap(f->start, f->size);
-#elif defined(__WIN32)
- if (f->start) UnmapViewOfFile(f->start);
-#endif
-
- f->start = NULL;
-
- return 0;
-}
diff --git a/src/stream.h b/src/stream.h
deleted file mode 100644
index 0a974c05..00000000
--- a/src/stream.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _STREAM_H_
-#define _STREAM_H_
-
-#include "buffer.h"
-
-typedef struct {
- char *start;
- off_t size;
-} stream;
-
-LI_EXPORT int stream_open(stream *f, buffer *fn);
-LI_EXPORT int stream_close(stream *f);
-
-#endif
diff --git a/src/sys-files.c b/src/sys-files.c
deleted file mode 100644
index 2a9079a3..00000000
--- a/src/sys-files.c
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "sys-files.h"
-
-#ifdef _WIN32
-#include "buffer.h"
-DIR *opendir(const char *dn) {
- DIR *d = malloc(sizeof(*d));
-
- if (INVALID_HANDLE_VALUE == (d->h = FindFirstFile(dn, &(d->finddata)))) {
- free(d);
- return NULL;
- }
-
- return d;
-}
-
-struct dirent *readdir(DIR *d) {
- if (!d->dent.d_name) {
- /* opendir has set a finddata already, push it out */
-
- d->dent.d_name = d->finddata.cFileName;
- return &(d->dent);
- }
- if (FindNextFile(d->h, &(d->finddata))) {
- d->dent.d_name = d->finddata.cFileName;
- return &(d->dent);
- } else {
- return NULL;
- }
-}
-
-void closedir(DIR *d) {
- FindClose(d);
-
- free(d);
-}
-
-buffer *pathname_unix2local(buffer *fn) {
- size_t i;
-
- for (i = 0; i < fn->used; i++) {
- if (fn->ptr[i] == '/') {
- fn->ptr[i] = '\\';
- }
- }
-
- return fn;
-}
-
-buffer *filename_unix2local(buffer *fn) {
- size_t i;
-
- for (i = 0; i < fn->used; i++) {
- if (fn->ptr[i] == '/') {
- fn->ptr[i] = '\\';
- }
- }
-#if 0
- buffer_prepare_append(fn, 4);
- memmove(fn->ptr + 4, fn->ptr, fn->used);
- memcpy(fn->ptr, "\\\\?\\", 4);
- fn->used += 4;
-#endif
- return fn;
-}
-#endif
-
diff --git a/src/sys-files.h b/src/sys-files.h
deleted file mode 100644
index b964f990..00000000
--- a/src/sys-files.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef _SYS_FILES_H_
-#define _SYS_FILES_H_
-
-#define DIR_SEPERATOR_UNIX '/'
-#define DIR_SEPERATOR_UNIX_STR "/"
-#define DIR_SEPERATOR_WIN '\\'
-#define DIR_SEPERATOR_WIN_STR "\\"
-
-#include "settings.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#include <io.h> /* open */
-#include <direct.h> /* chdir */
-
-#include "buffer.h"
-
-#define DIR_SEPERATOR DIR_SEPERATOR_WIN
-#define DIR_SEPERATOR_STR DIR_SEPERATOR_WIN_STR
-
-#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
-
-#undef S_ISDIR
-#undef S_ISCHR
-#undef S_ISBLK
-#undef S_ISREG
-#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
-#define S_ISCHR(mode) __S_ISTYPE((mode), _S_IFCHR)
-#define S_ISBLK(mode) __S_ISTYPE((mode), _S_IFBLK)
-#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
-/* we don't support symlinks */
-#define S_ISLNK(mode) 0
-
-#define lstat stat
-#define mkstemp(x) open(mktemp(x), O_RDWR)
-#define mkdir(x, y) mkdir(x)
-
-/* retrieve the most recent network, or general libc error */
-#define light_sock_errno() (WSAGetLastError())
-
-struct dirent {
- const char *d_name;
-};
-
-typedef struct {
- HANDLE h;
- WIN32_FIND_DATA finddata;
- struct dirent dent;
-} DIR;
-
-LI_EXPORT DIR * opendir(const char *dn);
-LI_EXPORT struct dirent * readdir(DIR *d);
-LI_EXPORT void closedir(DIR *d);
-
-LI_EXPORT buffer * filename_unix2local(buffer *b);
-LI_EXPORT buffer * pathname_unix2local(buffer *b);
-
-#else
-#include <unistd.h>
-#include <dirent.h>
-
-#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
-#define DIR_SEPERATOR_STR DIR_SEPERATOR_UNIX_STR
-
-#define light_sock_errno() (errno)
-
-#define filename_unix2local(x) /* (x) */
-#define pathname_unix2local(x) /* (x) */
-#endif
-
-#define PATHNAME_APPEND_SLASH(x) \
- if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
- char sl[2] = { DIR_SEPERATOR, 0 }; \
- BUFFER_APPEND_STRING_CONST(x, sl); \
- }
-
-#ifndef O_LARGEFILE
-# define O_LARGEFILE 0
-#endif
-
-#ifndef O_NOATIME
-# define O_NOATIME 0
-#endif
-
-#endif
-
-
diff --git a/src/sys-mmap.h b/src/sys-mmap.h
deleted file mode 100644
index 560987b3..00000000
--- a/src/sys-mmap.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef WIN32_MMAP_H
-#define WIN32_MMAP_H
-
-#include "settings.h"
-
-#ifdef _WIN32
-
-#define MAP_FAILED -1
-#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)
-
-#include <windows.h>
-
-#else
-#include <sys/mman.h>
-
-#ifndef MAP_FAILED
-#define MAP_FAILED -1
-#endif
-#endif
-
-#endif
diff --git a/src/sys-process.h b/src/sys-process.h
deleted file mode 100644
index 53df76e7..00000000
--- a/src/sys-process.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _SYS_PROCESS_H_
-#define _SYS_PROCESS_H_
-
-#ifdef _WIN32
-#include <process.h>
-#define pid_t int
-/* win32 has no fork() */
-#define kill(x, y) do { } while (0)
-#define getpid() 0
-
-#else
-#include <sys/wait.h>
-#include <unistd.h>
-#endif
-
-#endif
-
diff --git a/src/sys-socket.c b/src/sys-socket.c
deleted file mode 100644
index 97664115..00000000
--- a/src/sys-socket.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "base.h"
-#include "sys-socket.h"
-
-#ifndef HAVE_INET_ATON
-/* win32 has inet_addr instead if inet_aton */
-# ifdef HAVE_INET_ADDR
-int inet_aton(const char *cp, struct in_addr *inp) {
- struct in_addr a;
-
- a.s_addr = inet_addr(cp);
-
- if (INADDR_NONE == a.s_addr) {
- return 0;
- }
-
- inp->s_addr = a.s_addr;
-
- return 1;
-}
-# else
-# error no inet_aton emulation found
-# endif
-
-#endif
-
-#ifdef _WIN32
-
-#include <winsock2.h>
-
-/* windows doesn't have inet_ntop */
-
-/*
-I have to look into this more. WSAAddressToString takes a sockaddr structure, which includes
-the port number, so I must first test this stuff more carefully. For now, no IPV6 on windows.
-You will notice that HAVE_IPV6 is never true for win32.
-*/
-
-const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
-{
- /* WSAAddressToString takes a full sockaddr, while inet_ntop only takes the address */
- struct sockaddr_in sock4;
- struct sockaddr_in6 sock6;
- DWORD addrLen = cnt;
- int err = 0;
-
- /* src is either an in_addr or an in6_addr. */
- const struct in_addr *src4 = (const struct in_addr*) src;
- const struct in6_addr *src6 = (const struct in6_addr*) src;
-
- int ipv6 = af == AF_INET6;
-
- // DebugBreak();
-
- if ( ipv6 )
- {
- sock6.sin6_family = AF_INET6;
- sock6.sin6_port = 0;
- sock6.sin6_addr = *src6;
- }
- else
- {
- sock4.sin_family = AF_INET;
- sock4.sin_port = 0;
- sock4.sin_addr = *src4;
- }
-
- err = WSAAddressToStringA(
- ipv6 ? (LPSOCKADDR) &sock6 : (LPSOCKADDR) &sock4,
- ipv6 ? sizeof(sock6) : sizeof(sock4),
- NULL,
- dst, &addrLen );
- return err == 0 ? dst : NULL;
-}
-
-
-#endif
diff --git a/src/sys-socket.h b/src/sys-socket.h
deleted file mode 100644
index cf93efd2..00000000
--- a/src/sys-socket.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef SYS_SOCKET_H
-#define SYS_SOCKET_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef _WIN32
-#ifndef FD_SETSIZE
-/* By default this is 64 */
-#define FD_SETSIZE 4096
-#endif
-#include <winsock2.h>
-#include <ws2tcpip.h>
-//#include <wspiapi.h>
-//#define HAVE_IPV6 -- not until we've resolved the inet_ntop issue.
-
-#define ECONNRESET WSAECONNRESET
-#define EINPROGRESS WSAEINPROGRESS
-#define EALREADY WSAEALREADY
-#define ENOTCONN WSAENOTCONN
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define ECONNABORTED WSAECONNABORTED
-#define ECONNREFUSED WSAECONNREFUSED
-#define EHOSTUNREACH WSAEHOSTUNREACH
-#define ioctl ioctlsocket
-#define hstrerror(x) ""
-#define STDIN_FILENO 0
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-#ifndef __MINGW32__
-#define ssize_t int
-#endif
-
-#define sockread( fd, buf, bytes ) recv( fd, buf, bytes, 0 )
-
-LI_EXPORT const char * inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
-int inet_aton(const char *cp, struct in_addr *inp);
-#define HAVE_INET_ADDR
-#undef HAVE_INET_ATON
-
-#else
-#include <sys/types.h> /* required by netinet/tcp.h on FreeBSD */
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
-
-#ifndef SUN_LEN
-#define SUN_LEN(su) \
- (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
-#endif
-
-#define sockread( fd, buf, bytes ) read( fd, buf, bytes )
-#define closesocket(x) close(x)
-
-#include <netdb.h>
-#endif /* !_WIN32 */
-
-typedef union {
-#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;
-} sock_addr;
-
-#endif
diff --git a/src/sys-strings.h b/src/sys-strings.h
deleted file mode 100644
index 1103a8c1..00000000
--- a/src/sys-strings.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _SYS_STRINGS_H_
-#define _SYS_STRINGS_H_
-
-#ifdef _WIN32
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
-#include <stdlib.h>
-#define str_to_off_t(p, e, b) _strtoi64(p, e, b)
-#define STR_OFF_T_MAX LLONG_MAX
-#define STR_OFF_T_MIN LLONG_MIN
-#define strtoull _strtoui64
-#ifdef __MINGW32__
-/* missing prototype */
-unsigned __int64 _strtoui64(
- const char *nptr,
- char **endptr,
- int base
- );
-__int64 _strtoi64(
- const char *nptr,
- char **endptr,
- int base
- );
-#endif
-#else /** we are a unix */
-
-/**
- * we use strtoll() for parsing the ranges into a off_t
- *
- * if off_t is 32bit, we can use strtol() instead
- */
- #if SIZEOF_OFF_T == SIZEOF_LONG
- #define str_to_off_t(p, e, b) strtol(p, e, b)
- #define STR_OFF_T_MAX LONG_MAX
- #define STR_OFF_T_MIN LONG_MIN
- #elif defined(HAVE_STRTOLL)
- #define str_to_off_t(p, e, b) strtoll(p, e, b)
- #define STR_OFF_T_MAX LLONG_MAX
- #define STR_OFF_T_MIN LLONG_MIN
- #else
- #error off_t is more than 4 bytes but we can not parse it with strtol() (run autogen.sh again if you build from svn)
- #endif
-#endif
-
-#endif
-
diff --git a/src/timing.c b/src/timing.c
deleted file mode 100644
index 94c9441b..00000000
--- a/src/timing.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "base.h"
-#include "timing.h"
-
-void timing_log(server *srv, connection *con, int field) {
-#ifdef HAVE_GLIB_H
- if (srv->srvconf.log_timing) {
- g_get_current_time(&(con->timestamps[field]));
- }
-#endif
-}
-
diff --git a/src/timing.h b/src/timing.h
deleted file mode 100644
index 7fbb2ae5..00000000
--- a/src/timing.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _TIMING_H_
-#define _TIMING_H_
-
-#include "base.h"
-
-#define TIME_DIFF(t2, t1) \
- ((con->timestamps[t2].tv_sec - con->timestamps[t1].tv_sec) * 1000 + \
- (con->timestamps[t2].tv_usec - con->timestamps[t1].tv_usec) / 1000)
-
-LI_API void timing_log(server *srv, connection *con, int field);
-
-#endif
diff --git a/src/valgrind/Makefile.am b/src/valgrind/Makefile.am
deleted file mode 100644
index f3071778..00000000
--- a/src/valgrind/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-noinst_HEADERS = valgrind.h
diff --git a/src/valgrind/valgrind.h b/src/valgrind/valgrind.h
deleted file mode 100644
index a7120859..00000000
--- a/src/valgrind/valgrind.h
+++ /dev/null
@@ -1,469 +0,0 @@
-/* -*- c -*-
- ----------------------------------------------------------------
-
- Notice that the following BSD-style license applies to this one
- file (valgrind.h) only. The entire rest of Valgrind is licensed
- under the terms of the GNU General Public License, version 2. See
- the COPYING file in the source distribution for details.
-
- ----------------------------------------------------------------
-
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2000-2005 Julian Seward. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. The origin of this software must not be misrepresented; you must
- not claim that you wrote the original software. If you use this
- software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
-
- 3. Altered source versions must be plainly marked as such, and must
- not be misrepresented as being the original software.
-
- 4. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
-
- ----------------------------------------------------------------
-
- Notice that the above BSD-style license applies to this one file
- (valgrind.h) only. The entire rest of Valgrind is licensed under
- the terms of the GNU General Public License, version 2. See the
- COPYING file in the source distribution for details.
-
- ----------------------------------------------------------------
-*/
-
-
-/* This file is for inclusion into client (your!) code.
-
- You can use these macros to manipulate and query Valgrind's
- execution inside your own programs.
-
- The resulting executables will still run without Valgrind, just a
- little bit more slowly than they otherwise would, but otherwise
- unchanged. When not running on valgrind, each client request
- consumes very few (eg. < 10) instructions, so the resulting performance
- loss is negligible unless you plan to execute client requests
- millions of times per second. Nevertheless, if that is still a
- problem, you can compile with the NVALGRIND symbol defined (gcc
- -DNVALGRIND) so that client requests are not even compiled in. */
-
-#ifndef __VALGRIND_H
-#define __VALGRIND_H
-
-#include <stdarg.h>
-
-/* Nb: this file might be included in a file compiled with -ansi. So
- we can't use C++ style "//" comments nor the "asm" keyword (instead
- use "__asm__"). */
-
-/* If we're not compiling for our target architecture, don't generate
- any inline asms. Note that in this file we're using the compiler's
- CPP symbols for identifying architectures, which are different to
- the ones we use within the rest of Valgrind. */
-#if !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__)
-# ifndef NVALGRIND
-# define NVALGRIND 1
-# endif /* NVALGRIND */
-#endif
-
-/* ------------------------------------------------------------------ */
-/* The architecture-specific part */
-/* ------------------------------------------------------------------ */
-
-#ifdef NVALGRIND
-
-/* Define NVALGRIND to completely remove the Valgrind magic sequence
- from the compiled code (analogous to NDEBUG's effects on assert()) */
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, \
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
- { \
- (_zzq_rlval) = (_zzq_default); \
- }
-
-#else /* NVALGRIND */
-
-/* The following defines the magic code sequences which the JITter spots and
- handles magically. Don't look too closely at them; they will rot
- your brain. We must ensure that the default value gets put in the return
- slot, so that everything works when this is executed not under Valgrind.
- Args are passed in a memory block, and so there's no intrinsic limit to
- the number that could be passed, but it's currently four.
-
- The macro args are:
- _zzq_rlval result lvalue
- _zzq_default default value (result returned when running on real CPU)
- _zzq_request request code
- _zzq_arg1..4 request params
-
- Nb: we put the assembly code sequences for all architectures in this one
- file. This is because this file must be stand-alone, and we don't want
- to have multiple files.
-*/
-
-#ifdef __x86_64__
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, \
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
- \
- { volatile unsigned long long _zzq_args[5]; \
- _zzq_args[0] = (volatile unsigned long long)(_zzq_request); \
- _zzq_args[1] = (volatile unsigned long long)(_zzq_arg1); \
- _zzq_args[2] = (volatile unsigned long long)(_zzq_arg2); \
- _zzq_args[3] = (volatile unsigned long long)(_zzq_arg3); \
- _zzq_args[4] = (volatile unsigned long long)(_zzq_arg4); \
- __asm__ volatile("roll $29, %%eax ; roll $3, %%eax\n\t" \
- "rorl $27, %%eax ; rorl $5, %%eax\n\t" \
- "roll $13, %%eax ; roll $19, %%eax" \
- : "=d" (_zzq_rlval) \
- : "a" (&_zzq_args[0]), "0" (_zzq_default) \
- : "cc", "memory" \
- ); \
- }
-#endif /* __x86_64__ */
-
-#ifdef __i386__
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, \
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
- \
- { unsigned int _zzq_args[5]; \
- _zzq_args[0] = (unsigned int)(_zzq_request); \
- _zzq_args[1] = (unsigned int)(_zzq_arg1); \
- _zzq_args[2] = (unsigned int)(_zzq_arg2); \
- _zzq_args[3] = (unsigned int)(_zzq_arg3); \
- _zzq_args[4] = (unsigned int)(_zzq_arg4); \
- __asm__ volatile("roll $29, %%eax ; roll $3, %%eax\n\t" \
- "rorl $27, %%eax ; rorl $5, %%eax\n\t" \
- "roll $13, %%eax ; roll $19, %%eax" \
- : "=d" (_zzq_rlval) \
- : "a" (&_zzq_args[0]), "0" (_zzq_default) \
- : "cc", "memory" \
- ); \
- }
-#endif /* __i386__ */
-
-#ifdef __powerpc__
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, \
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
- \
- { volatile unsigned int _zzq_args[5]; \
- register unsigned int _zzq_tmp __asm__("r3"); \
- register volatile unsigned int *_zzq_ptr __asm__("r4"); \
- _zzq_args[0] = (volatile unsigned int)(_zzq_request); \
- _zzq_args[1] = (volatile unsigned int)(_zzq_arg1); \
- _zzq_args[2] = (volatile unsigned int)(_zzq_arg2); \
- _zzq_args[3] = (volatile unsigned int)(_zzq_arg3); \
- _zzq_args[4] = (volatile unsigned int)(_zzq_arg4); \
- _zzq_ptr = _zzq_args; \
- __asm__ volatile("tw 0,3,27\n\t" \
- "rlwinm 0,0,29,0,0\n\t" \
- "rlwinm 0,0,3,0,0\n\t" \
- "rlwinm 0,0,13,0,0\n\t" \
- "rlwinm 0,0,19,0,0\n\t" \
- "nop\n\t" \
- : "=r" (_zzq_tmp) \
- : "0" (_zzq_default), "r" (_zzq_ptr) \
- : "memory"); \
- _zzq_rlval = (__typeof__(_zzq_rlval)) _zzq_tmp; \
- }
-#endif /* __powerpc__ */
-
-/* Insert assembly code for other architectures here... */
-
-#endif /* NVALGRIND */
-
-
-/* ------------------------------------------------------------------ */
-/* The architecture-independent part */
-/* ------------------------------------------------------------------ */
-
-/* Some request codes. There are many more of these, but most are not
- exposed to end-user view. These are the public ones, all of the
- form 0x1000 + small_number.
-
- Core ones are in the range 0x00000000--0x0000ffff. The non-public ones
- start at 0x2000.
-*/
-
-/* These macros are used by tools -- they must be public, but don't embed them
- * into other programs. */
-#define VG_USERREQ_TOOL_BASE(a,b) \
- ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
-#define VG_IS_TOOL_USERREQ(a, b, v) \
- (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
-
-typedef
- enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001,
- VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
-
- /* These allow any function to be called from the
- simulated CPU but run on the real CPU.
- Nb: the first arg passed to the function is always the ThreadId of
- the running thread! So CLIENT_CALL0 actually requires a 1 arg
- function, etc. */
- VG_USERREQ__CLIENT_CALL0 = 0x1101,
- VG_USERREQ__CLIENT_CALL1 = 0x1102,
- VG_USERREQ__CLIENT_CALL2 = 0x1103,
- VG_USERREQ__CLIENT_CALL3 = 0x1104,
-
- /* Can be useful in regression testing suites -- eg. can send
- Valgrind's output to /dev/null and still count errors. */
- VG_USERREQ__COUNT_ERRORS = 0x1201,
-
- /* These are useful and can be interpreted by any tool that tracks
- malloc() et al, by using vg_replace_malloc.c. */
- VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
- VG_USERREQ__FREELIKE_BLOCK = 0x1302,
- /* Memory pool support. */
- VG_USERREQ__CREATE_MEMPOOL = 0x1303,
- VG_USERREQ__DESTROY_MEMPOOL = 0x1304,
- VG_USERREQ__MEMPOOL_ALLOC = 0x1305,
- VG_USERREQ__MEMPOOL_FREE = 0x1306,
-
- /* Allow printfs to valgrind log. */
- VG_USERREQ__PRINTF = 0x1401,
- VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
-
- /* Stack support. */
- VG_USERREQ__STACK_REGISTER = 0x1501,
- VG_USERREQ__STACK_DEREGISTER = 0x1502,
- VG_USERREQ__STACK_CHANGE = 0x1503,
- } Vg_ClientRequest;
-
-#ifndef __GNUC__
-#define __extension__
-#endif
-
-/* Returns the number of Valgrinds this code is running under. That is,
- 0 if running natively, 1 if running under Valgrind, 2 if running under
- Valgrind which is running under another Valgrind, etc. */
-#define RUNNING_ON_VALGRIND __extension__ \
- ({unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0 /* returned if not */, \
- VG_USERREQ__RUNNING_ON_VALGRIND, \
- 0, 0, 0, 0); \
- _qzz_res; \
- })
-
-
-/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
- _qzz_len - 1]. Useful if you are debugging a JITter or some such,
- since it provides a way to make sure valgrind will retranslate the
- invalidated area. Returns no value. */
-#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__DISCARD_TRANSLATIONS, \
- _qzz_addr, _qzz_len, 0, 0); \
- }
-
-#ifdef NVALGRIND
-
-#define VALGRIND_PRINTF(...)
-#define VALGRIND_PRINTF_BACKTRACE(...)
-
-#else /* NVALGRIND */
-
-int VALGRIND_PRINTF(const char *format, ...)
- __attribute__((format(__printf__, 1, 2)));
-__attribute__((weak))
-int
-VALGRIND_PRINTF(const char *format, ...)
-{
- unsigned long _qzz_res;
- va_list vargs;
- va_start(vargs, format);
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__PRINTF,
- (unsigned long)format, (unsigned long)vargs, 0, 0);
- va_end(vargs);
- return (int)_qzz_res;
-}
-
-int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
- __attribute__((format(__printf__, 1, 2)));
-__attribute__((weak))
-int
-VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
-{
- unsigned long _qzz_res;
- va_list vargs;
- va_start(vargs, format);
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE,
- (unsigned long)format, (unsigned long)vargs, 0, 0);
- va_end(vargs);
- return (int)_qzz_res;
-}
-
-#endif /* NVALGRIND */
-
-/* These requests allow control to move from the simulated CPU to the
- real CPU, calling an arbitary function */
-#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL0, \
- _qyy_fn, \
- 0, 0, 0); \
- _qyy_res; \
- })
-
-#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL1, \
- _qyy_fn, \
- _qyy_arg1, 0, 0); \
- _qyy_res; \
- })
-
-#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL2, \
- _qyy_fn, \
- _qyy_arg1, _qyy_arg2, 0); \
- _qyy_res; \
- })
-
-#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL3, \
- _qyy_fn, \
- _qyy_arg1, _qyy_arg2, _qyy_arg3); \
- _qyy_res; \
- })
-
-
-/* Counts the number of errors that have been recorded by a tool. Nb:
- the tool must record the errors with VG_(maybe_record_error)() or
- VG_(unique_error)() for them to be counted. */
-#define VALGRIND_COUNT_ERRORS \
- ({unsigned int _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__COUNT_ERRORS, \
- 0, 0, 0, 0); \
- _qyy_res; \
- })
-
-/* Mark a block of memory as having been allocated by a malloc()-like
- function. `addr' is the start of the usable block (ie. after any
- redzone) `rzB' is redzone size if the allocator can apply redzones;
- use '0' if not. Adding redzones makes it more likely Valgrind will spot
- block overruns. `is_zeroed' indicates if the memory is zeroed, as it is
- for calloc(). Put it immediately after the point where a block is
- allocated.
-
- If you're allocating memory via superblocks, and then handing out small
- chunks of each superblock, if you don't have redzones on your small
- blocks, it's worth marking the superblock with VALGRIND_MAKE_NOACCESS
- when it's created, so that block overruns are detected. But if you can
- put redzones on, it's probably better to not do this, so that messages
- for small overruns are described in terms of the small block rather than
- the superblock (but if you have a big overrun that skips over a redzone,
- you could miss an error this way). See memcheck/tests/custom_alloc.c
- for an example.
-
- Nb: block must be freed via a free()-like function specified
- with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */
-#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__MALLOCLIKE_BLOCK, \
- addr, sizeB, rzB, is_zeroed); \
- }
-
-/* Mark a block of memory as having been freed by a free()-like function.
- `rzB' is redzone size; it must match that given to
- VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the leak
- checker. Put it immediately after the point where the block is freed. */
-#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__FREELIKE_BLOCK, \
- addr, rzB, 0, 0); \
- }
-
-/* Create a memory pool. */
-#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__CREATE_MEMPOOL, \
- pool, rzB, is_zeroed, 0); \
- }
-
-/* Destroy a memory pool. */
-#define VALGRIND_DESTROY_MEMPOOL(pool) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__DESTROY_MEMPOOL, \
- pool, 0, 0, 0); \
- }
-
-/* Associate a piece of memory with a memory pool. */
-#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__MEMPOOL_ALLOC, \
- pool, addr, size, 0); \
- }
-
-/* Disassociate a piece of memory from a memory pool. */
-#define VALGRIND_MEMPOOL_FREE(pool, addr) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__MEMPOOL_FREE, \
- pool, addr, 0, 0); \
- }
-
-/* Mark a piece of memory as being a stack. Returns a stack id. */
-#define VALGRIND_STACK_REGISTER(start, end) \
- ({unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__STACK_REGISTER, \
- start, end, 0, 0); \
- _qzz_res; \
- })
-
-/* Unmark the piece of memory associated with a stack id as being a
- stack. */
-#define VALGRIND_STACK_DEREGISTER(id) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__STACK_DEREGISTER, \
- id, 0, 0, 0); \
- }
-
-/* Change the start and end address of the stack id. */
-#define VALGRIND_STACK_CHANGE(id, start, end) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__STACK_CHANGE, \
- id, start, end, 0); \
- }
-
-#endif /* __VALGRIND_H */
diff --git a/src/xgetopt.c b/src/xgetopt.c
deleted file mode 100644
index 73694ada..00000000
--- a/src/xgetopt.c
+++ /dev/null
@@ -1,222 +0,0 @@
-// XGetopt.cpp Version 1.2
-//
-// Author: Hans Dietrich
-// hdietrich2@hotmail.com
-//
-// Description:
-// XGetopt.cpp implements getopt(), a function to parse command lines.
-//
-// History
-// Version 1.2 - 2003 May 17
-// - Added Unicode support
-//
-// Version 1.1 - 2002 March 10
-// - Added example to XGetopt.cpp module header
-//
-// This software is released into the public domain.
-// You are free to use it in any way you like.
-//
-// This software is provided "as is" with no expressed
-// or implied warranty. I accept no liability for any
-// damage or loss of business that this software may cause.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// if you are using precompiled headers then include this line:
-//#include "stdafx.h"
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// if you are not using precompiled headers then include these lines:
-#include <windows.h>
-#include <stdio.h>
-#include <tchar.h>
-///////////////////////////////////////////////////////////////////////////////
-
-
-#include "XGetopt.h"
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// X G e t o p t . c p p
-//
-//
-// NAME
-// getopt -- parse command line options
-//
-// SYNOPSIS
-// int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
-//
-// extern TCHAR *optarg;
-// extern int optind;
-//
-// DESCRIPTION
-// The getopt() function parses the command line arguments. Its
-// arguments argc and argv are the argument count and array as
-// passed into the application on program invocation. In the case
-// of Visual C++ programs, argc and argv are available via the
-// variables __argc and __argv (double underscores), respectively.
-// getopt returns the next option letter in argv that matches a
-// letter in optstring. (Note: Unicode programs should use
-// __targv instead of __argv. Also, all character and string
-// literals should be enclosed in _T( ) ).
-//
-// optstring is a string of recognized option letters; if a letter
-// is followed by a colon, the option is expected to have an argument
-// that may or may not be separated from it by white space. optarg
-// is set to point to the start of the option argument on return from
-// getopt.
-//
-// Option letters may be combined, e.g., "-ab" is equivalent to
-// "-a -b". Option letters are case sensitive.
-//
-// getopt places in the external variable optind the argv index
-// of the next argument to be processed. optind is initialized
-// to 0 before the first call to getopt.
-//
-// When all options have been processed (i.e., up to the first
-// non-option argument), getopt returns EOF, optarg will point
-// to the argument, and optind will be set to the argv index of
-// the argument. If there are no non-option arguments, optarg
-// will be set to NULL.
-//
-// The special option "--" may be used to delimit the end of the
-// options; EOF will be returned, and "--" (and everything after it)
-// will be skipped.
-//
-// RETURN VALUE
-// For option letters contained in the string optstring, getopt
-// will return the option letter. getopt returns a question mark (?)
-// when it encounters an option letter not included in optstring.
-// EOF is returned when processing is finished.
-//
-// BUGS
-// 1) Long options are not supported.
-// 2) The GNU double-colon extension is not supported.
-// 3) The environment variable POSIXLY_CORRECT is not supported.
-// 4) The + syntax is not supported.
-// 5) The automatic permutation of arguments is not supported.
-// 6) This implementation of getopt() returns EOF if an error is
-// encountered, instead of -1 as the latest standard requires.
-//
-// EXAMPLE
-// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[])
-// {
-// int c;
-//
-// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
-// {
-// switch (c)
-// {
-// case _T('a'):
-// TRACE(_T("option a\n"));
-// //
-// // set some flag here
-// //
-// break;
-//
-// case _T('B'):
-// TRACE( _T("option B\n"));
-// //
-// // set some other flag here
-// //
-// break;
-//
-// case _T('n'):
-// TRACE(_T("option n: value=%d\n"), atoi(optarg));
-// //
-// // do something with value here
-// //
-// break;
-//
-// case _T('?'):
-// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
-// return FALSE;
-// break;
-//
-// default:
-// TRACE(_T("WARNING: no handler for option %c\n"), c);
-// return FALSE;
-// break;
-// }
-// }
-// //
-// // check for non-option args here
-// //
-// return TRUE;
-// }
-//
-///////////////////////////////////////////////////////////////////////////////
-
-TCHAR *optarg; // global argument pointer
-int optind = 0; // global argv index
-
-int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
-{
- static TCHAR *next = NULL;
- TCHAR c;
- TCHAR *cp = NULL;
-
- if (optind == 0)
- next = NULL;
-
- optarg = NULL;
-
- if (next == NULL || *next == _T('\0'))
- {
- if (optind == 0)
- optind++;
-
- if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0'))
- {
- optarg = NULL;
- if (optind < argc)
- optarg = argv[optind];
- return EOF;
- }
-
- if (_tcscmp(argv[optind], _T("--")) == 0)
- {
- optind++;
- optarg = NULL;
- if (optind < argc)
- optarg = argv[optind];
- return EOF;
- }
-
- next = argv[optind];
- next++; // skip past -
- optind++;
- }
-
- c = *next++;
- cp = _tcschr(optstring, c);
-
- if (cp == NULL || c == _T(':'))
- return _T('?');
-
- cp++;
- if (*cp == _T(':'))
- {
- if (*next != _T('\0'))
- {
- optarg = next;
- next = NULL;
- }
- else if (optind < argc)
- {
- optarg = argv[optind];
- optind++;
- }
- else
- {
- return _T('?');
- }
- }
-
- return c;
-}