Merge branch 'release/1.2.11'
diff --git a/.gitignore b/.gitignore
index 00eb13f..688cc3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@
#
# they aren't going into version control, but shouldn't be
# completely ignored. I'm removing the mods here.
+#
+docs/
+html/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee79fa8..93d3b44 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,35 +4,78 @@
set(PROJECT_MAJOR_VERSION 1)
set(PROJECT_MINOR_VERSION 2)
set(PROJECT_PATCH_VERSION 10)
+set(PROJECT_VERSION ${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}.${PROJECT_PATCH_VERSION})
-#add_definitions(-D_FORTIFY_SOURCE=2)
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPROJECT_VERSION=\"${PROJECT_VERSION}\" -Wall")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -ggdb3")
-set (PROJECT_VERSION ${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}.${PROJECT_PATCH_VERSION})
-set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
+SET(CMAKE_BUILD_TYPE Release CACHE STRING "default to Release")
+
+# will use later for htexpress API
+# add_executable(lambda-pp lambda-pp.c)
+
+# -DEVHTP_DISABLE_SSL:STRING=ON
+OPTION(EVHTP_DISABLE_SSL "Disable ssl support" OFF)
+
+# -DEVHTP_DISABLE_EVTHR:STRING=ON
+OPTION(EVHTP_DISABLE_EVTHR "Disable evthread support" OFF)
+
+# -DEVHTP_DISABLE_REGEX:STRING=ON
+OPTION(EVHTP_DISABLE_REGEX "Disable regex support" OFF)
+
+# -DEVHTP_BUILD_SHARED:STRING=ON
+OPTION(EVHTP_BUILD_SHARED "Build shared library too" OFF)
+
+OPTION(EVHTP_USE_JEMALLOC "Enable jemalloc allocator" OFF)
+OPTION(EVHTP_USE_TCMALLOC "Enable tcmalloc allocator" OFF)
+
+# fun color stuff
+if(NOT WIN32)
+ string(ASCII 27 Esc)
+ set(ColourReset "${Esc}[m")
+ set(ColourBold "${Esc}[1m")
+ set(Red "${Esc}[31m")
+ set(Green "${Esc}[32m")
+ set(Yellow "${Esc}[33m")
+ set(Blue "${Esc}[34m")
+ set(Magenta "${Esc}[35m")
+ set(Cyan "${Esc}[36m")
+ set(White "${Esc}[37m")
+ set(BoldRed "${Esc}[1;31m")
+ set(BoldGreen "${Esc}[1;32m")
+ set(BoldYellow "${Esc}[1;33m")
+ set(BoldBlue "${Esc}[1;34m")
+ set(BoldMagenta "${Esc}[1;35m")
+ set(BoldCyan "${Esc}[1;36m")
+ set(BoldWhite "${Esc}[1;37m")
+endif()
+
+set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
INCLUDE (CheckFunctionExists)
INCLUDE (CheckIncludeFiles)
INCLUDE (CheckTypeSize)
INCLUDE (CheckCCompilerFlag)
INCLUDE (TestBigEndian)
-INCLUDE (UseDebugSymbols)
-
-CHECK_FUNCTION_EXISTS(memcmp HAVE_MEMCMP)
CHECK_FUNCTION_EXISTS(strndup HAVE_STRNDUP)
CHECK_FUNCTION_EXISTS(strnlen HAVE_STRNLEN)
-CHECK_INCLUDE_FILES(alloca.h HAVE_ALLOCA_H)
-CHECK_INCLUDE_FILES(strings.h HAVE_STRINGS_H)
-CHECK_INCLUDE_FILES(string.h HAVE_STRING_H)
-CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H)
-CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H)
+
+if (EVHTP_THR_SHARED_PIPE)
+ add_definitions(-DEVTHR_SHARED_PIPE)
+endif()
+
+
+CHECK_INCLUDE_FILES(strings.h HAVE_STRINGS_H)
+CHECK_INCLUDE_FILES(string.h HAVE_STRING_H)
+CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H)
+CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H)
CHECK_INCLUDE_FILES(sys/times.h HAVE_SYS_TIMES_H)
-CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H)
-CHECK_INCLUDE_FILES(memory.h HAVE_MEMORY_H)
-CHECK_INCLUDE_FILES(stdarg.h HAVE_STDARG_PROTOTYPES)
-CHECK_INCLUDE_FILES(sys/tree.h HAVE_SYS_TREE)
+CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H)
+CHECK_INCLUDE_FILES(stdarg.h HAVE_STDARG_PROTOTYPES)
+CHECK_INCLUDE_FILES(sys/tree.h HAVE_SYS_TREE)
CHECK_INCLUDE_FILES(sys/queue.h HAVE_SYS_QUEUE)
-CHECK_INCLUDE_FILES(sys/un.h HAVE_SYS_UN)
+CHECK_INCLUDE_FILES(sys/un.h HAVE_SYS_UN)
CHECK_TYPE_SIZE("int" SIZEOF_INT)
CHECK_TYPE_SIZE("long" SIZEOF_LONG)
@@ -48,70 +91,50 @@
endif()
if (EVHTP_HAS_VISIBILITY_HIDDEN)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
endif()
if (NOT HAVE_SYS_TREE)
- CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/compat/sys/tree.h.in ${CMAKE_CURRENT_BINARY_DIR}/compat/sys/tree.h)
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/compat/sys/tree.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/compat/sys/tree.h)
endif(NOT HAVE_SYS_TREE)
if (NOT HAVE_SYS_QUEUE)
- CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/compat/sys/queue.h.in ${CMAKE_CURRENT_BINARY_DIR}/compat/sys/queue.h)
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/compat/sys/queue.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/compat/sys/queue.h)
endif(NOT HAVE_SYS_QUEUE)
if (NOT HAVE_STRNDUP)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_STRNDUP")
-endif(NOT HAVE_STRNDUP)
+ add_definitions(-DNO_STRNDUP)
+endif()
if (NOT HAVE_STRNLEN)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_STRNLEN")
-endif(NOT HAVE_STRNLEN)
+ add_definitions(-DNO_STRNLEN)
+endif()
if (NOT HAVE_SYS_UN)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_SYS_UN")
+ add_definitions(-DNO_SYS_UN)
endif(NOT HAVE_SYS_UN)
if (HOST_BIG_ENDIAN)
- add_definitions(-DHOST_BIG_ENDIAN)
+ add_definitions(-DHOST_BIG_ENDIAN)
endif()
# Test 32/64 bits
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
- add_definitions(-DEVHTP_SYS_ARCH=64)
+ add_definitions(-DEVHTP_SYS_ARCH=64)
elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
- add_definitions(-DEVHTP_SYS_ARCH=32)
+ add_definitions(-DEVHTP_SYS_ARCH=32)
else()
message(ERROR "Unable to determine architecture")
endif()
-# -DEVHTP_DISABLE_SSL:STRING=ON
-OPTION(EVHTP_DISABLE_SSL "Disable ssl support" OFF)
-
-# -DEVHTP_DISABLE_EVTHR:STRING=ON
-OPTION(EVHTP_DISABLE_EVTHR "Disable evthread support" OFF)
-
-# -DEVHTP_DISABLE_REGEX:STRING=ON
-OPTION(EVHTP_DISABLE_REGEX "Disable regex support" OFF)
-
-# -DEVHTP_BUILD_SHARED:STRING=ON
-OPTION(EVHTP_BUILD_SHARED "Build shared library too" OFF)
-
-# -DEVHTP_USE_DEFER_ACCEPT:STRING=ON
-OPTION(EVHTP_USE_DEFER_ACCEPT "Enable TCP_DEFER_ACCEPT" OFF)
-
if (EVHTP_USE_DEFER_ACCEPT)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_DEFER_ACCEPT")
+ add_definitions(-DUSE_DEFER_ACCEPT)
endif(EVHTP_USE_DEFER_ACCEPT)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
-include(BaseConfig)
-
-message(STATUS "Build Type : ${CMAKE_BUILD_TYPE}")
-message(STATUS "std Debug CFLAGS : ${CMAKE_C_FLAGS_DEBUG}")
-message(STATUS "Std Release CFLAGS : ${CMAKE_C_FLAGS_RELEASE}")
-message(STATUS "Std ReleaseWDebug CFLAGS : ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
-
find_package(LibEvent REQUIRED)
if (NOT LIBEVENT_OPENSSL_LIBRARY)
@@ -129,7 +152,7 @@
endif()
if (NOT OPENSSL_FOUND)
- message(WARN"Unable to find OpenSSL, will continue, but without the support")
+ message(STATUS "${Yellow}Unable to find libssl.. Disabling SSL support ${ColourReset}")
set (EVHTP_DISABLE_SSL ON)
set (OPENSSL_CRYPTO_LIBRARY "")
@@ -139,12 +162,15 @@
elseif(APPLE)
# darwin based hosts have deprecated normal openssl functions, which is
# annoying to see warnings, for now, just ignore them.
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
+ add_definitions(-Wno-deprecated-declarations)
endif()
if (NOT EVHTP_DISABLE_REGEX)
if (NOT HAS_SYS_ONIG)
- CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/oniguruma/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/oniguruma/config.h)
+ message(STATUS "${Blue}Using the built-in onigurma source.${ColourReset}")
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/oniguruma/config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/oniguruma/config.h)
+
set(ONIG_SOURCES
oniguruma/regerror.c
oniguruma/regparse.c
@@ -189,9 +215,11 @@
oniguruma/enc/gb18030.c
oniguruma/enc/koi8_r.c
oniguruma/enc/cp1251.c)
+
set (ONIG_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/oniguruma;${CMAKE_CURRENT_SOURCE_DIR}/oniguruma)
else()
- message("-- Using system libonig")
+ message(STATUS "${YELLOW}Using the system-wide version of oniguruma${ColourReset}")
+
set(ONIG_SOURCES "")
set(ONIG_LIBS ${HAS_SYS_ONIG})
set(ONIG_INCLUDE_DIR "")
@@ -203,9 +231,8 @@
endif()
include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/compat
- ${CMAKE_CURRENT_SOURCE_DIR}/htparse
- ${CMAKE_CURRENT_SOURCE_DIR}/evthr
${CMAKE_CURRENT_SOURCE_DIR}
${ONIG_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
@@ -228,16 +255,24 @@
set (EVHTP_DISABLE_SSL ON)
endif(NOT ${LIBEVENT_OPENSSL_FOUND})
-set(LIBEVHTP_SOURCES evhtp.c evhtp_numtoa.c htparse/htparse.c)
+set(LIBEVHTP_SOURCES evhtp.c evhtp_numtoa.c htparse.c)
+
+if (EVHTP_USE_JEMALLOC)
+ set(LIBEVHTP_EXTERNAL_LIBS ${LIBEVHTP_EXTERNAL_LIBS} jemalloc)
+endif()
+
+if (EVHTP_USE_TCMALLOC)
+ set(LIBEVHTP_EXTERNAL_LIBS ${LIBEVHTP_EXTERNAL_LIBS} tcmalloc)
+endif()
+
if (NOT EVHTP_DISABLE_EVTHR)
set (LIBEVHTP_EXTERNAL_LIBS ${LIBEVHTP_EXTERNAL_LIBS} pthread)
- set (LIBEVHTP_SOURCES ${LIBEVHTP_SOURCES} evthr/evthr.c)
+ set (LIBEVHTP_SOURCES ${LIBEVHTP_SOURCES} evthr.c)
endif(NOT EVHTP_DISABLE_EVTHR)
IF (WIN32)
- ADD_DEFINITIONS(-DWIN32)
- ADD_DEFINITIONS(-march=i486)
+ add_definitions(-DWIN32 -march=i486)
find_library (LIB_WS32 ws2_32)
set (SYS_LIBS ${SYS_LIBS} ${LIB_WS32})
ELSE ()
@@ -252,8 +287,6 @@
endif()
ENDIF (WIN32)
-add_custom_target(examples)
-
if (EVHTP_BUILD_SHARED)
set (EVHTP_LIBTYPE SHARED)
else()
@@ -267,26 +300,12 @@
add_library(evhtp ${EVHTP_LIBTYPE} ${LIBEVHTP_SOURCES} ${ONIG_SOURCES})
target_link_libraries(evhtp ${LIBEVHTP_EXTERNAL_LIBS})
-add_executable(test EXCLUDE_FROM_ALL examples/test.c)
-add_executable(test_basic EXCLUDE_FROM_ALL examples/test_basic.c)
-add_executable(test_vhost EXCLUDE_FROM_ALL examples/test_vhost.c)
-add_executable(test_client EXCLUDE_FROM_ALL examples/test_client.c)
-add_executable(test_query EXCLUDE_FROM_ALL examples/test_query.c)
-
-strip_debug_symbols(test_query)
-
-if (NOT EVHTP_DISABLE_EVTHR)
- add_executable(test_proxy EXCLUDE_FROM_ALL examples/test_proxy.c)
- target_link_libraries(test_proxy evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+if (EVHTP_BUILD_SHARED)
+ set_target_properties(evhtp PROPERTIES SOVERSION "${PROJECT_VERSION}")
endif()
-target_link_libraries(test evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
-target_link_libraries(test_basic evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
-target_link_libraries(test_vhost evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
-target_link_libraries(test_client evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
-target_link_libraries(test_query evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
-
-add_dependencies(examples test test_basic test_vhost test_client test_proxy test_query)
+add_subdirectory(tools)
+add_subdirectory(examples)
if (NOT LIB_INSTALL_DIR)
set (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib")
@@ -297,22 +316,25 @@
endif()
install (TARGETS evhtp DESTINATION ${LIB_INSTALL_DIR})
-install (FILES evhtp.h DESTINATION ${INCLUDE_INSTALL_DIR})
-install (FILES htparse/htparse.h DESTINATION ${INCLUDE_INSTALL_DIR})
-install (FILES ${CMAKE_CURRENT_BINARY_DIR}/evhtp-config.h DESTINATION ${INCLUDE_INSTALL_DIR})
+install (FILES evhtp.h DESTINATION ${INCLUDE_INSTALL_DIR}/evhtp)
+install (FILES htparse.h DESTINATION ${INCLUDE_INSTALL_DIR}/evhtp)
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/evhtp-config.h DESTINATION ${INCLUDE_INSTALL_DIR}/evhtp)
if (NOT EVHTP_DISABLE_EVTHR)
- install (FILES evthr/evthr.h DESTINATION ${INCLUDE_INSTALL_DIR})
+ install (FILES evthr.h DESTINATION ${INCLUDE_INSTALL_DIR}/evhtp)
endif()
-# oniguruma/onigposix.h
-
if (NOT EVHTP_DISABLE_REGEX)
if (NOT HAS_SYS_ONIG)
- install (FILES oniguruma/onigposix.h DESTINATION ${INCLUDE_INSTALL_DIR})
+ install (FILES oniguruma/onigposix.h DESTINATION ${INCLUDE_INSTALL_DIR}/evhtp)
endif()
endif()
+if (NOT HAVE_SYS_QUEUE)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/compat/sys/queue.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/evhtp/sys)
+endif()
+
IF (WIN32)
install (FILES compat/sys/queue.h DESTINATION ${INCLUDE_INSTALL_DIR}/sys)
install (FILES oniguruma/onigposix.h DESTINATION ${INCLUDE_INSTALL_DIR})
@@ -322,28 +344,52 @@
${CMAKE_CURRENT_SOURCE_DIR}/evhtp.pc.in
${CMAKE_CURRENT_BINARY_DIR}/evhtp.pc @ONLY)
-message(STATUS "CMAKE_BUILD_TYPE : " ${CMAKE_BUILD_TYPE})
-message(STATUS "CMAKE_BINARY_DIR : " ${CMAKE_BINARY_DIR})
-message(STATUS "CMAKE_CURRENT_BINARY_DIR : " ${CMAKE_CURRENT_BINARY_DIR})
-message(STATUS "CMAKE_SOURCE_DIR : " ${CMAKE_SOURCE_DIR})
-message(STATUS "CMAKE_CURRENT_SOURCE_DIR : " ${CMAKE_CURRENT_SOURCE_DIR})
-message(STATUS "PROJECT_BINARY_DIR : " ${PROJECT_BINARY_DIR})
-message(STATUS "PROJECT_SOURCE_DIR : " ${PROJECT_SOURCE_DIR})
-message(STATUS "CMAKE_MODULE_PATH : " ${CMAKE_MODULE_PATH})
-message(STATUS "CMAKE_COMMAND : " ${CMAKE_COMMAND})
-message(STATUS "CMAKE_ROOT : " ${CMAKE_ROOT})
-message(STATUS "CMAKE_SYSTEM : " ${CMAKE_SYSTEM})
-message(STATUS "CMAKE_SYSTEM_NAME : " ${CMAKE_SYSTEM_NAME})
-message(STATUS "CMAKE_SYSTEM_VERSION : " ${CMAKE_SYSTEM_VERSION})
-message(STATUS "CMAKE_SYSTEM_PROCESSOR : " ${CMAKE_SYSTEM_PROCESSOR})
-message(STATUS "CMAKE_C_FLAGS : " ${CMAKE_C_FLAGS})
-message(STATUS "CMAKE_CXX_FLAGS : " ${CMAKE_CXX_FLAGS})
-message(STATUS "CMAKE_C_COMPILER : " ${CMAKE_C_COMPILER})
-message(STATUS "CMAKE_CXX_COMPILER : " ${CMAKE_CXX_COMPILER})
-message(STATUS "CMAKE_AR : " ${CMAKE_AR})
-message(STATUS "CMAKE_RANLIB : " ${CMAKE_RANLIB})
-message(STATUS "CMAKE_C_FLAGS_DEBUG : " ${CMAKE_C_FLAGS_DEBUG})
-message(STATUS "CMAKE_C_FLAGS_RELEASE : " ${CMAKE_C_FLAGS_RELEASE})
-message(STATUS "CMAKE_C_FLAGS_RELWDBGIFO : " ${CMAKE_C_FLAGS_RELWITHDEBINFO})
-message(STATUS "CMAKE_INSTALL_PREFIX : " ${CMAKE_INSTALL_PREFIX})
-message(STATUS "Version : " ${PROJECT_VERSION})
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/evhtp.pc"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
+
+# add_definitions() calls do not show up in the C_FLAGS var
+# it is instead a property of COMPILE_DEFINITIONS.
+#
+# so we fetch the property into the variable CDEFS, iterate over each entry,
+# append it to a list, and finally replace ";" separators to -D to mimic a CFLAG
+
+get_property(CDEFS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
+
+foreach(CDEF ${CDEFS})
+ list(APPEND CFLAG_LIST ${CDEF})
+endforeach()
+
+string(REPLACE ";" " -D" CFLAG_DEFS "${CFLAG_LIST}")
+
+message("")
+message(STATUS "${BoldBlue}EVHTP_VERSION${ColourReset} : ${BoldGreen} ${PROJECT_VERSION}${ColourReset}")
+message(STATUS "${BoldBlue}EVHTP_DISABLE_SSL${ColourReset} : ${BoldGreen} ${EVHTP_DISABLE_SSL}${ColourReset}")
+message(STATUS "${BoldBlue}EVHTP_DISABLE_EVTHR${ColourReset} : ${BoldGreen} ${EVHTP_DISABLE_EVTHR}${ColourReset}")
+message(STATUS "${BoldBlue}EVHTP_DISABLE_REGEX${ColourReset} : ${BoldGreen} ${EVHTP_DISABLE_REGEX}${ColourReset}")
+message(STATUS "${BoldBlue}EVHTP_BUILD_SHARED${ColourReset} : ${BoldGreen} ${EVHTP_BUILD_SHARED}${ColourReset}")
+message(STATUS "${BoldBlue}EVHTP_USE_JEMALLOC${ColourReset} : ${BoldGreen} ${EVHTP_USE_JEMALLOC}${ColourReset}")
+message(STATUS "${BoldBlue}EVHTP_USE_TCMALLOC${ColourReset} : ${BoldGreen} ${EVHTP_USE_TCMALLOC}${ColourReset}")
+message("")
+message(STATUS "${Blue}CMAKE_BUILD_TYPE${ColourReset} : " ${BoldRed}${CMAKE_BUILD_TYPE}${ColourReset})
+message(STATUS "${Blue}CMAKE_INSTALL_PREFIX${ColourReset} : " ${BoldMagenta}${CMAKE_INSTALL_PREFIX}${ColourReset})
+message(STATUS "${Blue}CMAKE_BINARY_DIR${ColourReset} : " ${CMAKE_BINARY_DIR})
+message(STATUS "${Blue}CMAKE_CURRENT_BINARY_DIR${ColourReset} : " ${CMAKE_CURRENT_BINARY_DIR})
+message(STATUS "${Blue}CMAKE_SOURCE_DIR${ColourReset} : " ${CMAKE_SOURCE_DIR})
+message(STATUS "${Blue}CMAKE_CURRENT_SOURCE_DIR${ColourReset} : " ${CMAKE_CURRENT_SOURCE_DIR})
+message(STATUS "${Blue}PROJECT_BINARY_DIR${ColourReset} : " ${PROJECT_BINARY_DIR})
+message(STATUS "${Blue}PROJECT_SOURCE_DIR${ColourReset} : " ${PROJECT_SOURCE_DIR})
+message(STATUS "${Blue}CMAKE_MODULE_PATH${ColourReset} : " ${CMAKE_MODULE_PATH})
+message(STATUS "${Blue}CMAKE_SYSTEM_NAME${ColourReset} : " ${CMAKE_SYSTEM_NAME})
+message(STATUS "${Blue}CMAKE_SYSTEM_VERSION${ColourReset} : " ${CMAKE_SYSTEM_VERSION})
+message(STATUS "${Blue}CMAKE_C_COMPILER${ColourReset} : " ${CMAKE_C_COMPILER})
+message(STATUS "${Blue}CMAKE_AR${ColourReset} : " ${CMAKE_AR})
+message(STATUS "${Blue}CMAKE_RANLIB${ColourReset} : " ${CMAKE_RANLIB})
+message(STATUS "${Blue}CFLAGS${ColourReset} : -D${CFLAG_DEFS} ${CMAKE_C_FLAGS}")
+
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+ message(" ${CMAKE_C_FLAGS_DEBUG}")
+else(CMAKE_BUILD_TYPE MATCHES Release)
+ message(" ${CMAKE_C_FLAGS_RELEASE}")
+endif()
+
+message("")
diff --git a/CMakeModules/AddOptions.cmake b/CMakeModules/AddOptions.cmake
deleted file mode 100644
index 3255d90..0000000
--- a/CMakeModules/AddOptions.cmake
+++ /dev/null
@@ -1,102 +0,0 @@
-# - Add options without repeating them on the command line
-#
-# Synopsis:
-#
-# add_options (lang build opts)
-#
-# where:
-#
-# lang Name of the language whose compiler should receive the
-# options, e.g. CXX. If a comma-separated list is received
-# then the option is added for all those languages. Use the
-# special value ALL_LANGUAGES for these languages: CXX, C
-# and Fortran
-#
-# build Kind of build to which this options should apply,
-# such as DEBUG and RELEASE. This can also be a comma-
-# separated list. Use the special value ALL_BUILDS to apply
-# to all builds.
-#
-# opts List of options to add. Each should be quoted.
-#
-# Example:
-#
-# add_options (CXX RELEASE "-O3" "-DNDEBUG" "-Wall")
-
-function (add_options langs builds)
- # special handling of empty language specification
- if ("${langs}" STREQUAL "ALL_LANGUAGES")
- set (langs CXX C Fortran)
- endif ("${langs}" STREQUAL "ALL_LANGUAGES")
- foreach (lang IN LISTS langs)
- # prepend underscore if necessary
- foreach (build IN LISTS builds)
- if (NOT ("${build}" STREQUAL "ALL_BUILDS"))
- set (_bld "_${build}")
- string (TOUPPER "${_bld}" _bld)
- else (NOT ("${build}" STREQUAL "ALL_BUILDS"))
- set (_bld "")
- endif (NOT ("${build}" STREQUAL "ALL_BUILDS"))
- # if we want everything in the "global" flag, then simply
- # ignore the build type here and go add everything to that one
- if (CMAKE_NOT_USING_CONFIG_FLAGS)
- set (_bld "")
- endif ()
- foreach (_opt IN LISTS ARGN)
- set (_var "CMAKE_${lang}_FLAGS${_bld}")
- #message (STATUS "Adding \"${_opt}\" to \${${_var}}")
- # remove it first
- string (REPLACE "${_opt}" "" _without "${${_var}}")
- string (STRIP "${_without}" _without)
- # we need to strip this one as well, so they are comparable
- string (STRIP "${${_var}}" _stripped)
- # if it wasn't there, then add it at the end
- if ("${_without}" STREQUAL "${_stripped}")
- # don't add any extra spaces if no options yet are set
- if (NOT ${_stripped} STREQUAL "")
- set (${_var} "${_stripped} ${_opt}")
- else (NOT ${_stripped} STREQUAL "")
- set (${_var} "${_opt}")
- endif (NOT ${_stripped} STREQUAL "")
- set (${_var} "${${_var}}" PARENT_SCOPE)
- endif ("${_without}" STREQUAL "${_stripped}")
- endforeach (_opt)
- endforeach (build)
- endforeach (lang)
-endfunction (add_options lang build)
-
-# set varname to flag unless user has specified something that matches regex
-function (set_default_option lang varname flag regex)
- # lang is either C, CXX or Fortran
- if ("${lang}" STREQUAL "Fortran")
- set (letter "F")
- else ()
- set (letter "${lang}")
- endif ()
- string (TOUPPER "${CMAKE_BUILD_TYPE}" _build)
- if ((NOT ("$ENV{${letter}FLAGS}" MATCHES "${regex}"))
- AND (NOT ("${CMAKE_${lang}_FLAGS}" MATCHES "${regex}"))
- AND (NOT ("${CMAKE_${lang}_FLAGS_${_build}}" MATCHES "${regex}")))
- set (${varname} ${flag} PARENT_SCOPE)
- else ()
- set (${varname} PARENT_SCOPE)
- endif ()
-endfunction (set_default_option)
-
-# clear default options as a proxy for not using any default options
-# at all. there is one *huge* problem with this: CMake runs the platform
-# initialization before executing any line at all in the project and
-# there seems to be no way to disable that behaviour, so we cannot really
-# distinguish between a platform default and something that the user has
-# passed on the command line. the best thing we can do is to all user-
-# defined setting if they are something other than the platform default.
-macro (no_default_options)
- foreach (lang IN ITEMS C CXX Fortran)
- foreach (build IN ITEMS DEBUG RELEASE MINSIZEREL RELWITHDEBINFO)
- if ("${CMAKE_${lang}_FLAGS_${build}}" STREQUAL "${CMAKE_${lang}_FLAGS_${build}_INIT}")
- # for some strange reason we cannot clear this flag, only set it to empty
- set (CMAKE_${lang}_FLAGS_${build} "")
- endif ()
- endforeach (build)
- endforeach (lang)
-endmacro (no_default_options)
diff --git a/CMakeModules/BaseConfig.cmake b/CMakeModules/BaseConfig.cmake
deleted file mode 100644
index 2f30867..0000000
--- a/CMakeModules/BaseConfig.cmake
+++ /dev/null
@@ -1,31 +0,0 @@
-if (CMAKE_COMPILER_IS_GNUCC)
-
- set(RSN_BASE_C_FLAGS "-Wall -fno-strict-aliasing")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RSN_BASE_C_FLAGS} -DPROJECT_VERSION=\"${PROJECT_VERSION}\"")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${RSN_BASE_C_FLAGS} -ggdb")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RSN_BASE_C_FLAGS}")
-
- if(APPLE)
- # Newer versions of OSX will spew a bunch of warnings about deprecated ssl functions,
- # this should be addressed at some point in time, but for now, just ignore them.
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_BSD_SOURCE -Wno-deprecated-declarations")
- elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
- # XXX Should I set POSIX_C_SOURCE?
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_BSD_SOURCE")
- elseif(UNIX)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112")
- endif(APPLE)
-
-endif(CMAKE_COMPILER_IS_GNUCC)
-
-if (EVHTP_DISABLE_EVTHR)
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEVHTP_DISABLE_EVTHR")
-endif(EVHTP_DISABLE_EVTHR)
-
-if (EVHTP_DISABLE_SSL)
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEVHTP_DISABLE_SSL")
-endif(EVHTP_DISABLE_SSL)
-
-if (NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Release)
-endif(NOT CMAKE_BUILD_TYPE)
diff --git a/CMakeModules/UseCompVer.cmake b/CMakeModules/UseCompVer.cmake
deleted file mode 100644
index e8ac099..0000000
--- a/CMakeModules/UseCompVer.cmake
+++ /dev/null
@@ -1,108 +0,0 @@
-# - Get compiler version
-
-# probe the GCC version, returns empty string if GCC is not compiler
-function (get_gcc_version language ver_name)
- if(CMAKE_${language}_COMPILER_ID STREQUAL GNU)
- # exec_program is deprecated, but execute_process does't work :-(
- exec_program (${CMAKE_${language}_COMPILER}
- ARGS ${CMAKE_${language}_COMPILER_ARG1} -dumpversion
- OUTPUT_VARIABLE _version
- )
- set (${ver_name} ${_version} PARENT_SCOPE)
- else (CMAKE_${language}_COMPILER_ID STREQUAL GNU)
- set (${ver_name} "" PARENT_SCOPE)
- endif (CMAKE_${language}_COMPILER_ID STREQUAL GNU)
-endfunction (get_gcc_version ver_name)
-
-# less reliable, but includes the patch number
-function (get_gcc_patch language ver_name)
- if(CMAKE_${language}_COMPILER_ID STREQUAL GNU)
- # exec_program is deprecated, but execute_process does't work :-(
- exec_program (${CMAKE_${language}_COMPILER}
- ARGS ${CMAKE_${language}_COMPILER_ARG1} --version
- OUTPUT_VARIABLE _version
- )
- # split multi-line string into list
- if (WIN32)
- string (REPLACE "\r\n" ";" _version "${_version}")
- else (WIN32)
- string (REPLACE "\n" ";" _version "${_version}")
- endif (WIN32)
- # only keep first line
- list (GET _version 0 _version)
- # extract version number from it (this is the fragile part)
- string (REGEX REPLACE "^[^\\(]+(\\([^\\)]*\\))?[\ \t]*([0-9]+\\.[0-9]+\\.[0-9]+)(.*\\(.*\\))?" "\\2" _version "${_version}")
- # return this to the caller
- set (${ver_name} ${_version} PARENT_SCOPE)
- else (CMAKE_${language}_COMPILER_ID STREQUAL GNU)
- set (${ver_name} "" PARENT_SCOPE)
- endif (CMAKE_${language}_COMPILER_ID STREQUAL GNU)
-endfunction (get_gcc_patch language ver_name)
-
-function (compiler_info)
- if (CMAKE_COMPILER_IS_GNUCXX)
- get_gcc_patch (CXX version)
- message (STATUS "GNU C++ compiler version: ${version}")
- endif (CMAKE_COMPILER_IS_GNUCXX)
-endfunction (compiler_info)
-
-function (get_ld_version ver_name)
- # run linker to get the version number. interestingly, this option works
- # (for our purposes) on all major platforms (Linux, Mac OS X and Windows);
- # it returns the program version although it may have ended in error
- exec_program (${CMAKE_LINKER}
- ARGS "-v"
- OUTPUT_VARIABLE _version
- )
-
- # keep only first line, even on Mac OS X there is no line end
- list (GET _version 0 _version)
-
- # format of the version string is platform-specific
- if (NOT WIN32)
- if (APPLE)
- string (REGEX REPLACE ".*, from Apple (.*\)" "\\1" _version "${_version}")
- else (APPLE)
- # assuming some GNU toolchain now
- string (REGEX REPLACE "GNU ([a-zA-Z0-9_]*) (version|\\(.*\\)) ([^\\ ]*).*" "\\1 \\3" _version "${_version}")
- endif (APPLE)
- endif (NOT WIN32)
-
- # return the string to the caller
- set (${ver_name} "${_version}" PARENT_SCOPE)
-endfunction (get_ld_version ver_name)
-
-function (linker_info)
- get_ld_version (version)
- message (STATUS "Linker: ${version}")
-endfunction (linker_info)
-
-# sets CXX_COMPAT_GCC if we have either GCC or Clang
-macro (is_compiler_gcc_compatible)
- # is the C++ compiler clang++?
- string (TOUPPER "${CMAKE_CXX_COMPILER_ID}" _comp_id)
- if (_comp_id MATCHES "CLANG")
- set (CMAKE_COMPILER_IS_CLANGXX TRUE)
- else ()
- set (CMAKE_COMPILER_IS_CLANGXX FALSE)
- endif ()
- # is the C++ compiler g++ or clang++?
- if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX)
- set (CXX_COMPAT_GCC TRUE)
- else ()
- set (CXX_COMPAT_GCC FALSE)
- endif ()
- # is the C compiler clang?
- string (TOUPPER "${CMAKE_C_COMPILER_ID}" _comp_id)
- if (_comp_id MATCHES "CLANG")
- set (CMAKE_COMPILER_IS_CLANG TRUE)
- else ()
- set (CMAKE_COMPILER_IS_CLANG FALSE)
- endif ()
- # is the C compiler gcc or clang?
- if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
- set (C_COMPAT_GCC TRUE)
- else ()
- set (C_COMPAT_GCC FALSE)
- endif ()
-endmacro (is_compiler_gcc_compatible)
diff --git a/CMakeModules/UseDebugSymbols.cmake b/CMakeModules/UseDebugSymbols.cmake
deleted file mode 100644
index dbe0a17..0000000
--- a/CMakeModules/UseDebugSymbols.cmake
+++ /dev/null
@@ -1,139 +0,0 @@
-# - Generate debug symbols in a separate file
-#
-# (1) Include this file in your CMakeLists.txt; it will setup everything
-# to compile WITH debug symbols in any case.
-#
-# (2) Run the strip_debug_symbols function on every target that you want
-# to strip.
-
-# Copyright (C) 2012 Uni Research AS
-# This code is licensed under The GNU General Public License v3.0
-
-include (AddOptions)
-include (UseCompVer)
-is_compiler_gcc_compatible ()
-
-# only debugging using the GNU toolchain is supported for now
-if (CXX_COMPAT_GCC)
- # default debug level, if not specified by the user
- set_default_option (CXX _dbg_flag "-ggdb3" "(^|\ )-g")
-
- # add debug symbols to *all* targets, regardless. there WILL come a
- # time when you need to find a bug which only manifests itself in a
- # release target on a production system!
- if (_dbg_flag)
- message (STATUS "Generating debug symbols: ${_dbg_flag}")
- add_options (ALL_LANGUAGES ALL_BUILDS "${_dbg_flag}")
- endif (_dbg_flag)
-
- # extracting the debug info is done by a separate utility in the GNU
- # toolchain. check that this is actually installed.
- message (STATUS "Looking for strip utility")
- if (APPLE)
- # MacOS X has a duo of utilities; we need both
- find_program (OBJCOPY strip)
- find_program (DSYMUTIL dsymutil)
- mark_as_advanced (DSYMUTIL)
- if (NOT DSYMUTIL)
- set (OBJCOPY dsymutil-NOTFOUND)
- endif (NOT DSYMUTIL)
- else (APPLE)
- find_program (OBJCOPY
- objcopy
- ${CYGWIN_INSTALL_PATH}/bin /usr/bin /usr/local/bin
- )
- endif (APPLE)
- mark_as_advanced (OBJCOPY)
- if (OBJCOPY)
- message (STATUS "Looking for strip utility - found")
- else (OBJCOPY)
- message (WARNING "Looking for strip utility - not found")
- endif (OBJCOPY)
-endif ()
-
-# command to separate the debug information from the executable into
-# its own file; this must be called for each target; optionally takes
-# the name of a variable to receive the list of .debug files
-function (strip_debug_symbols targets)
- if (CXX_COMPAT_GCC AND OBJCOPY)
- foreach (target IN LISTS targets)
- # libraries must retain the symbols in order to link to them, but
- # everything can be stripped in an executable
- get_target_property (_kind ${target} TYPE)
-
- # don't strip static libraries
- if ("${_kind}" STREQUAL "STATIC_LIBRARY")
- return ()
- endif ("${_kind}" STREQUAL "STATIC_LIBRARY")
-
- # don't strip public symbols in shared objects
- if ("${_kind}" STREQUAL "EXECUTABLE")
- set (_inst_dir bin)
- set (_strip_args --strip-all --strip-unneeded)
- else ("${_kind}" STREQUAL "EXECUTABLE")
- set(_inst_dir lib)
- set (_strip_args --strip-debug --strip-unneeded)
- endif ("${_kind}" STREQUAL "EXECUTABLE")
-
- # add_custom_command doesn't support generator expressions in the
- # working_directory argument (sic; that's what you get when you do
- # ad hoc programming all the time), so we need to extract the
- # location up front (the location on the other hand should not be
- # used for libraries as it does not include the soversion -- sic
- # again)
- get_target_property (_full ${target} LOCATION)
- get_filename_component (_dir ${_full} PATH)
- if (NOT (("${_dir}" STREQUAL "") OR ("${_dir}" MATCHES ".*/$")))
- set (_dir "${_dir}/")
- endif (NOT (("${_dir}" STREQUAL "") OR ("${_dir}" MATCHES ".*/$")))
- get_filename_component (_name ${_full} NAME_WE)
- get_filename_component (_ext ${_full} EXT)
- # only libraries have soversion property attached
- get_target_property (_target_soversion ${target} SOVERSION)
- get_target_property (_target_version ${target} VERSION)
-
- if (_target_soversion)
- # MacOS X puts the version number before the extension
- if (APPLE)
- set (_target_file_name "${_name}.${_target_version}${_ext}")
- else (APPLE)
- set (_target_file_name "${_name}${_ext}.${_target_version}")
- endif (APPLE)
- else (_target_soversion)
- set (_target_file_name "${_name}${_ext}")
- endif (_target_soversion)
-
- set (_target_file "${_dir}${_target_file_name}")
- # do without generator expressions (which doesn't work everywhere)
- if (APPLE)
- set (_debug_ext ".dSYM")
- add_custom_command (TARGET ${target}
- POST_BUILD
- WORKING_DIRECTORY ${_dir}
- COMMAND ${DSYMUTIL} ARGS --out=${_target_file}${_debug_ext} ${_target_file}
- COMMAND ${OBJCOPY} ARGS -S ${_target_file}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_target_file} ${CMAKE_BINARY_DIR}/install/${_inst_dir}
- VERBATIM)
- else ()
- set (_debug_ext ".debug")
- add_custom_command (TARGET ${target}
- POST_BUILD
- WORKING_DIRECTORY ${_dir}
- COMMAND ${OBJCOPY} ARGS --only-keep-debug ${_target_file} ${_target_file}${_debug_ext}
- COMMAND ${OBJCOPY} ARGS ${_strip_args} ${_target_file}
- COMMAND ${OBJCOPY} ARGS --add-gnu-debuglink=${_target_file_name}${_debug_ext} ${_target_file}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_target_file} ${CMAKE_BINARY_DIR}/install/${_inst_dir}
- VERBATIM)
- endif ()
-
- # add this .debug file to the list
- file (RELATIVE_PATH _this_debug_file "${PROJECT_BINARY_DIR}" "${_target_file}${_debug_ext}")
- set (_debug_files ${_debug_files} ${_this_debug_file})
- endforeach (target)
- # if optional debug list was requested, then copy to output parameter
- if (ARGV1)
- set (${ARGV1} ${_debug_files} PARENT_SCOPE)
- endif (ARGV1)
- endif ()
-endfunction (strip_debug_symbols targets)
-
diff --git a/ChangeLog b/ChangeLog
index 4ffb260..04905b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+v1.2.11
+ o Added missing extern "C"'s to public headers (9a0d250 Mark Ellzey)
+ o CMakeLists cleanup, and pretty display (fc0f5da Mark Ellzey)
+ o Oops, added back find_package() for libevent (9cdae63 Mark Ellzey)
+ o Does image linking work here? (c10690b Mark Ellzey)
+ o [htparse] have each state consume as needed (c34dba5 Mark Ellzey)
+ o [htparse] formatting (4adcc67 Mark Ellzey)
+ o Cleaning up things a bit (e7268d2 Mark Ellzey)
+ o updated (718de1e Mark Ellzey)
+ o Install into <installdir>/include/evhtp/*.h (7065156 Mark Ellzey)
+ o Optimizations / assertions / more safe_Free conversions (511fb19 Mark Ellzey)
+ o Fix test_query tests (2d4c22f Mark Ellzey)
+ o evthr initial shared pipe prototype (72f01f5 Mark Ellzey)
+ o [evthr] shared pipe updates (0251481 Mark Ellzey)
+ o Formatting. (f67f958 Mark Ellzey)
+ o Added EVHTP_THR_SHARED_PIPE option (default ON) (d160452 Mark Ellzey)
+ o formatting, fixes, assertions (b1cef41 Mark Ellzey)
+ o Issue161 : deal with http 1.0 stuff (67ed0bc Mark Ellzey)
+ o update test_basic (3ea2eba Mark Ellzey)
+ o use evhtp_safe_free for authority (50dffb6 Mark Ellzey)
+ o [htparse] keep-alive A_case fix (910137f Mark Ellzey)
+ o sockflags, and more pipeline fixses (9b69ee7 Mark Ellzey)
+ o Might want to make that listener nonblocking (d34a1d0 Mark Ellzey)
+ o Coreent socket() assertion (d2263e0 Mark Ellzey)
+ o htparse optimizations, backlog flag for test.c (9f5a38e Mark Ellzey)
+ o scratch buffers / added test_perf for graphing (95e9ff3 Mark Ellzey)
+ o rm'd ratelimit, added ability to use je/tc malloc (934cf5a Mark Ellzey)
+ o Updating layouts - added lambda-pp code (8aef49d Mark Ellzey)
+ o Cleanup time! (43005ad Mark Ellzey)
+ o formatting (542a701 Mark Ellzey)
+ o default response cb needs to set 0 len (2f1ecab Mark Ellzey)
+ o use elif defined JE... (2682dca Mark Ellzey)
+ o Added evhtp_get_cb (see full commit msg) (cdf5291 Mark Ellzey)
+ o Various fixes / added SOVERSION'ing (73d7ee5 Mark Ellzey)
+ o Move around tc/jemalloc ifdefs, btw tcmalloc is awful. (e456fe0 Mark Ellzey)
+ o build: install evhtp.pc in /usr/lib/pkgconfig (0400ce0 Vincent Bernat)
+ o jfkdlsa (fabe244 Mark Ellzey)
+ o doxygen mod for evhtp.h (3d0e615 Mark Ellzey)
+ o Default to EVHTP_PARSE_QUERY_FLAG_LENIENT for query parsing. (a462fc5 Mark Ellzey Thomas)
+ o (evhtp_make_request): Add request->buffer_out as body if populated. (8bc4ab3 akalend)
+ o Added setsockopt for ipv6 to only use ipv6 null check for ssl via akalend (acfc9dd Mark Ellzey Thomas)
+ o modify str_to_uint64: uint64_t check can never be greater than UINT64_MAX (7d6135c xuhao)
+ o use EVHTP_DISABLE_SSL instead of USE_SSL in header (c884191 Mark Ellzey)
+ o export evhtp_connection_ssl_new via @rosenk, thanks! (c2168be Mark Ellzey)
+
v1.2.10
o client ssl connection added. This requires a SSL_CTX and must be set by the user (439431a StunMan)
o Only export public symbols. (cf66c7c Mark Ellzey)
diff --git a/Doxyfile b/Doxyfile
index 6c5363d..fe9ba04 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,1661 +1,183 @@
-# Doxyfile 1.7.1
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
+OUTPUT_DIRECTORY = ./html/docs/
DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
-PROJECT_NAME = Libevhtp
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER = 0.3.7
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = ./docs/
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
+PROJECT_NAME = Libevhtp
+PROJECT_NUMBER = 1.2.10-dev
CREATE_SUBDIRS = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
-
OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
REPEAT_BRIEF = YES
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
+FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = YES
MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
TAB_SIZE = 8
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
OPTIMIZE_OUTPUT_FOR_C = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
-
OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen to replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
SUBGROUPING = YES
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
+TYPEDEF_HIDES_STRUCT = YES
+EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
+EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespace are hidden.
-
EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = YES
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
SORT_BY_SCOPE_NAME = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
SHOW_USED_FILES = YES
-
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
SHOW_DIRECTORIES = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page. This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
WARN_IF_UNDOCUMENTED = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
WARN_IF_DOC_ERROR = YES
-
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
WARN_NO_PARAMDOC = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = evhtp.c evhtp.h
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
-
+INPUT = evhtp.h
INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
-
-FILE_PATTERNS = *.c \
- *.cc \
- *.cxx \
- *.cpp \
- *.c++ \
- *.d \
- *.java \
- *.ii \
- *.ixx \
- *.ipp \
- *.i++ \
- *.inl \
- *.h \
- *.hh \
- *.hxx \
- *.hpp \
- *.h++ \
- *.idl \
- *.odl \
- *.cs \
- *.php \
- *.php3 \
- *.inc \
- *.m \
- *.mm \
- *.dox \
- *.py \
- *.f90 \
- *.f \
- *.vhd \
- *.vhdl
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
-# from the input.
-
EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
+EXCLUDE_PATTERNS = */.git/* .*.d
EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
+EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output. If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
-
FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
FILTER_SOURCE_FILES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
-
REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code. Otherwise they will link to the documentation.
-
REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
VERBATIM_HEADERS = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
+ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-
HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
HTML_STYLESHEET =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
HTML_ALIGN_MEMBERS = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
-
GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
DISABLE_INDEX = NO
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
ENUM_VALUES_PER_LINE = 4
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-
GENERATE_TREEVIEW = NO
-
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
TREEVIEW_WIDTH = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT = YES
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvances is that it is more difficult to setup
-# and does not have live searching capabilities.
-
-SERVER_BASED_SEARCH = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = YES
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
+GENERATE_LATEX = NO
LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
-
LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-
PAPER_TYPE = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
LATEX_HIDE_INDICES = NO
-
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
+GENERATE_MAN = YES
MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
+PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS
EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
-
SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
-
CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
MSCGEN_PATH =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS = 0
-
-# By default doxygen will write a font called FreeSans.ttf to the output
-# directory and reference it in all dot files that doxygen generates. This
-# font does not include all possible unicode characters however, so when you need
-# these (or just want a differently looking font) you can specify the font name
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
-
-DOT_FONTNAME = FreeSans.ttf
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
+HAVE_DOT = YES
CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
UML_LOOK = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
TEMPLATE_RELATIONS = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH = NO
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
-
+CALL_GRAPH = YES
CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-
GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
DOT_IMAGE_FORMAT = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
DOTFILE_DIRS =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
+DOT_TRANSPARENT = YES
DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
DOT_CLEANUP = YES
+SEARCHENGINE = NO
diff --git a/README.markdown b/README.markdown
index 550b099..f8f6cf2 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,5 +1,5 @@
-# Libevhtp
-*****
+|  | <h1>Libevhtp</h1> |
+| :------------- | -------------: |
This document describes details on using the evhtp API. This document is
probably not very awesome, it's best to look at test.c to see advanced usage.
@@ -104,3 +104,26 @@
cmake -G "MSYS Makefiles" -DCMAKE_INCLUDE_PATH=/mingw/include -DCMAKE_LIBRARY_PATH=/mingw/lib -DCMAKE_INSTALL_PREFIX=/mingw .
make
+
+## Performance stuff
+
+While we never documented any benchmark publically,
+the popular open source project [ZIMG](http://zimg.buaa.us) did a bit of that
+for us.The ZIMG team decided to move away from NGINX to libevhtp for their
+software, and the results were pretty outstanding. Here is a graph showing their
+application under very high load
+
+
+
+The X-axis is the number of connections, while the Y-axis is requests per
+second.
+
+You can read the whole article here: [Architecture Design of an Image Server](http://zimg.buaa.us/documents/Architecture_Design_of_Image_Server/)
+
+Slightly outdated (Now faster!)
+
+
+<a href="https://scan.coverity.com/projects/5084">
+ <img alt="Coverity Scan Build Status"
+ src="https://scan.coverity.com/projects/5084/badge.svg"/>
+</a>
diff --git a/SIGNED.md b/SIGNED.md
new file mode 100644
index 0000000..179c95b
--- /dev/null
+++ b/SIGNED.md
@@ -0,0 +1,186 @@
+##### Signed by https://keybase.io/strcpy
+```
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQEcBAABAgAGBQJVC7HUAAoJEPIKXr0GpbbCZ1wIAJ5MwoT3jggOf6d+MBfLJb6Z
+n9lL8B+MAVzDL5u0beZzY9AFPnHn+Npj1rf49SOrbiGYgDPqOJPk7ZrxNv+wAFGz
+m6xiiOWUta0qaTIS1RgnXih0WOcir+5lm/5DuWlW4a7obUs30IEZzsvUqMVsxcX9
+70CFuvJBwTzf1NAMTpzGweZ/00yRVMacBO56aWMKLyHT7at3rMFRm8TSBBmvnO6y
+zFmprtPDQpV7GgAh5PTspfPkT4dLmfwgCTvgC+hoAef/6+XtIfESl0EdWZTjg3OO
+ZWukfeoCvIBXAxmGd/ns/mahLM2jFDRoGL09LyezrGUQvx6A8t2PWUHYsExnD1g=
+=h8Wj
+-----END PGP SIGNATURE-----
+
+```
+
+<!-- END SIGNATURES -->
+
+### Begin signed statement
+
+#### Expect
+
+```
+size exec file contents
+ ./
+173 .gitignore 372447fe4ebc48d242af7873ca6e8e18d73bee6a21525d7898c82d67dda48728
+12269 CMakeLists.txt b4d807ff26d14ebeaa27516a0923fb43bc709b07c1a8837538f3bb8c877b679f
+ CMakeModules/
+3926 AddOptions.cmake b89e00b3a04af81f1d7fad2ad9ec09e43d227a8740e74c6af38ff320e4bc7798
+1213 BaseConfig.cmake b69f6aab9039f6dbdc5e337b2ab2bac3d58956097a3685be37568be6f9b64c18
+1349 FindLibEvent.cmake d6ded937cc2f557531e4b7232158a22bec67fc4f3e7ea6525a64a52ab9b04788
+3770 UseCompVer.cmake e5b4052ddb6aa19057f2c4e09dcd3da23c2d9698941b31f9b31f548f7f8adcf7
+5304 UseDebugSymbols.cmake aa013ac37e5c61845739dbe2852d637a4542abef4edae89b8a043c1e83cde211
+33495 ChangeLog 2a02b057b18132bb36bfb29ab32a6e38d7530c2cf7f7b63ea6e0c2e23fb4d40c
+69989 Doxyfile 80cee7da0b443cb608470527dfb3eb25caf8318deeb8ba1734aeafadc9871552
+1781 LICENSE b013218ca11124c57d295516987989a3d7d8dcf17bb22b0923ddf5eb9982b3c5
+5308 README.markdown 737a395d07c1c4f80bfc00fca84b2a5ddc844d4ea8695ee1819105e59262b942
+ build/
+0 placeholder e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+ compat/
+ sys/
+16674 queue.h.in f5b69cf714d6c0bccb69c3a3b66839634ea8be6905b0dd141613889d155b489f
+74192 tree.h.in ae4dad3d8437c922d215f15d8dcba74fa60b5b43851bdd12a6da652471eee43d
+590 evhtp-config.h.in d3090a15e212f00ede0dac030481eb41a33bfd30934e7b5640c8a12332057a75
+720 evhtp-internal.h bf88199b54863f56a58ad7dcb249bb967a7dfaa6d58567c9fd10d3e73e15d4b6
+116275 evhtp.c 4fd2c70a560d8a5fa854ae004dd8dd799032ac8c59044aaa538179035c219e8a
+42916 evhtp.h 718f3957ad317937b737c58cc268a10b8069067e1091292e4709369ff551b1a8
+287 evhtp.pc.in 0d68fca6310508d446ebc8ee963c97136772ea3e69a00123968f0b613937ecc7
+1507 evhtp_numtoa.c 17c99ca11204b848accd5aaf3aa17f3ffa81927bb727c7b1e2e2f36293e5a4a8
+876 evhtp_numtoa.h 8ac8153c37984ea6082702ae9e715af989bc7260455a6ec67e84c92422fab005
+7073 evthr.c 0d68eef07fd63a8b3a4e89d083068ffa9c1d7a84cd469ed5b98a708f15cdd34b
+1643 evthr.h bf1ea48887450deb3b9f1e623c01d90a42eb7bf1f63cd5d087d597fa88079d94
+ examples/
+18422 test.c e42e9425289f5852a4b7373a848e1e58bb54cdd83d77181c29de89e1c3f6702b
+846 test_basic.c 302e23d3475099f9efd9c22b19a9f17463baf9c91f93cdd4bb5732b6c1f2df2e
+2060 test_client.c 9d06f74af2272a7f7cc3a0fc03e5ec7b9f7bd4c7c7f64aaee40532043100cb49
+11962 test_htparse.c 4e2e659ae2be92e1cf9decb9a42040e7a2ee6d2efd41ec29f4c1a0feb7971e7b
+3545 test_proxy.c 7ca2c2fda2755457ab15221165ec8a6f59128260b58bf6a001a173e91597864e
+7533 test_query.c 29c3092d9d0a54ed36b505ca5d38444bd10562cfd746366989abdec3f19095c5
+1317 test_vhost.c fe1ef3b75a10a043ba8c827717240bfabe860b4880e5c5b3e165cbd2127b85ef
+10340 thread_design.c 0991b37d7f2be57ca696dccb5728e61b51b66aece0d2e125fbefcf0a4cbcc6ff
+67336 htparse.c d954a62926dce13b92439177232658144daa27ea406a00a291e10e563599227e
+3801 htparse.h fbe06e8488248048baac677c7953ee87763c310a8c65cf73858cceff3f78198f
+ oniguruma/
+41 AUTHORS d74e190700c96963a9a4d883c2780d6f0c9a035f9d84d21a7ff977bd0bef3b54
+1881 CMakeLists.txt c979eaa21f6cc50bb38432305166fc08e969866c7dc59df3f326d498d00645ed
+1426 COPYING 0367dd7457d2499db8d1619ddd34223772d87f64d3db6aef9fab27753c0d0eda
+104851 HISTORY 2326065d34bf4b93fcd94ee81fd4cfd37c3c84e32eed23c2024cae7a019eb28f
+9478 INSTALL 4008daba19745ef700e8a69d160c8cc74347b8662c4285b5f943a66bc6e696a6
+2819 Makefile.am 61856fc2c97c84fd099431f6fe90328a467bcf0b54dc6aff616f4548e1018882
+64662 Makefile.in 6514edd957546aa8758b4c7b1e49a22e46de87e704b4086796f2fe7eb8ee8aa1
+5824 README dd126c9730f67218d294dc41bc27e52634be4e62e3cfbd70222fcbe342ec8f49
+5906 README.ja 9c8ae9854d7a686d6925d3f40c3d58d6fa96393cab7f81db3e730d8a70a02701|4350eb3d6ca4027e3719e1d30d330217503793dd2b7faf36cc312d8efb00bed7
+1030 config.h.in 663ad7972d7d51a148097130e86c10875a2e9478938e30049d974ba3d69cbfe9
+ enc/
+2408 ascii.c 62a20e8eabacf7e9673eda63428194e8700f467f55a2264701ae1f30c95bf4d8
+5438 big5.c b9281459f1f30614b5cdbd758683e86211967b1d8b1d04d826fe9932caf0c914
+8427 cp1251.c 698af66ad00f662c28bd88e798d58b1844c2ebdc2c7544e8eb7621afbfcda65c
+7212 euc_jp.c a0c90ad9a2e17940621f331fb674082ed3adc8632ecbd79f4cb10aeb987eb31f
+5169 euc_kr.c 88940a071cbc08cb98c8f6520871b80f2bab19d8f7ea4bb97bccd760c3af4987
+4391 euc_tw.c 2a50ad60a1198a9a520dee5f78f4bd5aae5268f5c1ba0851c3239339f8fa5c56
+12623 gb18030.c 158c7021e2cb3ac419d88208679dd45d68cf667531fa4aba12c45c2e610827b7
+8759 iso8859_1.c 0a96294d835c4e779af6abbd781f961c607e3069c725ea06db7697c0896a22fd
+9061 iso8859_10.c cfaee581e23415fea0ead784764ee1b068258f7b17866b779e5699d84cc09bbe
+4700 iso8859_11.c fb99147fcad49a640089ac0432e096f893550646bc4793dcf76f80ee5dc0b3ed
+8936 iso8859_13.c b83a37f4affcbc155818f674c759029092ff5c1afa35dabda5c42bacdc659743
+9118 iso8859_14.c 694d310eef7b2d9302da4e413d66c4be60ca2c92bad0bd3c92ff950b8714143c
+9090 iso8859_15.c 46f71d3e79df7b2c1f35b4a88a2fe8ed0e9bafcafde517eea8bf9ac113530c11
+9064 iso8859_16.c 4f895f1f3e39a5feeed493879952ed59023a026ce5203ab797e37a8c79e620cf
+9032 iso8859_2.c f814e36f349647388d5c1164abff03286eb2959a5ac54a466943ce4507426122
+9017 iso8859_3.c 993248f9e139973c7c122e17e2a961771f2adb0e80f83d05b72887a533bd211b
+9068 iso8859_4.c bde4dcd84715b29654bd6af041776472f4573b2e835f34f79ce6dc0b9f92bd70
+8788 iso8859_5.c 455036deb66b1f46324044d3c0444aeaccd7aa0a6cd6c09ba91db688577474b5
+4693 iso8859_6.c f608d8d17f929ba2cbe147769391a24dad26dc828696509b5438cdf12dae3ca2
+8702 iso8859_7.c e087979a15be34232ff778f64457058a769fe5a17e0d752c6b904c6c713f8bce
+4693 iso8859_8.c 5e921ad74752363d0fff3c6d451393bff381dd342044a7256a9403bff2216559
+8970 iso8859_9.c cea4207ea1fea951fd04d7ce77d2636244febf0255f074b54c6c3870d8804f66
+9267 koi8.c 0b8b9aabafed1f7df7559a097582cc736332870810dd95c5c43215f28aa68e92
+8623 koi8_r.c ebd883250c1074d1290c8841d26c77724cb37bee5d66317af134dd9e2e01fa5b
+28613 mktable.c 278b62506987e040c83d76b9719a3806d83ad8011343bfcc5f77e1ea4f3bb72f
+8259 sjis.c 58bf75d8271f35baabba3e0dff63931daafa4a5d5e5d0a694c8216329032e8ad
+238107 unicode.c 83dc72f52eca615214c5260505a2917cbd0a79c7efe9002a6c269ee86e985d67
+6208 utf16_be.c 7536dafcc03c2f6b2dfb09907a7e57a0df6a79e6c321fc99feb4b9cf3475eda8
+6254 utf16_le.c 6f571e6351cbf5cbdc83f96cb371560ca76cda91c48d4bda3addb5fdaebca83e
+5083 utf32_be.c f7e51559eb0d03f80e94e5c14dc359315ce91d33a26c1ac6b4a6712c7309301f
+5116 utf32_le.c fb5367d3be48c7f9b30108db8619c30ae1f43938a19780924483957e54bdf1da
+8281 utf8.c 1ae263d2c475b46c4946b3caa8026ecdd6bfff2792555a43388cc62e6f5a421e
+1407 onig-config.in d4f03d9e6b851fcc11ecf625aadf1248c9da4db9ddb9a7f538f51347a752616a
+3429 oniggnu.h 9b105f489f39e0e3c7f8a134c1876aa06ab91ef5abf5bf28edd3da29ff82a9f3
+5753 onigposix.h 6923ff3279c303e97a3509ed94f8499ab0fbec56d241afd79e1a853b3abfff32
+36363 oniguruma.h 49d7362f079ebc3730b448e553e7d84cabcee2cd7af0ae712c16ff54db4d571b
+144310 regcomp.c 0ba02e07f84c849b712a7cee0dbe4df87c06115d6ddbf85a270938f62bfc967c
+27673 regenc.c 4aa13ad79a29fb352851621fcefb70fbf0bf78254fcbe20ef1d655005165a86b
+8995 regenc.h d2569a176cdcab3a720b73375ecb54056b9078ec3f3c397a12c9218a57dae7cc
+12127 regerror.c cb3153290fb35b68daf75ac800ea5e02dca73f6289f6bed7d2adc119e75bbb09
+92706 regexec.c 85ef2a2017f40d31d9b106351eb38f2aa5d1d082bdacc3c4624dc61b43be0647
+5961 regext.c a36080ca9604c3bed612e0bbd433cfcc38b097a0cc5acccfec82105a57a60a94
+4606 reggnu.c d2f863bb05f1216d2bd5eb57ddb7e8d178fdbbbce12e89d93f708ba6e37edbd2
+29044 regint.h 23c3975f371908ac114bd79264109b6f3f8357b6fc83ba3183229b1f500304b0
+124477 regparse.c 79d83acd99ce212df1d610ed8dbea00017bf60a105a02e5a8ab58a3f1570cc98
+12158 regparse.h c8480f242f865552d947a949383b6579d496839bbc8dfbd1a391460b43e37513
+3630 regposerr.c 853945b9695209ab73f61396a9341ebd334af59ed4a142ecca2f807a12b78e42
+10840 regposix.c be43f47c3e13c2674fc39505765959fdc7ec961ceb31c4cea74c7260be517aa7
+11381 regsyntax.c 66e05410c16eb32806847e68faed7570a8acfac929cf13d399d1096c5e28668f
+2884 regtrav.c 799d2e82006486abf6e98683b79bc8d3c8febb525dd87e993b0d010d4a1e2ac5
+2116 regversion.c eac3ffb78255e00142d72d2f79049efdab7f78a01fc722d5ad6b619f326231c6
+ sample/
+596 Makefile.am d030dcd544ad5d3aa5495d8f29e85fcaccddd1378598d220708a63b1253eec35
+15992 Makefile.in f9d0c0342d1a1fb09aa5cae2256c3810ac8cdf99f286496b916f35b6186dc7ef
+3530 crnl.c 168a89366cffbac7727716a22f1ec6e7ed0faa3759b5fad5f16f55353fdcc115
+9755 encode.c a77d8264fec223b64193639aba189ae85cc369662f19630ee753543685f219eb
+2680 listcap.c e45e0dc19dd8378c0b561106014261c337f1bf8e4ab5646a1cbc4cfc85568dc3
+1893 names.c 29842695e33f18219e1bc82212815e8f7cdcd92f6cffb29ee1fb43180a6eca99
+2327 posix.c dbee9148884b62c2866d3108c0ad9af3f855a7b5058b47415531eff1f6a0f536
+1361 simple.c ccb8e23f98df3ab83c3c0574ef59f3bac46d2ce7b7527e8ae5199a0d4e5fd522
+2167 sql.c d5f5221557f6f1ce631a278e52485043115097daa235456329b1977e1f0e7478
+1801 syntax.c 131f74f8fe66978d6e5c8cfb89467d20583a5320a53f3bcb1279cbde37a47169
+11025 st.c 87ad07cac050af7d3e5dd2ed3be50dedda8886695c889cee8710900746e14eb3
+1648 st.h 8abe8d7952fa49cc1a021c85609474a1c5570674287404c95ab8f23c98b17bb3
+27942 testc.c d2594d1369b3c73e7def01d23c75ac808a2463fa4aee7f73fcd8e5b68c8e0ee0|3e948438abafa03feda79d5dbfd01acedb8498c7e0d3008b153de68457b22d69
+71370 testu.c 38b3b842afe0e1d80765c78c1fc1adfbfda381163c85267da1a8816feee7adb6
+ win32/
+7246 Makefile e1ec44a22c546cefe53c5809eda594b768829f0847de0dc748e5f108a7cd61c7|6354cc21dd799689aa20b7927fe9b7910bc7ef6a5802fcf906b24b7b9829ed09
+2033 config.h dc26c6e27c03e980a9dbd853296e219b6a007614780d50af64ec48266b632468|06de45495bc5e68ede1bebf4cf9efbb477ee4dce9889e8a889d6355c40285d0d
+28801 testc.c 3208bf7b05caadfc3aaa59dead98551a656bb8e7181aaed3e0d2c322b02abd6d|b9d8a129156ca32fff146a385b94a0cbd78306827be800962ca044c25826966a
+70035 zimg_vs_nginx.png 274b9e87a8c89d2139564937f143e253830cebf121423e8c8fa9d4d7b7da6eb4|9db9594e8a78c04a34c35b419271d8d908e198f0c543eb1b9b462d6224cf1e49
+```
+
+#### Ignore
+
+```
+/SIGNED.md
+```
+
+#### Presets
+
+```
+git # ignore .git and anything as described by .gitignore files
+dropbox # ignore .dropbox-cache and other Dropbox-related files
+kb # ignore anything as described by .kbignore files
+```
+
+<!-- summarize version = 0.0.9 -->
+
+### End signed statement
+
+<hr>
+
+#### Notes
+
+With keybase you can sign any directory's contents, whether it's a git repo,
+source code distribution, or a personal documents folder. It aims to replace the drudgery of:
+
+ 1. comparing a zipped file to a detached statement
+ 2. downloading a public key
+ 3. confirming it is in fact the author's by reviewing public statements they've made, using it
+
+All in one simple command:
+
+```bash
+keybase dir verify
+```
+
+There are lots of options, including assertions for automating your checks.
+
+For more info, check out https://keybase.io/docs/command_line/code_signing
\ No newline at end of file
diff --git a/build/placeholder b/build/placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/placeholder
diff --git a/CMakeModules/FindLibEvent.cmake b/cmake/FindLibEvent.cmake
similarity index 100%
rename from CMakeModules/FindLibEvent.cmake
rename to cmake/FindLibEvent.cmake
diff --git a/evhtp-config.h.in b/evhtp-config.h.in
index 9e3d95f..d6ddbc7 100644
--- a/evhtp-config.h.in
+++ b/evhtp-config.h.in
@@ -1,6 +1,19 @@
#ifndef __EVHTP_CONFIG_H__
#define __EVHTP_CONFIG_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EVHTP_EXPORT
+# if (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER || defined __clang__
+# define EVHTP_EXPORT __attribute__ ((visibility("default")))
+# else
+# define EVHTP_EXPORT
+# endif
+#endif
+
+
#undef EVHTP_DISABLE_EVTHR
#undef EVHTP_DISABLE_REGEX
#undef EVHTP_DISABLE_SSL
@@ -10,5 +23,30 @@
#cmakedefine EVHTP_DISABLE_REGEX
#cmakedefine EVHTP_DISABLE_SSL
#cmakedefine EVHTP_DISABLE_EVTHR
+#cmakedefine EVHTP_USE_TCMALLOC
+#cmakedefine EVHTP_USE_JEMALLOC
+#cmakedefine EVHTP_USE_TCMALLOC
+
+#ifdef EVHTP_USE_TCMALLOC
+#include <google/tcmalloc.h>
+#define malloc(size) tc_malloc(size)
+#define calloc(count, size) tc_calloc(count, size)
+#define realloc(ptr, size) tc_realloc(ptr, size)
+#define free(ptr) tc_free(ptr)
+#endif
+
+#ifdef EVHTP_USE_JEMALLOC
+#define JEMALLOC_NO_DEMANGLE
+#include <jemalloc/jemalloc.h>
+#define malloc(size) je_malloc(size)
+#define calloc(count, size) je_calloc(count, size)
+#define realloc(ptr, size) je_realloc(ptr, size)
+#define free(ptr) je_free(ptr)
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/evhtp-internal.h b/evhtp-internal.h
index 7c893d1..cf7f962 100644
--- a/evhtp-internal.h
+++ b/evhtp-internal.h
@@ -1,11 +1,17 @@
#ifndef __EVHTP_INTERNAL_H__
#define __EVHTP_INTERNAL_H__
-#ifdef EVHTP_HAS_VISIBILITY_HIDDEN
-#define __visible __attribute__((visibility("default")))
-#define EXPORT_SYMBOL(x) typeof(x)(x)__visible
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined __GNUC__ || defined __llvm__
+# define evhtp_likely(x) __builtin_expect(!!(x), 1)
+# define evhtp_unlikely(x) __builtin_expect(!!(x), 0)
#else
-#define EXPORT_SYMBOL(n)
+# define evhtp_likely(x) (x)
+# define evhtp_unlikely(x) (x)
#endif
#ifndef TAILQ_FOREACH_SAFE
@@ -20,5 +26,51 @@
(_var) = NULL; \
} while (0)
+
+#define evhtp_assert(x) \
+ do { \
+ if (evhtp_unlikely(!(x))) { \
+ fprintf(stderr, "Assertion failed: %s (%s:%s:%d)\n", # x, \
+ __func__, __FILE__, __LINE__); \
+ fflush(stderr); \
+ abort(); \
+ } \
+ } while (0)
+
+#define evhtp_alloc_assert(x) \
+ do { \
+ if (evhtp_unlikely(!x)) { \
+ fprintf(stderr, "Out of memory (%s:%s:%d)\n", \
+ __func__, __FILE__, __LINE__); \
+ fflush(stderr); \
+ abort(); \
+ } \
+ } while (0)
+
+#define evhtp_assert_fmt(x, fmt, ...) \
+ do { \
+ if (evhtp_unlikely(!(x))) { \
+ fprintf(stderr, "Assertion failed: %s (%s:%s:%d) " fmt "\n", \
+ # x, __func__, __FILE__, __LINE__, __VA_ARGS__); \
+ fflush(stderr); \
+ abort(); \
+ } \
+ } while (0)
+
+#define evhtp_errno_assert(x) \
+ do { \
+ if (evhtp_unlikely(!(x))) { \
+ fprintf(stderr, "%s [%d] (%s:%s:%d)\n", \
+ strerror(errno), errno, \
+ __func__, __FILE__, __LINE__); \
+ fflush(stderr); \
+ abort(); \
+ } \
+ } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/evhtp.c b/evhtp.c
index 24ffd6d..6ff6b90 100644
--- a/evhtp.c
+++ b/evhtp.c
@@ -28,6 +28,18 @@
#include "evhtp.h"
+#ifdef EVHTP_DEBUG
+static void
+htp_log_connection(evhtp_connection_t * c) {
+ htp_log_debug("connection = %p\n", c);
+ htp_log_debug("request = %p\n", c->request);
+}
+
+#endif
+
+
+
+
static int _evhtp_request_parser_start(htparser * p);
static int _evhtp_request_parser_host(htparser * p, const char * data, size_t len);
static int _evhtp_request_parser_port(htparser * p, const char * data, size_t len);
@@ -343,6 +355,7 @@
*
* @return 1 if HTTP/1.1, else 0
*/
+
#define _evhtp_is_http_10(_major, _minor) \
(_major >= 1 && _minor <= 0)
@@ -520,6 +533,7 @@
if (connection->request) {
_evhtp_error_hook(connection->request, errtype);
}
+
HOOK_CONN_RUN(connection, on_connection_error, errtype);
return EVHTP_RES_OK;
@@ -610,7 +624,7 @@
*/
static inline int
_evhtp_glob_match(const char * pattern, size_t pat_len, const char * string, size_t str_len) {
- if (!pattern || !string) {
+ if (evhtp_unlikely(!pattern || !string)) {
return 0;
}
@@ -622,58 +636,7 @@
str_len = strlen(string);
}
- /* XXX still in testing */
return _evhtp_glob_match2(pattern, pat_len, string, str_len);
-
-#if 0
- while (pat_len) {
- if (pattern[0] == '*') {
- while (pattern[1] == '*') {
- pattern++;
- pat_len--;
- }
-
- if (pat_len == 1) {
- return 1;
- }
-
- while (str_len) {
- if (_evhtp_glob_match(pattern + 1, pat_len, string, str_len)) {
- return 1;
- }
-
- string++;
- str_len--;
- }
-
- return 0;
- } else {
- if (pattern[0] != string[0]) {
- return 0;
- }
-
- string++;
- str_len--;
- }
-
- pattern++;
- pat_len--;
-
- if (str_len == 0) {
- while (*pattern == '*') {
- pattern++;
- pat_len--;
- }
- break;
- }
- }
-
- if (pat_len == 0 && str_len == 0) {
- return 1;
- }
-
- return 0;
-#endif
} /* _evhtp_glob_match */
static evhtp_callback_t *
@@ -686,7 +649,7 @@
#endif
evhtp_callback_t * callback;
- if (cbs == NULL) {
+ if (evhtp_unlikely(cbs == NULL)) {
return NULL;
}
@@ -744,7 +707,7 @@
evhtp_request_t * req;
uint8_t error;
- if (!(req = calloc(sizeof(evhtp_request_t), 1))) {
+ if (evhtp_unlikely(!(req = calloc(sizeof(evhtp_request_t), 1)))) {
return NULL;
}
@@ -754,19 +717,19 @@
req->status = EVHTP_RES_OK;
do {
- if (!(req->buffer_in = evbuffer_new())) {
+ if (evhtp_unlikely(!(req->buffer_in = evbuffer_new()))) {
break;
}
- if (!(req->buffer_out = evbuffer_new())) {
+ if (evhtp_unlikely(!(req->buffer_out = evbuffer_new()))) {
break;
}
- if (!(req->headers_in = malloc(sizeof(evhtp_headers_t)))) {
+ if (evhtp_unlikely(!(req->headers_in = malloc(sizeof(evhtp_headers_t))))) {
break;
}
- if (!(req->headers_out = malloc(sizeof(evhtp_headers_t)))) {
+ if (evhtp_unlikely(!(req->headers_out = malloc(sizeof(evhtp_headers_t))))) {
break;
}
@@ -792,7 +755,7 @@
*/
static void
_evhtp_request_free(evhtp_request_t * request) {
- if (request == NULL) {
+ if (evhtp_unlikely(request == NULL)) {
return;
}
@@ -853,11 +816,11 @@
return;
}
- free(authority->username);
- free(authority->password);
- free(authority->hostname);
+ evhtp_safe_free(authority->username, free);
+ evhtp_safe_free(authority->password, free);
+ evhtp_safe_free(authority->hostname, free);
- free(authority);
+ evhtp_safe_free(authority, free);
}
/**
@@ -883,18 +846,18 @@
*/
static void
_evhtp_uri_free(evhtp_uri_t * uri) {
- if (uri == NULL) {
+ if (evhtp_unlikely(uri == NULL)) {
return;
}
- evhtp_query_free(uri->query);
+ evhtp_safe_free(uri->query, evhtp_query_free);
+ evhtp_safe_free(uri->path, _evhtp_path_free);
+ evhtp_safe_free(uri->authority, _evhtp_authority_free);
- _evhtp_path_free(uri->path);
- _evhtp_authority_free(uri->authority);
+ evhtp_safe_free(uri->fragment, free);
+ evhtp_safe_free(uri->query_raw, free);
- free(uri->fragment);
- free(uri->query_raw);
- free(uri);
+ evhtp_safe_free(uri, free);
}
/**
@@ -919,21 +882,24 @@
char * path = NULL;
char * file = NULL;
- if (!(req_path = calloc(sizeof(evhtp_path_t), 1))) {
- return NULL;
- }
+ req_path = calloc(sizeof(evhtp_path_t), 1);
+ evhtp_alloc_assert(req_path);
- if (len == 0) {
+ if (evhtp_unlikely(len == 0)) {
/*
* odd situation here, no preceding "/", so just assume the path is "/"
*/
path = strdup("/");
+ evhtp_alloc_assert(path);
} else if (*data != '/') {
/* request like GET stupid HTTP/1.0, treat stupid as the file, and
* assume the path is "/"
*/
path = strdup("/");
file = strndup(data, len);
+
+ evhtp_alloc_assert(path);
+ evhtp_alloc_assert(file);
} else {
if (data[len - 1] != '/') {
/*
@@ -956,14 +922,14 @@
/* check for overflow */
if ((const char *)(data + path_len) > data_end) {
- free(req_path);
+ evhtp_safe_free(req_path, free);
return NULL;
}
/* check for overflow */
if ((const char *)(&data[i + 1] + file_len) > data_end) {
- free(req_path);
+ evhtp_safe_free(req_path, free);
return NULL;
}
@@ -971,6 +937,9 @@
path = strndup(data, path_len);
file = strndup(&data[i + 1], file_len);
+ evhtp_alloc_assert(path);
+ evhtp_alloc_assert(file);
+
break;
}
}
@@ -978,14 +947,17 @@
if (i == 0 && data[i] == '/' && !file && !path) {
/* drops here if the request is something like GET /foo */
path = strdup("/");
+ evhtp_alloc_assert(path);
if (len > 1) {
file = strndup((const char *)(data + 1), len);
+ evhtp_alloc_assert(file);
}
}
} else {
/* the last character is a "/", thus the request is just a path */
path = strndup(data, len);
+ evhtp_alloc_assert(path);
}
}
@@ -995,6 +967,8 @@
req_path->full = strdup("/");
}
+ evhtp_alloc_assert(req_path->full);
+
req_path->path = path;
req_path->file = file;
@@ -1003,29 +977,28 @@
static void
_evhtp_path_free(evhtp_path_t * path) {
- if (path == NULL) {
+ if (evhtp_unlikely(path == NULL)) {
return;
}
- free(path->full);
+ evhtp_safe_free(path->full, free);
+ evhtp_safe_free(path->path, free);
+ evhtp_safe_free(path->file, free);
+ evhtp_safe_free(path->match_start, free);
+ evhtp_safe_free(path->match_end, free);
- free(path->path);
- free(path->file);
- free(path->match_start);
- free(path->match_end);
-
- free(path);
+ evhtp_safe_free(path, free);
}
static int
_evhtp_request_parser_start(htparser * p) {
evhtp_connection_t * c = htparser_get_userdata(p);
- if (c->type == evhtp_type_client) {
+ if (evhtp_unlikely(c->type == evhtp_type_client)) {
return 0;
}
- if (c->paused == 1) {
+ if (evhtp_unlikely(c->paused == 1)) {
return -1;
}
@@ -1037,7 +1010,7 @@
}
}
- if (!(c->request = _evhtp_request_new(c))) {
+ if (evhtp_unlikely(!(c->request = _evhtp_request_new(c)))) {
return -1;
}
@@ -1081,15 +1054,12 @@
size_t fraglen;
/* Skip '#'. */
- fragment += 1;
- frag_offset += 1;
- fraglen = len - frag_offset;
+ fragment += 1;
+ frag_offset += 1;
+ fraglen = len - frag_offset;
- if (!(uri->fragment = malloc(fraglen + 1))) {
- c->request->status = EVHTP_RES_ERROR;
-
- return -1;
- }
+ uri->fragment = malloc(fraglen + 1);
+ evhtp_alloc_assert(uri->fragment);
memcpy(uri->fragment, fragment, fraglen);
@@ -1100,15 +1070,16 @@
uri->query = evhtp_parse_query_wflags(data, len, c->htp->parser_flags);
- if (!uri->query) {
+ if (evhtp_unlikely(!uri->query)) {
c->request->status = EVHTP_RES_ERROR;
return -1;
}
uri->query_raw = malloc(len + 1);
- memcpy(uri->query_raw, data, len);
+ evhtp_alloc_assert(uri->query_raw);
+ memcpy(uri->query_raw, data, len);
uri->query_raw[len] = '\0';
return 0;
@@ -1132,6 +1103,8 @@
evhtp_header_t * hdr;
key_s = malloc(len + 1);
+ evhtp_alloc_assert(key_s);
+
key_s[len] = '\0';
memcpy(key_s, data, len);
@@ -1153,11 +1126,13 @@
evhtp_header_t * header;
val_s = malloc(len + 1);
+ evhtp_alloc_assert(val_s);
+
val_s[len] = '\0';
memcpy(val_s, data, len);
if ((header = evhtp_header_val_add(c->request->headers_in, val_s, 0)) == NULL) {
- free(val_s);
+ evhtp_safe_free(val_s, free);
c->request->status = EVHTP_RES_FATAL;
return -1;
@@ -1178,7 +1153,7 @@
evhtp_alias_t * evhtp_alias;
TAILQ_FOREACH(evhtp_vhost, &evhtp->vhosts, next_vhost) {
- if (evhtp_vhost->server_name == NULL) {
+ if (evhtp_unlikely(evhtp_vhost->server_name == NULL)) {
continue;
}
@@ -1215,11 +1190,11 @@
return -1;
}
- if ((evhtp = request->htp) == NULL) {
+ if (evhtp_unlikely((evhtp = request->htp) == NULL)) {
return -1;
}
- if ((conn = request->conn) == NULL) {
+ if (evhtp_unlikely((conn = request->conn) == NULL)) {
return -1;
}
@@ -1259,10 +1234,12 @@
if (path->match_start == NULL) {
path->match_start = calloc(strlen(path->full) + 1, 1);
+ evhtp_alloc_assert(path->match_start);
}
if (path->match_end == NULL) {
path->match_end = calloc(strlen(path->full) + 1, 1);
+ evhtp_alloc_assert(path->match_end);
}
if (path->matched_soff != UINT_MAX /*ONIG_REGION_NOTPOS*/) {
@@ -1282,6 +1259,7 @@
if (hooks != NULL) {
if (request->hooks == NULL) {
request->hooks = malloc(sizeof(evhtp_hooks_t));
+ evhtp_alloc_assert(request->hooks);
}
memcpy(request->hooks, hooks, sizeof(evhtp_hooks_t));
@@ -1348,11 +1326,8 @@
static int
_evhtp_require_uri(evhtp_connection_t * c) {
if (c && c->request && !c->request->uri) {
- if (!(c->request->uri = _evhtp_uri_new())) {
- c->request->status = EVHTP_RES_FATAL;
-
- return -1;
- }
+ c->request->uri = _evhtp_uri_new();
+ evhtp_alloc_assert(c->request->uri);
}
return 0;
@@ -1368,7 +1343,7 @@
}
authority = c->request->uri->authority;
- authority->hostname = strndup(data, len);
+ authority->hostname = malloc(len + 1);
if (!authority->hostname) {
c->request->status = EVHTP_RES_FATAL;
@@ -1376,6 +1351,9 @@
return -1;
}
+ memcpy(authority->hostname, data, len);
+ authority->hostname[len] = '\0';
+
return 0;
}
@@ -1413,7 +1391,7 @@
return -1;
}
- if (!(path = _evhtp_path_new(data, len))) {
+ if (evhtp_unlikely(!(path = _evhtp_path_new(data, len)))) {
c->request->status = EVHTP_RES_FATAL;
return -1;
@@ -1438,7 +1416,10 @@
static int
_evhtp_request_parser_headers(htparser * p) {
- evhtp_connection_t * c = htparser_get_userdata(p);
+ evhtp_connection_t * c;
+
+ c = htparser_get_userdata(p);
+ evhtp_assert(c != NULL);
/* XXX proto should be set with htparsers on_hdrs_begin hook */
c->request->keepalive = htparser_should_keep_alive(p);
@@ -1479,7 +1460,10 @@
return -1;
}
- buf = evbuffer_new();
+ buf = c->scratch_buf;
+ evhtp_assert(buf != NULL);
+
+
evbuffer_add(buf, data, len);
if ((c->request->status = _evhtp_body_hook(c->request, buf)) != EVHTP_RES_OK) {
@@ -1490,7 +1474,7 @@
evbuffer_add_buffer(c->request->buffer_in, buf);
}
- evbuffer_free(buf);
+ evbuffer_drain(buf, -1);
c->body_bytes_read += len;
@@ -1599,6 +1583,8 @@
body = (const char *)evbuffer_pullup(buf_in, body_len);
uri->query_raw = calloc(body_len + 1, 1);
+ evhtp_alloc_assert(uri->query_raw);
+
memcpy(uri->query_raw, body, body_len);
uri->query = evhtp_parse_query(body, body_len);
@@ -1649,7 +1635,16 @@
content_type = evhtp_header_find(request->headers_out, "Content-Type");
out_len = evbuffer_get_length(request->buffer_out);
- buf = evbuffer_new();
+
+ buf = request->conn->scratch_buf;
+ evhtp_assert(buf != NULL);
+
+ evbuffer_drain(buf, -1);
+
+ /*
+ * buf = evbuffer_new();
+ * evhtp_alloc_assert(buf);
+ */
if (htparser_get_multipart(request->conn->parser) == 1) {
goto check_proto;
@@ -1667,23 +1662,7 @@
evhtp_headers_add_header(request->headers_out,
evhtp_header_new("Content-Length", out_buf, 0, 1));
}
-
- if (!content_type) {
- evhtp_headers_add_header(request->headers_out,
- evhtp_header_new("Content-Type", "text/plain", 0, 0));
- }
- } else {
- if (!evhtp_header_find(request->headers_out, "Content-Length")) {
- const char * chunked = evhtp_header_find(request->headers_out,
- "transfer-encoding");
-
- if (!chunked || !strstr(chunked, "chunked")) {
- evhtp_headers_add_header(request->headers_out,
- evhtp_header_new("Content-Length", "0", 0, 0));
- }
- }
}
-
check_proto:
/* add the proper keep-alive type headers based on http version */
switch (request->proto) {
@@ -1693,6 +1672,14 @@
evhtp_headers_add_header(request->headers_out,
evhtp_header_new("Connection", "close", 0, 0));
}
+
+#if 0
+ if (!out_len && !evhtp_header_find(request->headers_out, "Content-Length")) {
+ evhtp_headers_add_header(request->headers_out,
+ evhtp_header_new("Content-Length", "0", 0, 0));
+ }
+#endif
+
break;
case EVHTP_PROTO_10:
if (request->keepalive == 1) {
@@ -1710,6 +1697,11 @@
} /* switch */
+ if (!content_type) {
+ evhtp_headers_add_header(request->headers_out,
+ evhtp_header_new("Content-Type", "text/plain", 0, 0));
+ }
+
/* attempt to add the status line into a temporary buffer and then use
* evbuffer_add(). Using plain old snprintf() will be faster than
* evbuffer_add_printf(). If the snprintf() fails, which it rarely should,
@@ -1786,9 +1778,13 @@
size_t nread;
size_t avail;
+ htp_log_debug("enter sock = %d", c->sock);
+
avail = evbuffer_get_length(bufferevent_get_input(bev));
- if (avail == 0) {
+ htp_log_debug("available bytes %zu", avail);
+
+ if (evhtp_unlikely(avail == 0)) {
return;
}
@@ -1802,9 +1798,13 @@
buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
+ htp_log_debug("buffer is\n----\n%.*s\n-----", (int)avail, (const char *)buf);
+
nread = htparser_run(c->parser, &request_psets, (const char *)buf, avail);
- if (c->owner != 1) {
+ htp_log_debug("nread = %zu", nread);
+
+ if (evhtp_unlikely(c->owner != 1)) {
/*
* someone has taken the ownership of this connection, we still need to
* drain the input buffer that had been read up to this point.
@@ -1833,6 +1833,9 @@
evhtp_request_pause(c->request);
} else if (htparser_get_error(c->parser) != htparse_error_none) {
evhtp_connection_free(c);
+ } else if (nread < avail) {
+ /* we still have more data to read (piped request probably) */
+ evhtp_connection_resume(c);
}
} /* _evhtp_connection_readcb */
@@ -1840,17 +1843,19 @@
_evhtp_connection_writecb(evbev_t * bev, void * arg) {
evhtp_connection_t * c = arg;
- if (c->request == NULL) {
+ htp_log_debug("c->request = %p", c->request);
+
+ if (evhtp_unlikely(c->request == NULL)) {
return;
}
_evhtp_connection_write_hook(c);
- if (c->paused == 1) {
+ if (evhtp_unlikely(c->paused == 1)) {
return;
}
- if (c->waiting == 1) {
+ if (evhtp_unlikely(c->waiting == 1)) {
c->waiting = 0;
bufferevent_enable(bev, EV_READ);
@@ -1866,7 +1871,6 @@
return;
}
-
/*
* if there is a set maximum number of keepalive requests configured, check
* to make sure we are not over it. If we have gone over the max we set the
@@ -1897,8 +1901,6 @@
}
htparser_init(c->parser, htp_type_request);
-
-
htparser_set_userdata(c->parser, c);
return;
@@ -1920,7 +1922,7 @@
}
if ((events & BEV_EVENT_CONNECTED)) {
- if (c->type == evhtp_type_client) {
+ if (evhtp_likely(c->type == evhtp_type_client)) {
c->connected = 1;
bufferevent_setcb(bev,
_evhtp_connection_readcb,
@@ -1965,6 +1967,9 @@
_evhtp_connection_error_hook(c, events);
if (c->paused == 1) {
+ /* we are currently paused, so we don't want to free just yet, let's
+ * wait till the next loop.
+ */
c->free_connection = 1;
} else {
evhtp_connection_free((evhtp_connection_t *)arg);
@@ -1976,7 +1981,7 @@
void * args;
evhtp_res res;
- if (htp->defaults.pre_accept == NULL) {
+ if (evhtp_likely(htp->defaults.pre_accept == NULL)) {
return 0;
}
@@ -2017,6 +2022,9 @@
connection->bev = bufferevent_socket_new(evbase,
connection->sock,
connection->htp->bev_flags);
+
+ htp_log_debug("enter sock=%d\n", connection->sock);
+
#ifndef EVHTP_DISABLE_SSL
end:
#endif
@@ -2056,6 +2064,8 @@
static void
_evhtp_default_request_cb(evhtp_request_t * request, void * arg) {
+ evhtp_headers_add_header(request->headers_out,
+ evhtp_header_new("Content-Length", "0", 0, 0));
evhtp_send_reply(request, EVHTP_RES_NOTFOUND);
}
@@ -2072,28 +2082,25 @@
ptype = htp_type_request;
break;
default:
-
return NULL;
}
- if (!(connection = calloc(sizeof(evhtp_connection_t), 1))) {
- return NULL;
- }
+ connection = calloc(sizeof(evhtp_connection_t), 1);
+ evhtp_alloc_assert(connection);
- connection->error = 0;
- connection->owner = 1;
- connection->paused = 0;
- connection->connected = 0;
- connection->sock = sock;
- connection->htp = htp;
- connection->type = type;
- connection->parser = htparser_new();
+ connection->scratch_buf = evbuffer_new();
+ evhtp_alloc_assert(connection->scratch_buf);
- if (!connection->parser) {
- evhtp_safe_free(connection, free);
+ connection->error = 0;
+ connection->owner = 1;
+ connection->paused = 0;
+ connection->connected = 0;
+ connection->sock = sock;
+ connection->htp = htp;
+ connection->type = type;
+ connection->parser = htparser_new();
- return NULL;
- }
+ evhtp_alloc_assert(connection->parser);
htparser_init(connection->parser, ptype);
htparser_set_userdata(connection->parser, connection);
@@ -2119,7 +2126,7 @@
void * args;
evhtp_res res;
- if (htp->defaults.post_accept == NULL) {
+ if (evhtp_likely(htp->defaults.post_accept == NULL)) {
return 0;
}
@@ -2162,16 +2169,21 @@
evhtp_t * htp = arg;
evhtp_connection_t * connection;
- if (!(connection = _evhtp_connection_new(htp, fd, evhtp_type_server))) {
+ if (evhtp_unlikely(!(connection = _evhtp_connection_new(htp, fd, evhtp_type_server)))) {
return;
}
+ htp_log_debug("fd = %d, conn = %p", fd, connection);
+
connection->saddr = malloc(sl);
+ evhtp_alloc_assert(connection->saddr);
+
memcpy(connection->saddr, s, sl);
#ifndef EVHTP_DISABLE_EVTHR
if (htp->thr_pool != NULL) {
- if (evthr_pool_defer(htp->thr_pool, _evhtp_run_in_thread, connection) != EVTHR_RES_OK) {
+ if (evthr_pool_defer(htp->thr_pool,
+ _evhtp_run_in_thread, connection) != EVTHR_RES_OK) {
evutil_closesocket(connection->sock);
evhtp_connection_free(connection);
@@ -2194,7 +2206,7 @@
return;
}
-}
+} /* _evhtp_accept_cb */
#ifndef EVHTP_DISABLE_SSL
#ifndef EVHTP_DISABLE_EVTHR
@@ -2326,6 +2338,10 @@
htp_method
evhtp_request_get_method(evhtp_request_t * r) {
+ evhtp_assert(r != NULL);
+ evhtp_assert(r->conn != NULL);
+ evhtp_assert(r->conn->parser != NULL);
+
return htparser_get_method(r->conn->parser);
}
@@ -2336,6 +2352,8 @@
*/
void
evhtp_connection_pause(evhtp_connection_t * c) {
+ evhtp_assert(c != NULL);
+
c->paused = 1;
bufferevent_disable(c->bev, EV_READ | EV_WRITE);
@@ -2350,6 +2368,8 @@
*/
void
evhtp_connection_resume(evhtp_connection_t * c) {
+ evhtp_assert(c != NULL);
+
c->paused = 0;
event_active(c->resume_ev, EV_WRITE, 1);
@@ -2366,6 +2386,8 @@
*/
void
evhtp_request_pause(evhtp_request_t * request) {
+ evhtp_assert(request != NULL);
+
request->status = EVHTP_RES_PAUSE;
evhtp_connection_pause(request->conn);
}
@@ -2379,6 +2401,8 @@
*/
void
evhtp_request_resume(evhtp_request_t * request) {
+ evhtp_assert(request != NULL);
+
evhtp_connection_resume(request->conn);
}
@@ -2428,7 +2452,10 @@
evhtp_kvs_t *
evhtp_kvs_new(void) {
- evhtp_kvs_t * kvs = malloc(sizeof(evhtp_kvs_t));
+ evhtp_kvs_t * kvs;
+
+ kvs = malloc(sizeof(evhtp_kvs_t));
+ evhtp_alloc_assert(kvs);
TAILQ_INIT(kvs);
@@ -2439,9 +2466,8 @@
evhtp_kv_new(const char * key, const char * val, char kalloc, char valloc) {
evhtp_kv_t * kv;
- if (!(kv = malloc(sizeof(evhtp_kv_t)))) {
- return NULL;
- }
+ kv = malloc(sizeof(evhtp_kv_t));
+ evhtp_alloc_assert(kv);
kv->k_heaped = kalloc;
kv->v_heaped = valloc;
@@ -2490,7 +2516,7 @@
void
evhtp_kv_free(evhtp_kv_t * kv) {
- if (kv == NULL) {
+ if (evhtp_unlikely(kv == NULL)) {
return;
}
@@ -2507,7 +2533,7 @@
void
evhtp_kv_rm_and_free(evhtp_kvs_t * kvs, evhtp_kv_t * kv) {
- if (kvs == NULL || kv == NULL) {
+ if (evhtp_unlikely(kvs == NULL || kv == NULL)) {
return;
}
@@ -2521,7 +2547,7 @@
evhtp_kv_t * kv;
evhtp_kv_t * save;
- if (kvs == NULL) {
+ if (evhtp_unlikely(kvs == NULL)) {
return;
}
@@ -2530,7 +2556,7 @@
TAILQ_REMOVE(kvs, kv, next);
- evhtp_kv_free(kv);
+ evhtp_safe_free(kv, evhtp_kv_free);
}
evhtp_safe_free(kvs, free);
@@ -2559,7 +2585,7 @@
evhtp_kv_find(evhtp_kvs_t * kvs, const char * key) {
evhtp_kv_t * kv;
- if (kvs == NULL || key == NULL) {
+ if (evhtp_unlikely(kvs == NULL || key == NULL)) {
return NULL;
}
@@ -2576,7 +2602,7 @@
evhtp_kvs_find_kv(evhtp_kvs_t * kvs, const char * key) {
evhtp_kv_t * kv;
- if (kvs == NULL || key == NULL) {
+ if (evhtp_unlikely(kvs == NULL || key == NULL)) {
return NULL;
}
@@ -2591,7 +2617,7 @@
void
evhtp_kvs_add_kv(evhtp_kvs_t * kvs, evhtp_kv_t * kv) {
- if (kvs == NULL || kv == NULL) {
+ if (evhtp_unlikely(kvs == NULL || kv == NULL)) {
return;
}
@@ -2607,7 +2633,10 @@
evhtp_kv_t * kv;
TAILQ_FOREACH(kv, src, next) {
- evhtp_kvs_add_kv(dst, evhtp_kv_new(kv->key, kv->val, kv->k_heaped, kv->v_heaped));
+ evhtp_kvs_add_kv(dst, evhtp_kv_new(kv->key,
+ kv->val,
+ kv->k_heaped,
+ kv->v_heaped));
}
}
@@ -2740,7 +2769,6 @@
unsigned char ch;
size_t i;
-
if (len > (SIZE_MAX - (len + 2))) {
return NULL;
}
@@ -2758,15 +2786,11 @@
char * key_buf;
char * val_buf;
- if (!(key_buf = malloc(len + 1))) {
- return NULL;
- }
+ key_buf = malloc(len + 1);
+ evhtp_alloc_assert(key_buf);
- if (!(val_buf = malloc(len + 1))) {
- evhtp_safe_free(key_buf, free);
-
- return NULL;
- }
+ val_buf = malloc(len + 1);
+ evhtp_alloc_assert(val_buf);
#endif
for (i = 0; i < len; i++) {
@@ -2981,7 +3005,8 @@
evhtp_query_t *
evhtp_parse_query(const char * query, size_t len) {
- return evhtp_parse_query_wflags(query, len, EVHTP_PARSE_QUERY_FLAG_STRICT);
+ return evhtp_parse_query_wflags(query, len,
+ EVHTP_PARSE_QUERY_FLAG_STRICT);
}
void
@@ -2998,7 +3023,8 @@
}
bufferevent_write_buffer(c->bev, reply_buf);
- evbuffer_free(reply_buf);
+ evbuffer_drain(reply_buf, -1);
+ /* evbuffer_free(reply_buf); */
}
void
@@ -3030,7 +3056,8 @@
}
bufferevent_write_buffer(evhtp_connection_get_bev(c), reply_buf);
- evbuffer_free(reply_buf);
+ evbuffer_drain(reply_buf, -1);
+ /* evbuffer_free(reply_buf); */
}
int
@@ -3067,8 +3094,10 @@
*/
evhtp_kv_rm_and_free(request->headers_out, content_len);
+#if 0
evhtp_headers_add_header(request->headers_out,
evhtp_header_new("Content-Length", "0", 0, 0));
+#endif
request->chunked = 1;
break;
@@ -3114,12 +3143,12 @@
evhtp_send_reply_chunk(evhtp_request_t * request, evbuf_t * buf) {
evbuf_t * output;
- output = bufferevent_get_output(request->conn->bev);
-
if (evbuffer_get_length(buf) == 0) {
return;
}
+ output = bufferevent_get_output(request->conn->bev);
+
if (request->chunked == 1) {
evbuffer_add_printf(output, "%x\r\n",
(unsigned)evbuffer_get_length(buf));
@@ -3146,8 +3175,7 @@
void
evhtp_unbind_socket(evhtp_t * htp) {
- evconnlistener_free(htp->server);
- htp->server = NULL;
+ evhtp_safe_free(htp->server, evconnlistener_free);
}
int
@@ -3155,26 +3183,50 @@
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#endif
+ evutil_socket_t fd;
+ int on = 1;
- htp->server = evconnlistener_new_bind(htp->evbase, _evhtp_accept_cb, (void *)htp,
- LEV_OPT_THREADSAFE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
- backlog, sa, sin_len);
- if (!htp->server) {
- return -1;
+ fd = socket(sa->sa_family, SOCK_STREAM, 0);
+ evhtp_errno_assert(fd != -1);
+
+ evutil_make_socket_closeonexec(fd);
+ evutil_make_socket_nonblocking(fd);
+
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
+
+ if (sa->sa_family == AF_INET6) {
+ int rc;
+
+ rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+ evhtp_errno_assert(rc != -1);
}
-#ifdef USE_DEFER_ACCEPT
- {
- evutil_socket_t sock;
- int one = 1;
-
- sock = evconnlistener_get_fd(htp->server);
-
- setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, (ev_socklen_t)sizeof(one));
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, (ev_socklen_t)sizeof(one));
+#if defined SO_REUSEPORT
+ if (htp->enable_reuseport) {
+ setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on));
}
#endif
+#if defined TCP_NODELAY
+ if (htp->enable_nodelay == 1) {
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on));
+ }
+#endif
+
+#if defined TCP_DEFER_ACCEPT
+ if (htp->enable_defer_accept == 1) {
+ setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, (void *)&on, sizeof(on));
+ }
+#endif
+
+ evhtp_errno_assert(bind(fd, sa, sin_len) != -1);
+
+ htp->server = evconnlistener_new(htp->evbase, _evhtp_accept_cb, htp,
+ LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
+ backlog, fd);
+ evhtp_errno_assert(htp->server != NULL);
+
#ifndef EVHTP_DISABLE_SSL
if (htp->ssl_ctx != NULL) {
/* if ssl is enabled and we have virtual hosts, set our servername
@@ -3190,7 +3242,7 @@
#endif
return 0;
-}
+} /* evhtp_bind_sockaddr */
int
evhtp_bind_socket(evhtp_t * htp, const char * baddr, uint16_t port, int backlog) {
@@ -3273,9 +3325,8 @@
evhtp_callback_new(const char * path, evhtp_callback_type type, evhtp_callback_cb cb, void * arg) {
evhtp_callback_t * hcb;
- if (!(hcb = calloc(sizeof(evhtp_callback_t), 1))) {
- return NULL;
- }
+ hcb = calloc(sizeof(evhtp_callback_t), 1);
+ evhtp_alloc_assert(hcb);
hcb->type = type;
hcb->cb = cb;
@@ -3318,7 +3369,7 @@
switch (callback->type) {
case evhtp_callback_type_hash:
- free(callback->val.path);
+ evhtp_safe_free(callback->val.path, free);
break;
case evhtp_callback_type_glob:
evhtp_safe_free(callback->val.glob, free);
@@ -3326,7 +3377,7 @@
#ifndef EVHTP_DISABLE_REGEX
case evhtp_callback_type_regex:
regfree(callback->val.regex);
- free(callback->val.regex);
+ evhtp_safe_free(callback->val.regex, free);
break;
#endif
}
@@ -3417,7 +3468,6 @@
(*hooks)->on_event_arg = arg;
break;
default:
-
return -1;
} /* switch */
@@ -3530,6 +3580,19 @@
return hcb;
}
+evhtp_callback_t *
+evhtp_get_cb(evhtp_t * htp, const char * path) {
+ evhtp_callback_t * callback;
+
+ TAILQ_FOREACH(callback, htp->callbacks, next) {
+ if (strcmp(callback->val.path, path) == 0) {
+ return callback;
+ }
+ }
+
+ return NULL;
+}
+
#ifndef EVHTP_DISABLE_EVTHR
static void
_evhtp_thread_init(evthr_t * thr, void * arg) {
@@ -3718,6 +3781,8 @@
htp->ssl_cfg = cfg;
htp->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ evhtp_alloc_assert(htp->ssl_ctx);
+
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
SSL_CTX_set_options(htp->ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
SSL_CTX_set_timeout(htp->ssl_ctx, cfg->ssl_ctx_timeout);
@@ -3890,22 +3955,31 @@
evhtp_connection_set_bev(request->conn, bev);
}
+void
+evhtp_request_set_keepalive(evhtp_request_t * request, int val) {
+ request->keepalive = (val > 0) ? 1 : 0;
+}
+
evhtp_connection_t *
evhtp_request_get_connection(evhtp_request_t * request) {
return request->conn;
}
+evhtp_proto
+evhtp_request_get_proto(evhtp_request_t * request) {
+ return request->proto;
+}
+
inline void
evhtp_connection_set_timeouts(evhtp_connection_t * c,
const struct timeval * rtimeo,
const struct timeval * wtimeo) {
- if (!c) {
+ if (evhtp_unlikely(c == NULL)) {
return;
}
- if (rtimeo || wtimeo) {
- bufferevent_set_timeouts(c->bev, rtimeo, wtimeo);
- }
+
+ bufferevent_set_timeouts(c->bev, rtimeo, wtimeo);
}
void
@@ -3924,16 +3998,17 @@
void
evhtp_connection_free(evhtp_connection_t * connection) {
- if (connection == NULL) {
+ if (evhtp_unlikely(connection == NULL)) {
return;
}
_evhtp_connection_fini_hook(connection);
- evhtp_safe_free(connection->request, _evhtp_request_free);
+ evhtp_safe_free(connection->request, _evhtp_request_free);
evhtp_safe_free(connection->parser, free);
evhtp_safe_free(connection->hooks, free);
evhtp_safe_free(connection->saddr, free);
+ evhtp_safe_free(connection->scratch_buf, evbuffer_free);
if (connection->resume_ev) {
evhtp_safe_free(connection->resume_ev, event_free);
@@ -3953,10 +4028,6 @@
#endif
}
- if (connection->ratelimit_cfg != NULL) {
- ev_token_bucket_cfg_free(connection->ratelimit_cfg);
- }
-
evhtp_safe_free(connection, free);
} /* evhtp_connection_free */
@@ -4011,7 +4082,7 @@
evhtp_add_alias(evhtp_t * evhtp, const char * name) {
evhtp_alias_t * alias;
- if (evhtp == NULL || name == NULL) {
+ if (evhtp_unlikely(evhtp == NULL || name == NULL)) {
return -1;
}
@@ -4020,6 +4091,7 @@
}
alias->alias = strdup(name);
+ evhtp_alloc_assert(alias->alias);
TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
@@ -4081,17 +4153,18 @@
evhtp_new(evbase_t * evbase, void * arg) {
evhtp_t * htp;
- if (evbase == NULL) {
- return NULL;
- }
+ evhtp_assert(evbase != NULL);
- if (!(htp = calloc(sizeof(evhtp_t), 1))) {
- return NULL;
- }
+ htp = calloc(sizeof(evhtp_t), 1);
+ evhtp_alloc_assert(htp);
- htp->arg = arg;
- htp->evbase = evbase;
- htp->bev_flags = BEV_OPT_CLOSE_ON_FREE;
+ htp->arg = arg;
+ htp->evbase = evbase;
+ htp->bev_flags = BEV_OPT_CLOSE_ON_FREE;
+
+ /* default to lenient argument parsing */
+ htp->parser_flags = EVHTP_PARSE_QUERY_FLAG_LENIENT;
+
TAILQ_INIT(&htp->vhosts);
TAILQ_INIT(&htp->aliases);
@@ -4123,19 +4196,20 @@
#endif
if (evhtp->server_name) {
- free(evhtp->server_name);
+ evhtp_safe_free(evhtp->server_name, free);
}
if (evhtp->callbacks) {
- evhtp_callbacks_free(evhtp->callbacks);
+ evhtp_safe_free(evhtp->callbacks, evhtp_callbacks_free);
}
TAILQ_FOREACH_SAFE(evhtp_alias, &evhtp->aliases, next, tmp) {
if (evhtp_alias->alias != NULL) {
- free(evhtp_alias->alias);
+ evhtp_safe_free(evhtp_alias->alias, free);
}
+
TAILQ_REMOVE(&evhtp->aliases, evhtp_alias, next);
- free(evhtp_alias);
+ evhtp_safe_free(evhtp_alias, free);
}
#ifndef EVHTP_DISABLE_SSL
@@ -4144,32 +4218,9 @@
}
#endif
- free(evhtp);
+ evhtp_safe_free(evhtp, free);
} /* evhtp_free */
-int
-evhtp_connection_set_rate_limit(evhtp_connection_t * conn,
- size_t read_rate, size_t read_burst,
- size_t write_rate, size_t write_burst,
- const struct timeval * tick) {
- struct ev_token_bucket_cfg * tcfg;
-
- if (conn == NULL || conn->bev == NULL) {
- return -1;
- }
-
- tcfg = ev_token_bucket_cfg_new(read_rate, read_burst,
- write_rate, write_burst, tick);
-
- if (tcfg == NULL) {
- return -1;
- }
-
- conn->ratelimit_cfg = tcfg;
-
- return bufferevent_set_rate_limit(conn->bev, tcfg);
-}
-
/*****************************************************************
* client request functions *
*****************************************************************/
@@ -4185,9 +4236,7 @@
evhtp_connection_t * conn;
int err;
- if (evbase == NULL) {
- return NULL;
- }
+ evhtp_assert(evbase != NULL);
if (!(conn = _evhtp_connection_new(NULL, -1, evhtp_type_client))) {
return NULL;
@@ -4251,9 +4300,7 @@
evhtp_connection_t * conn;
struct sockaddr_in sin;
- if (evbase == NULL) {
- return NULL;
- }
+ evhtp_assert(evbase != NULL);
if (!(conn = _evhtp_connection_new(NULL, -1, evhtp_type_client))) {
return NULL;
@@ -4265,10 +4312,10 @@
conn->ssl = SSL_new(ctx);
conn->evbase = evbase;
- conn->bev = bufferevent_openssl_socket_new(evbase, -1, conn->ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
+ conn->bev = bufferevent_openssl_socket_new(evbase, -1, conn->ssl,
+ BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
bufferevent_enable(conn->bev, EV_READ);
-
bufferevent_setcb(conn->bev, NULL, NULL,
_evhtp_connection_eventcb, conn);
@@ -4286,9 +4333,8 @@
evhtp_request_new(evhtp_callback_cb cb, void * arg) {
evhtp_request_t * r;
- if (!(r = _evhtp_request_new(NULL))) {
- return NULL;
- }
+ r = _evhtp_request_new(NULL);
+ evhtp_alloc_assert(r);
r->cb = cb;
r->cbarg = arg;
@@ -4322,6 +4368,9 @@
evhtp_headers_for_each(r->headers_out, _evhtp_create_headers, obuf);
evbuffer_add_reference(obuf, "\r\n", 2, NULL, NULL);
+ if (evbuffer_get_length(r->buffer_out)) {
+ evbuffer_add_buffer(obuf, r->buffer_out);
+ }
return 0;
}
@@ -4329,5 +4378,4 @@
unsigned int
evhtp_request_status(evhtp_request_t * r) {
return htparser_get_status(r->conn->parser);
-}
-
+}
\ No newline at end of file
diff --git a/evhtp.h b/evhtp.h
index ddc4996..1f0cdaa 100644
--- a/evhtp.h
+++ b/evhtp.h
@@ -1,16 +1,9 @@
+#include <evhtp-config.h>
+
#ifndef __EVHTP__H__
#define __EVHTP__H__
-#include <evhtp-config.h>
-
-#ifndef EVHTP_EXPORT
-# if (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER || defined __clang__
-# define EVHTP_EXPORT __attribute__ ((visibility("default")))
-# else
-# define EVHTP_EXPORT
-# endif
-#endif
-
+/** @file */
#ifndef EVHTP_DISABLE_EVTHR
#include <evthr.h>
#endif
@@ -38,6 +31,26 @@
extern "C" {
#endif
+#ifdef EVHTP_DEBUG
+#define __QUOTE(x) # x
+#define _QUOTE(x) __QUOTE(x)
+#define htp_debug_strlen(x) strlen(x)
+
+#define htp_log_debug(fmt, ...) do { \
+ time_t t = time(NULL); \
+ struct tm * dm = localtime(&t); \
+ \
+ fprintf(stdout, "[%02d:%02d:%02d] evhtp.c:[" _QUOTE(__LINE__) "]\t %-26s: " \
+ fmt "\n", dm->tm_hour, dm->tm_min, dm->tm_sec, __func__, ## __VA_ARGS__); \
+ fflush(stdout); \
+} while (0)
+
+#else
+#define htp_debug_strlen(x) 0
+#define htp_log_debug(fmt, ...) do {} while (0)
+#endif
+
+
#ifndef EVHTP_DISABLE_SSL
typedef SSL_SESSION evhtp_ssl_sess_t;
typedef SSL evhtp_ssl_t;
@@ -184,10 +197,10 @@
typedef void * (* evhtp_ssl_scache_init)(evhtp_t *);
#endif
-#define EVHTP_VERSION "1.2.10"
+#define EVHTP_VERSION "1.2.11"
#define EVHTP_VERSION_MAJOR 1
#define EVHTP_VERSION_MINOR 2
-#define EVHTP_VERSION_PATCH 10
+#define EVHTP_VERSION_PATCH 11
#define evhtp_headers_iterator evhtp_kvs_iterator
@@ -198,6 +211,7 @@
#define EVHTP_RES_DATA_TOO_LONG 4
#define EVHTP_RES_OK 200
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define EVHTP_RES_100 100
#define EVHTP_RES_CONTINUE 100
#define EVHTP_RES_SWITCH_PROTO 101
@@ -253,6 +267,7 @@
#define EVHTP_RES_GWTIMEOUT 504
#define EVHTP_RES_VERNSUPPORT 505
#define EVHTP_RES_BWEXEED 509
+#endif
struct evhtp_defaults_s {
evhtp_callback_cb cb;
@@ -273,28 +288,33 @@
* @brief main structure containing all configuration information
*/
struct evhtp_s {
- evhtp_t * parent; /**< only when this is a vhost */
- evbase_t * evbase; /**< the initialized event_base */
- evserv_t * server; /**< the libevent listener struct */
- char * server_name; /**< the name included in Host: responses */
- void * arg; /**< user-defined evhtp_t specific arguments */
- int bev_flags; /**< bufferevent flags to use on bufferevent_*_socket_new() */
+ evhtp_t * parent; /**< only when this is a vhost */
+ evbase_t * evbase; /**< the initialized event_base */
+ evserv_t * server; /**< the libevent listener struct */
+ char * server_name; /**< the name included in Host: responses */
+ void * arg; /**< user-defined evhtp_t specific arguments */
+ int bev_flags; /**< bufferevent flags to use on bufferevent_*_socket_new() */
uint64_t max_body_size;
uint64_t max_keepalive_requests;
- int disable_100_cont; /**< if set, evhtp will not respond to Expect: 100-continue */
- int parser_flags; /**< default query flags to alter 'strictness' (see EVHTP_PARSE_QUERY_FLAG_*) */
+ uint8_t disable_100_cont : 1, /**< if set, evhtp will not respond to Expect: 100-continue */
+ enable_reuseport : 1,
+ enable_nodelay : 1,
+ enable_defer_accept : 1,
+ pad : 4;
+
+ int parser_flags; /**< default query flags to alter 'strictness' (see EVHTP_PARSE_QUERY_FLAG_*) */
#ifndef EVHTP_DISABLE_SSL
- evhtp_ssl_ctx_t * ssl_ctx; /**< if ssl enabled, this is the servers CTX */
+ evhtp_ssl_ctx_t * ssl_ctx; /**< if ssl enabled, this is the servers CTX */
evhtp_ssl_cfg_t * ssl_cfg;
#endif
#ifndef EVHTP_DISABLE_EVTHR
- evthr_pool_t * thr_pool; /**< connection threadpool */
+ evthr_pool_t * thr_pool; /**< connection threadpool */
#endif
#ifndef EVHTP_DISABLE_EVTHR
- pthread_mutex_t * lock; /**< parent lock for add/del cbs in threads */
+ pthread_mutex_t * lock; /**< parent lock for add/del cbs in threads */
evhtp_thread_init_cb thread_init_cb;
void * thread_init_cbarg;
#endif
@@ -438,7 +458,9 @@
evhtp_t * htp;
evbase_t * evbase;
evbev_t * bev;
- evthr_t * thread;
+#ifndef EVHTP_DISABLE_EVTHR
+ evthr_t * thread;
+#endif
#ifndef EVHTP_DISABLE_SSL
evhtp_ssl_t * ssl;
#endif
@@ -446,26 +468,26 @@
htparser * parser;
event_t * resume_ev;
struct sockaddr * saddr;
- struct timeval recv_timeo; /**< conn read timeouts (overrides global) */
- struct timeval send_timeo; /**< conn write timeouts (overrides global) */
+ struct timeval recv_timeo; /**< conn read timeouts (overrides global) */
+ struct timeval send_timeo; /**< conn write timeouts (overrides global) */
evutil_socket_t sock;
- evhtp_request_t * request; /**< the request currently being processed */
+ evhtp_request_t * request; /**< the request currently being processed */
uint64_t max_body_size;
uint64_t body_bytes_read;
uint64_t num_requests;
- evhtp_type type; /**< server or client */
+ evhtp_type type; /**< server or client */
uint8_t error : 1,
- owner : 1, /**< set to 1 if this structure owns the bufferevent */
- vhost_via_sni : 1, /**< set to 1 if the vhost was found via SSL SNI */
- paused : 1, /**< this connection has been marked as paused */
- connected : 1, /**< client specific - set after successful connection */
- waiting : 1, /**< used to make sure resuming happens AFTER sending a reply */
+ owner : 1, /**< set to 1 if this structure owns the bufferevent */
+ vhost_via_sni : 1, /**< set to 1 if the vhost was found via SSL SNI */
+ paused : 1, /**< this connection has been marked as paused */
+ connected : 1, /**< client specific - set after successful connection */
+ waiting : 1, /**< used to make sure resuming happens AFTER sending a reply */
free_connection : 1,
- keepalive : 1; /**< set to 1 after the first request has been processed and the connection is kept open */
- struct ev_token_bucket_cfg * ratelimit_cfg; /**< connection-specific ratelimiting configuration. */
+ keepalive : 1; /**< set to 1 after the first request has been processed and the connection is kept open */
+ struct evbuffer * scratch_buf; /**< always zero'd out after used */
#ifdef EVHTP_FUTURE_USE
- TAILQ_HEAD(, evhtp_request_s) pending; /**< client pending data */
+ TAILQ_HEAD(, evhtp_request_s) pending; /**< client pending data */
#endif
};
@@ -609,7 +631,29 @@
* @param arg user-defined argument passed to the callback
*/
EVHTP_EXPORT void evhtp_set_gencb(evhtp_t * htp, evhtp_callback_cb cb, void * arg);
+
+
+/**
+ * @brief call a user-defined function before the connection is accepted.
+ *
+ * @param htp
+ * @param evhtp_pre_accept_cb
+ * @param arg
+ *
+ * @return
+ */
EVHTP_EXPORT void evhtp_set_pre_accept_cb(evhtp_t * htp, evhtp_pre_accept_cb, void * arg);
+
+
+/**
+ * @brief call a user-defined function right after a connection is accepted.
+ *
+ * @param htp
+ * @param evhtp_post_accept_cb
+ * @param arg
+ *
+ * @return
+ */
EVHTP_EXPORT void evhtp_set_post_accept_cb(evhtp_t * htp, evhtp_post_accept_cb, void * arg);
/**
@@ -626,7 +670,6 @@
evhtp_callback_cb cb, void * arg);
-
/**
* @brief sets a callback to be executed based on a regex pattern
*
@@ -659,6 +702,34 @@
EVHTP_EXPORT evhtp_callback_t * evhtp_set_glob_cb(evhtp_t * htp, const char * pattern,
evhtp_callback_cb cb, void * arg);
+
+/**
+ * @brief attempts to find the callback matching the exact string 'needle'. This is useful
+ * in cases where we want to get the original handle, but is not in scope.
+ *
+ * with pattern based callbacks, this does not attempt to find a callback that would
+ * match the string if the pattern matcher was executed.
+ *
+ * Meaning:
+ * evhtp_set_glob_cb(htp, "/foo/bar*", ....);
+ *
+ * Calling
+ * evhtp_get_cb(htp, "/foo/bar/baz");
+ *
+ * Will return NULL since it's not the exact pattern set
+ *
+ * Calling
+ * evhtp_get_cb(htp, "/foo/bar*");
+ *
+ * Is the correct usage.
+ *
+ * @param htp
+ * @param needle
+ *
+ * @return NULL if callback is not not found
+ */
+EVHTP_EXPORT evhtp_callback_t * evhtp_get_cb(evhtp_t * htp, const char * needle);
+
/**
* @brief sets a callback hook for either a connection or a path/regex .
*
@@ -932,7 +1003,6 @@
*/
EVHTP_EXPORT void evhtp_kvs_free(evhtp_kvs_t * kvs);
-
/**
* @brief free's resources associated with 'kv' if ONLY found within the key/value list
*
@@ -941,7 +1011,6 @@
*/
EVHTP_EXPORT void evhtp_kv_rm_and_free(evhtp_kvs_t * kvs, evhtp_kv_t * kv);
-
/**
* @brief find the string value of 'key' from the key/value list 'kvs'
*
@@ -1120,7 +1189,8 @@
*
* @return htp_method enum
*/
-EVHTP_EXPORT htp_method evhtp_request_get_method(evhtp_request_t * r);
+EVHTP_EXPORT htp_method evhtp_request_get_method(evhtp_request_t * r);
+EVHTP_EXPORT evhtp_proto evhtp_request_get_proto(evhtp_request_t * r);
/* the following functions all do the same thing, pause and the processing */
EVHTP_EXPORT void evhtp_connection_pause(evhtp_connection_t * connection);
@@ -1236,6 +1306,7 @@
* @param len
*/
EVHTP_EXPORT void evhtp_request_set_max_body_size(evhtp_request_t * request, uint64_t len);
+EVHTP_EXPORT void evhtp_request_set_keepalive(evhtp_request_t * request, int val);
/**
* @brief sets a maximum number of requests that a single connection can make.
@@ -1246,26 +1317,6 @@
EVHTP_EXPORT void evhtp_set_max_keepalive_requests(evhtp_t * htp, uint64_t num);
-/**
- * @brief set a bufferevent ratelimit on a evhtp_connection_t structure. The
- * logic is the same as libevent's rate-limiting code.
- *
- * @param c
- * @param read_rate
- * @param read_burst
- * @param write_rate
- * @param write_burst
- * @param tick
- *
- * @return
- */
-EVHTP_EXPORT int
-evhtp_connection_set_ratelimit(evhtp_connection_t * c,
- size_t read_rate, size_t read_burst,
- size_t write_rate,
- size_t write_burst,
- const struct timeval * tick);
-
/*****************************************************************
* client request functions *
*****************************************************************/
@@ -1273,8 +1324,7 @@
/**
* @brief allocate a new connection
*/
-EVHTP_EXPORT evhtp_connection_t *
-evhtp_connection_new_dns(evbase_t * evbase,
+EVHTP_EXPORT evhtp_connection_t * evhtp_connection_new_dns(evbase_t * evbase,
struct evdns_base * dns_base,
const char * addr, uint16_t port);
@@ -1284,8 +1334,8 @@
EVHTP_EXPORT evhtp_connection_t *
evhtp_connection_new(evbase_t * evbase, const char * addr, uint16_t port);
-#ifndef DISABLE_SSL
-evhtp_connection_t * evhtp_connection_ssl_new(evbase_t * evbase, const char * addr, uint16_t port, evhtp_ssl_ctx_t * ctx);
+#ifndef EVHTP_DISABLE_SSL
+EVHTP_EXPORT evhtp_connection_t * evhtp_connection_ssl_new(evbase_t * evbase, const char * addr, uint16_t port, evhtp_ssl_ctx_t * ctx);
#endif
diff --git a/evhtp.pc.in b/evhtp.pc.in
index 8ca3523..a7b351f 100644
--- a/evhtp.pc.in
+++ b/evhtp.pc.in
@@ -1,6 +1,6 @@
prefix=@CMAKE_INSTALL_PREFIX@
libdir=@LIB_INSTALL_DIR@
-includedir=@INCLUDE_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@/evhtp
Name: libevhtp
Description: A more flexible replacement for libevent's httpd API
diff --git a/evhtp_numtoa.c b/evhtp_numtoa.c
index 6ccfb89..05dd466 100644
--- a/evhtp_numtoa.c
+++ b/evhtp_numtoa.c
@@ -42,8 +42,6 @@
return (size_t)(wstr - str);
}
-EXPORT_SYMBOL(evhtp_modp_u64toa);
-
size_t
evhtp_modp_u32toa(uint32_t value, char * str) {
char * wstr = str;
@@ -61,8 +59,6 @@
return (size_t)(wstr - str);
}
-EXPORT_SYMBOL(evhtp_modp_u32toa);
-
inline size_t
evhtp_modp_sizetoa(size_t value, char * str) {
#if EVHTP_SYS_ARCH == 64
@@ -74,4 +70,3 @@
#endif
}
-EXPORT_SYMBOL(evhtp_modp_sizetoa);
diff --git a/evhtp_numtoa.h b/evhtp_numtoa.h
index de295a4..21ace95 100644
--- a/evhtp_numtoa.h
+++ b/evhtp_numtoa.h
@@ -5,6 +5,8 @@
extern "C" {
#endif
+#include "evhtp-config.h"
+
/**
* @brief based on the system architecture, convert a size_t
* number to a string.
@@ -14,7 +16,7 @@
*
* @return
*/
-size_t evhtp_modp_sizetoa(size_t value, char * str);
+EVHTP_EXPORT size_t evhtp_modp_sizetoa(size_t value, char * str);
/**
* @brief converts uint32_t value to string
@@ -24,7 +26,7 @@
*
* @return
*/
-size_t evhtp_modp_u32toa(uint32_t value, char * str);
+EVHTP_EXPORT size_t evhtp_modp_u32toa(uint32_t value, char * str);
/**
@@ -35,7 +37,7 @@
*
* @return
*/
-size_t evhtp_modp_u64toa(uint64_t value, char * str);
+EVHTP_EXPORT size_t evhtp_modp_u64toa(uint64_t value, char * str);
#define evhtp_modp_uchartoa(_val) (unsigned char)('0' + _val)
diff --git a/evthr/evthr.c b/evthr.c
similarity index 78%
rename from evthr/evthr.c
rename to evthr.c
index 486c469..4511544 100644
--- a/evthr/evthr.c
+++ b/evthr.c
@@ -29,11 +29,15 @@
uint8_t stop;
void * args;
evthr_cb cb;
-};
+} __attribute__((packed));
TAILQ_HEAD(evthr_pool_slist, evthr);
struct evthr_pool {
+#ifdef EVTHR_SHARED_PIPE
+ int rdr;
+ int wdr;
+#endif
int nthreads;
evthr_pool_slist_t threads;
};
@@ -45,23 +49,20 @@
ev_t * event;
evbase_t * evbase;
pthread_mutex_t lock;
- pthread_mutex_t rlock;
pthread_t * thr;
evthr_init_cb init_cb;
void * arg;
void * aux;
+#ifdef EVTHR_SHARED_PIPE
+ int pool_rdr;
+ struct event * shared_pool_ev;
+#endif
TAILQ_ENTRY(evthr) next;
};
-static inline int
-_evthr_read(evthr_t * thr, evthr_cmd_t * cmd, evutil_socket_t sock) {
- if (recv(sock, cmd, sizeof(evthr_cmd_t), 0) != sizeof(evthr_cmd_t)) {
- return 0;
- }
-
- return 1;
-}
+#define _evthr_read(thr, cmd, sock) \
+ (recv(sock, cmd, sizeof(evthr_cmd_t), 0) == sizeof(evthr_cmd_t)) ? 1 : 0
static void
_evthr_read_cmd(evutil_socket_t sock, short which, void * args) {
@@ -73,24 +74,17 @@
return;
}
- pthread_mutex_lock(&thread->rlock);
-
stopped = 0;
- while (_evthr_read(thread, &cmd, sock) == 1) {
- if (cmd.stop == 1) {
- stopped = 1;
- break;
- }
+ if (evhtp_likely(_evthr_read(thread, &cmd, sock) == 1)) {
+ stopped = cmd.stop;
- if (cmd.cb != NULL) {
+ if (evhtp_likely(cmd.cb != NULL)) {
(cmd.cb)(thread, cmd.args, thread->arg);
}
}
- pthread_mutex_unlock(&thread->rlock);
-
- if (stopped == 1) {
+ if (evhtp_unlikely(stopped == 1)) {
event_base_loopbreak(thread->evbase);
}
@@ -115,6 +109,14 @@
event_add(thread->event, NULL);
+#ifdef EVTHR_SHARED_PIPE
+ if (thread->pool_rdr > 0) {
+ thread->shared_pool_ev = event_new(thread->evbase, thread->pool_rdr,
+ EV_READ | EV_PERSIST, _evthr_read_cmd, args);
+ event_add(thread->shared_pool_ev, NULL);
+ }
+#endif
+
pthread_mutex_lock(&thread->lock);
if (thread->init_cb != NULL) {
@@ -130,46 +132,35 @@
}
pthread_exit(NULL);
-}
+} /* _evthr_loop */
evthr_res
evthr_defer(evthr_t * thread, evthr_cb cb, void * arg) {
- evthr_cmd_t cmd;
-
-
- cmd.cb = cb;
- cmd.args = arg;
- cmd.stop = 0;
-
- pthread_mutex_lock(&thread->rlock);
+ evthr_cmd_t cmd = {
+ .cb = cb,
+ .args = arg,
+ .stop = 0
+ };
if (send(thread->wdr, &cmd, sizeof(cmd), 0) <= 0) {
- pthread_mutex_unlock(&thread->rlock);
return EVTHR_RES_RETRY;
}
- pthread_mutex_unlock(&thread->rlock);
-
return EVTHR_RES_OK;
}
evthr_res
evthr_stop(evthr_t * thread) {
- evthr_cmd_t cmd;
+ evthr_cmd_t cmd = {
+ .cb = NULL,
+ .args = NULL,
+ .stop = 1
+ };
- /* cmd.magic = _EVTHR_MAGIC; */
- cmd.cb = NULL;
- cmd.args = NULL;
- cmd.stop = 1;
-
- pthread_mutex_lock(&thread->rlock);
-
- if (write(thread->wdr, &cmd, sizeof(evthr_cmd_t)) < 0) {
- pthread_mutex_unlock(&thread->rlock);
+ if (send(thread->wdr, &cmd, sizeof(evthr_cmd_t), 0) < 0) {
return EVTHR_RES_RETRY;
}
- pthread_mutex_unlock(&thread->rlock);
pthread_join(*thread->thr, NULL);
return EVTHR_RES_OK;
}
@@ -216,11 +207,6 @@
return NULL;
}
- if (pthread_mutex_init(&thread->rlock, NULL)) {
- evthr_free(thread);
- return NULL;
- }
-
return thread;
} /* evthr_new */
@@ -302,6 +288,19 @@
evthr_res
evthr_pool_defer(evthr_pool_t * pool, evthr_cb cb, void * arg) {
+#ifdef EVTHR_SHARED_PIPE
+ evthr_cmd_t cmd = {
+ .cb = cb,
+ .args = arg,
+ .stop = 0
+ };
+
+ if (evhtp_unlikely(send(pool->wdr, &cmd, sizeof(cmd), 0) == -1)) {
+ return EVTHR_RES_RETRY;
+ }
+
+ return EVTHR_RES_OK;
+#else
evthr_t * thr = NULL;
if (pool == NULL) {
@@ -319,6 +318,7 @@
return evthr_defer(thr, cb, arg);
+#endif
} /* evthr_pool_defer */
evthr_pool_t *
@@ -326,6 +326,10 @@
evthr_pool_t * pool;
int i;
+#ifdef EVTHR_SHARED_PIPE
+ int fds[2];
+#endif
+
if (nthreads == 0) {
return NULL;
}
@@ -337,6 +341,18 @@
pool->nthreads = nthreads;
TAILQ_INIT(&pool->threads);
+#ifdef EVTHR_SHARED_PIPE
+ if (evutil_socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == -1) {
+ return NULL;
+ }
+
+ evutil_make_socket_nonblocking(fds[0]);
+ evutil_make_socket_nonblocking(fds[1]);
+
+ pool->rdr = fds[0];
+ pool->wdr = fds[1];
+#endif
+
for (i = 0; i < nthreads; i++) {
evthr_t * thread;
@@ -345,11 +361,15 @@
return NULL;
}
+#ifdef EVTHR_SHARED_PIPE
+ thread->pool_rdr = fds[0];
+#endif
+
TAILQ_INSERT_TAIL(&pool->threads, thread, next);
}
return pool;
-}
+} /* evthr_pool_new */
int
evthr_pool_start(evthr_pool_t * pool) {
@@ -370,16 +390,3 @@
return 0;
}
-EXPORT_SYMBOL(evthr_new);
-EXPORT_SYMBOL(evthr_get_base);
-EXPORT_SYMBOL(evthr_set_aux);
-EXPORT_SYMBOL(evthr_get_aux);
-EXPORT_SYMBOL(evthr_start);
-EXPORT_SYMBOL(evthr_stop);
-EXPORT_SYMBOL(evthr_defer);
-EXPORT_SYMBOL(evthr_free);
-EXPORT_SYMBOL(evthr_pool_new);
-EXPORT_SYMBOL(evthr_pool_start);
-EXPORT_SYMBOL(evthr_pool_stop);
-EXPORT_SYMBOL(evthr_pool_defer);
-EXPORT_SYMBOL(evthr_pool_free);
diff --git a/evthr.h b/evthr.h
new file mode 100644
index 0000000..978fbae
--- /dev/null
+++ b/evthr.h
@@ -0,0 +1,56 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#ifndef __EVTHR_H__
+#define __EVTHR_H__
+
+#include <pthread.h>
+#include <event2/event.h>
+#include <evhtp-config.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum evthr_res {
+ EVTHR_RES_OK = 0,
+ EVTHR_RES_BACKLOG,
+ EVTHR_RES_RETRY,
+ EVTHR_RES_NOCB,
+ EVTHR_RES_FATAL
+};
+
+struct evthr_pool;
+struct evthr;
+
+typedef struct event_base evbase_t;
+typedef struct event ev_t;
+
+typedef struct evthr_pool evthr_pool_t;
+typedef struct evthr evthr_t;
+typedef enum evthr_res evthr_res;
+
+typedef void (* evthr_cb)(evthr_t * thr, void * cmd_arg, void * shared);
+typedef void (* evthr_init_cb)(evthr_t * thr, void * shared);
+
+EVHTP_EXPORT evthr_t * evthr_new(evthr_init_cb init_cb, void * arg);
+EVHTP_EXPORT evbase_t * evthr_get_base(evthr_t * thr);
+EVHTP_EXPORT void evthr_set_aux(evthr_t * thr, void * aux);
+EVHTP_EXPORT void * evthr_get_aux(evthr_t * thr);
+EVHTP_EXPORT int evthr_start(evthr_t * evthr);
+EVHTP_EXPORT evthr_res evthr_stop(evthr_t * evthr);
+EVHTP_EXPORT evthr_res evthr_defer(evthr_t * evthr, evthr_cb cb, void * arg);
+EVHTP_EXPORT void evthr_free(evthr_t * evthr);
+
+EVHTP_EXPORT evthr_pool_t * evthr_pool_new(int nthreads, evthr_init_cb init_cb, void * shared);
+EVHTP_EXPORT int evthr_pool_start(evthr_pool_t * pool);
+EVHTP_EXPORT evthr_res evthr_pool_stop(evthr_pool_t * pool);
+EVHTP_EXPORT evthr_res evthr_pool_defer(evthr_pool_t * pool, evthr_cb cb, void * arg);
+EVHTP_EXPORT void evthr_pool_free(evthr_pool_t * pool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EVTHR_H__ */
+
diff --git a/evthr/Makefile b/evthr/Makefile
deleted file mode 100644
index 925356e..0000000
--- a/evthr/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-SRC = evthr.c
-OUT = libevthr.a
-OBJ = $(SRC:.c=.o)
-INCLUDES = -I.
-CFLAGS += -Wall -Wextra -ggdb
-LDFLAGS += -ggdb
-CC = gcc
-
-.SUFFIXES: .c
-
-default: $(OUT)
-
-.c.o:
- $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@
-
-$(OUT): $(OBJ)
- ar rcs $(OUT) $(OBJ)
-
-test: $(OUT) test.c
- $(CC) $(INCLUDES) $(CFLAGS) test.c -o test $(OUT) -levent -levent_pthreads -lpthread
-
-clean:
- rm -f $(OBJ) $(OUT) test
-
diff --git a/evthr/README b/evthr/README
deleted file mode 100644
index 5ce37cb..0000000
--- a/evthr/README
+++ /dev/null
@@ -1,53 +0,0 @@
-Libevthr is an API which manages threads and thread-pools in an event based
-manner. This API requires libevent with threading support.
-
-Libevthr works a bit differently than most thread management systems. Instead of
-conditional signalling and some type of pre-thread queue, Libevthr uses a
-deferral type mechanism. That is, a thread is always running, abstracted to a
-point where you "defer" your function *into* a thread.
-
-For example you can start up a single thread with a backlog of 10 (a backlog
-being the max number of outstanding callbacks to run within the thread), and
-execute a function you would like to run inside the thread one or many times.
-The act of deferrals is non-blocking.
-
-Example Code for evthrs:
-
- evthr_t * thr = evthr_new(10, NULL);
-
- if (evthr_start(thr) < 0) {
- exit(1);
- }
-
- evthr_defer(thr, my_cb_1, NULL);
- evthr_defer(thr, my_cb_2, NULL);
- evthr_defer(thr, my_cb_3, NULL);
-
- sleep(n_seconds);
-
- evthr_stop(thr);
-
-Libevthr also has the ability to create pools using the same methods that a
-single evthr has. For example, if you would like to create 10 threads, each
-with a backlog of 5:
-
- evthr_pool_t * thr_pool = evthr_pool_new(10, 5, NULL);
-
- if (evthr_pool_start(thr_pool) < 0) {
- exit(1);
- }
-
- evthr_pool_defer(thr_pool, my_cb_1, NULL);
- evthr_pool_defer(thr_pool, my_cb_2, NULL);
- evthr_pool_defer(thr_pool, my_cb_3, NULL);
-
-Your callback functions which you defer must be of type "evthr_cb", or
-"void cb_name(void * arg, void * shared)". In this case, the "arg" variable is
-the data you passed as the third argument to either evthr_pool_defer, or
-evthr_defer. The "shared" variable is the data that was either the second
-variable in evthr_new(), or the third variable in evthr_pool_new().
-
-The gist of this is to allow a global dataset, along with deferred specific
-data.
-
-See test.c for a quick example.
diff --git a/evthr/evthr.h b/evthr/evthr.h
deleted file mode 100644
index c5ae91b..0000000
--- a/evthr/evthr.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-#ifndef __EVTHR_H__
-#define __EVTHR_H__
-
-#include <sched.h>
-#include <pthread.h>
-#include <sys/queue.h>
-#include <event2/event.h>
-#include <event2/thread.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum evthr_res {
- EVTHR_RES_OK = 0,
- EVTHR_RES_BACKLOG,
- EVTHR_RES_RETRY,
- EVTHR_RES_NOCB,
- EVTHR_RES_FATAL
-};
-
-struct evthr_pool;
-struct evthr;
-
-typedef struct event_base evbase_t;
-typedef struct event ev_t;
-
-typedef struct evthr_pool evthr_pool_t;
-typedef struct evthr evthr_t;
-typedef enum evthr_res evthr_res;
-
-typedef void (*evthr_cb)(evthr_t * thr, void * cmd_arg, void * shared);
-typedef void (*evthr_init_cb)(evthr_t * thr, void * shared);
-
-evthr_t * evthr_new(evthr_init_cb init_cb, void * arg);
-evbase_t * evthr_get_base(evthr_t * thr);
-void evthr_set_aux(evthr_t * thr, void * aux);
-void * evthr_get_aux(evthr_t * thr);
-int evthr_start(evthr_t * evthr);
-evthr_res evthr_stop(evthr_t * evthr);
-evthr_res evthr_defer(evthr_t * evthr, evthr_cb cb, void * arg);
-void evthr_free(evthr_t * evthr);
-
-evthr_pool_t * evthr_pool_new(int nthreads, evthr_init_cb init_cb, void * shared);
-int evthr_pool_start(evthr_pool_t * pool);
-evthr_res evthr_pool_stop(evthr_pool_t * pool);
-evthr_res evthr_pool_defer(evthr_pool_t * pool, evthr_cb cb, void * arg);
-void evthr_pool_free(evthr_pool_t * pool);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __EVTHR_H__ */
-
diff --git a/evthr/test.c b/evthr/test.c
deleted file mode 100644
index 8f762df..0000000
--- a/evthr/test.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <evthr.h>
-
-static void
-_test_cb_1(evthr_t * thr, void * cmdarg, void * shared) {
- printf("START _test_cb_1 (%u)\n", (unsigned int)pthread_self());
- sleep(1);
- printf("END _test_cb_1 (%u)\n", (unsigned int)pthread_self());
-}
-
-int
-main(int argc, char ** argv) {
- evthr_pool_t * pool = NULL;
- int i = 0;
-
- pool = evthr_pool_new(8, NULL, NULL);
-
- evthr_pool_start(pool);
-
- while (1) {
- if (i++ >= 5) {
- break;
- }
-
- printf("Iter %d\n", i);
-
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
-
- sleep(2);
- }
-
- evthr_pool_stop(pool);
- evthr_pool_free(pool);
-
- pool = evthr_pool_new(2, NULL, NULL);
- i = 0;
-
- evthr_pool_set_max_backlog(pool, 1);
- evthr_pool_start(pool);
-
- while (1) {
- if (i++ >= 5) {
- break;
- }
-
- printf("Iter %d\n", i);
-
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- printf("%d\n", evthr_pool_defer(pool, _test_cb_1, "derp"));
- }
-
- evthr_pool_stop(pool);
- evthr_pool_free(pool);
-
- return 0;
-} /* main */
-
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..dc820cb
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_custom_target(examples)
+
+add_executable(test EXCLUDE_FROM_ALL test.c)
+add_executable(test_basic EXCLUDE_FROM_ALL test_basic.c)
+add_executable(test_vhost EXCLUDE_FROM_ALL test_vhost.c)
+add_executable(test_client EXCLUDE_FROM_ALL test_client.c)
+add_executable(test_query EXCLUDE_FROM_ALL test_query.c)
+add_executable(test_perf EXCLUDE_FROM_ALL test_perf.c)
+
+if (NOT EVHTP_DISABLE_EVTHR)
+ add_executable(test_proxy EXCLUDE_FROM_ALL test_proxy.c)
+ target_link_libraries(test_proxy evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+endif()
+
+target_link_libraries(test evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+target_link_libraries(test_basic evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+target_link_libraries(test_vhost evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+target_link_libraries(test_client evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+target_link_libraries(test_query evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+target_link_libraries(test_perf evhtp ${LIBEVHTP_EXTERNAL_LIBS} ${SYS_LIBS})
+
+add_dependencies(examples test test_basic test_vhost test_client test_proxy test_query test_perf)
+
+
diff --git a/examples/test.c b/examples/test.c
index 5dd919b..dd385e4 100644
--- a/examples/test.c
+++ b/examples/test.c
@@ -6,9 +6,12 @@
#include <errno.h>
#include <signal.h>
#include <inttypes.h>
-#include <evhtp.h>
#include <event2/event.h>
+#include "../evhtp-internal.h"
+#include "../evhtp.h"
+
+
#ifndef EVHTP_DISABLE_EVTHR
int use_threads = 0;
int num_threads = 0;
@@ -21,6 +24,7 @@
char * ssl_capath = NULL;
size_t bw_limit = 0;
uint64_t max_keepalives = 0;
+int backlog = 1024;
struct pauser {
event_t * timer_ev;
@@ -409,7 +413,7 @@
#endif
-const char * optstr = "htn:a:p:r:s:c:C:l:N:m:";
+const char * optstr = "htn:a:p:r:s:c:C:l:N:m:b:";
const char * help =
"Options: \n"
@@ -478,6 +482,9 @@
case 'm':
max_keepalives = atoll(optarg);
break;
+ case 'b':
+ backlog = atoll(optarg);
+ break;
default:
printf("Unknown opt %s\n", optarg);
return -1;
@@ -498,8 +505,6 @@
event_base_loopexit(data, NULL);
}
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
int
main(int argc, char ** argv) {
struct event * ev_sigint;
@@ -531,32 +536,54 @@
evbase = event_base_new();
htp = evhtp_new(evbase, NULL);
- htp->parser_flags = EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS;
+ evhtp_set_parser_flags(htp, EVHTP_PARSE_QUERY_FLAG_LENIENT);
evhtp_set_max_keepalive_requests(htp, max_keepalives);
- cb_1 = evhtp_set_cb(htp, "/ref", test_default_cb, "fjdkls");
- cb_2 = evhtp_set_cb(htp, "/foo", test_foo_cb, "bar");
- cb_3 = evhtp_set_cb(htp, "/foo/", test_foo_cb, "bar");
- cb_4 = evhtp_set_cb(htp, "/bar", test_bar_cb, "baz");
- cb_5 = evhtp_set_cb(htp, "/500", test_500_cb, "500");
+ /* htp->enable_nodelay = 1; */
+ /* htp->enable_defer_accept = 1; */
+ htp->enable_reuseport = 1;
+
+ cb_1 = evhtp_set_cb(htp, "/ref", test_default_cb, "fjdkls");
+ evhtp_assert(cb_1 != NULL);
+
+ cb_2 = evhtp_set_cb(htp, "/foo", test_foo_cb, "bar");
+ evhtp_assert(cb_2 != NULL);
+
+ cb_3 = evhtp_set_cb(htp, "/foo/", test_foo_cb, "bar");
+ evhtp_assert(cb_3 != NULL);
+
+ cb_4 = evhtp_set_cb(htp, "/bar", test_bar_cb, "baz");
+ evhtp_assert(cb_4 != NULL);
+
+ cb_5 = evhtp_set_cb(htp, "/500", test_500_cb, "500");
+ evhtp_assert(cb_5 != NULL);
+
#ifndef EVHTP_DISABLE_REGEX
- cb_6 = evhtp_set_regex_cb(htp, "^(/anything/).*", test_regex, NULL);
+ cb_6 = evhtp_set_regex_cb(htp, "^(/anything/).*", test_regex, NULL);
+ evhtp_assert(cb_6 != NULL);
#endif
- cb_7 = evhtp_set_cb(htp, "/pause", test_pause_cb, NULL);
+ cb_7 = evhtp_set_cb(htp, "/pause", test_pause_cb, NULL);
+ evhtp_assert(cb_7 != NULL);
#ifndef EVHTP_DISABLE_REGEX
- cb_8 = evhtp_set_regex_cb(htp, "^/create/(.*)", create_callback, NULL);
+ cb_8 = evhtp_set_regex_cb(htp, "^/create/(.*)", create_callback, NULL);
+ evhtp_assert(cb_8 != NULL);
#endif
- cb_9 = evhtp_set_glob_cb(htp, "*/glob/*", test_glob_cb, NULL);
- cb_10 = evhtp_set_cb(htp, "/max_body_size", test_max_body, NULL);
+ cb_9 = evhtp_set_glob_cb(htp, "*/glob/*", test_glob_cb, NULL);
+ evhtp_assert(cb_9 != NULL);
+
+ cb_10 = evhtp_set_cb(htp, "/max_body_size", test_max_body, NULL);
+ evhtp_assert(cb_10 != NULL);
/* set a callback to test out chunking API */
- cb_11 = evhtp_set_cb(htp, "/chunkme", test_chunking, NULL);
+ cb_11 = evhtp_set_cb(htp, "/chunkme", test_chunking, NULL);
+ evhtp_assert(cb_11 != NULL);
/* set a callback which takes ownership of the underlying bufferevent and
* just starts echoing things
*/
- cb_12 = evhtp_set_cb(htp, "/ownme", test_ownership, NULL);
+ cb_12 = evhtp_set_cb(htp, "/ownme", test_ownership, NULL);
+ evhtp_assert(cb_12 != NULL);
/* set a callback to pause on each header for cb_7 */
evhtp_set_hook(&cb_7->hooks, evhtp_hook_on_path, pause_init_cb, NULL);
@@ -621,7 +648,7 @@
}
#endif
- if (evhtp_bind_socket(htp, bind_addr, bind_port, 2046) < 0) {
+ if (evhtp_bind_socket(htp, bind_addr, bind_port, backlog) < 0) {
fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
exit(-1);
}
@@ -640,4 +667,3 @@
return 0;
} /* main */
-#pragma GCC diagnostic pop
diff --git a/examples/test_basic.c b/examples/test_basic.c
index 64a8e26..96d02d5 100644
--- a/examples/test_basic.c
+++ b/examples/test_basic.c
@@ -9,10 +9,31 @@
testcb(evhtp_request_t * req, void * a) {
const char * str = a;
- evbuffer_add_printf(req->buffer_out, "%s", str);
+ evbuffer_add(req->buffer_out, str, strlen(str));
evhtp_send_reply(req, EVHTP_RES_OK);
}
+void
+issue161cb(evhtp_request_t * req, void * a) {
+ struct evbuffer * b = evbuffer_new();
+
+ if (evhtp_request_get_proto(req) == EVHTP_PROTO_10) {
+ evhtp_request_set_keepalive(req, 0);
+ }
+
+ evhtp_send_reply_start(req, EVHTP_RES_OK);
+
+ evbuffer_add(b, "foo", 3);
+ evhtp_send_reply_body(req, b);
+
+ evbuffer_add(b, "bar\n\n", 5);
+ evhtp_send_reply_body(req, b);
+
+ evhtp_send_reply_end(req);
+
+ evbuffer_free(b);
+}
+
int
main(int argc, char ** argv) {
evbase_t * evbase = event_base_new();
@@ -21,12 +42,11 @@
evhtp_set_cb(htp, "/simple/", testcb, "simple");
evhtp_set_cb(htp, "/1/ping", testcb, "one");
evhtp_set_cb(htp, "/1/ping.json", testcb, "two");
-#if 0
+ evhtp_set_cb(htp, "/issue161", issue161cb, NULL);
#ifndef EVHTP_DISABLE_EVTHR
- evhtp_use_threads(htp, NULL, 4, NULL);
+ evhtp_use_threads(htp, NULL, 8, NULL);
#endif
-#endif
- evhtp_bind_socket(htp, "0.0.0.0", 8081, 1024);
+ evhtp_bind_socket(htp, "0.0.0.0", 8081, 2048);
event_base_loop(evbase, 0);
diff --git a/htparse/test.c b/examples/test_htparse.c
similarity index 100%
rename from htparse/test.c
rename to examples/test_htparse.c
diff --git a/examples/test_perf.c b/examples/test_perf.c
new file mode 100644
index 0000000..707de17
--- /dev/null
+++ b/examples/test_perf.c
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <signal.h>
+#include <inttypes.h>
+
+#include "../evhtp-internal.h"
+#include "../evhtp.h"
+
+static int num_threads = 0;
+static char * baddr = "127.0.0.1";
+static uint16_t bport = 8081;
+static int backlog = 1024;
+static int nodelay = 0;
+static int defer_accept = 0;
+static int reuse_port = 0;
+static size_t payload_sz = 100;
+
+static void
+response_cb(evhtp_request_t * r, void * a) {
+ evbuffer_add_reference(r->buffer_out,
+ (const char *)a, payload_sz, NULL, NULL);
+
+ evhtp_send_reply(r, EVHTP_RES_OK);
+}
+
+int
+main(int argc, char ** argv) {
+ extern char * optarg;
+ extern int optind;
+ extern int opterr;
+ extern int optopt;
+ int c;
+
+ while ((c = getopt(argc, argv, "t:a:p:b:ndrs:")) != -1) {
+ switch (c) {
+ case 't':
+ num_threads = atoi(optarg);
+ break;
+ case 'a':
+ baddr = strdup(optarg);
+ break;
+ case 'p':
+ bport = atoi(optarg);
+ break;
+ case 'b':
+ backlog = atoll(optarg);
+ case 'n':
+ nodelay = 1;
+ break;
+ case 'd':
+ defer_accept = 1;
+ break;
+ case 'r':
+ reuse_port = 1;
+ break;
+ case 's':
+ payload_sz = atoll(optarg);
+ break;
+ default:
+ fprintf(stdout, "Usage: %s [flags]\n", argv[0]);
+ fprintf(stdout, " -t <n> : number of worker threads [Default: %d]\n", num_threads);
+ fprintf(stdout, " -a <s> : bind address [Default: %s]\n", baddr);
+ fprintf(stdout, " -p <n> : bind port [Default: %d]\n", bport);
+ fprintf(stdout, " -b <b> : listen backlog [Default: %d]\n", backlog);
+ fprintf(stdout, " -s <n> : size of the response [Default: %zu]\n", payload_sz);
+ fprintf(stdout, " -n : disable nagle (nodelay) [Default: %s]\n", nodelay ? "true" : "false");
+ fprintf(stdout, " -d : enable deferred accept [Default: %s]\n", defer_accept ? "true" : "false");
+ fprintf(stdout, " -r : enable linux reuseport [Default: %s]\n", reuse_port ? "true" : "false");
+ exit(EXIT_FAILURE);
+ } /* switch */
+ }
+
+ {
+ struct event_base * evbase;
+ evhtp_t * htp;
+ char payload[payload_sz];
+
+ evbase = event_base_new();
+ evhtp_alloc_assert(evbase);
+
+ htp = evhtp_new(evbase, NULL);
+ evhtp_alloc_assert(htp);
+
+ evhtp_set_parser_flags(htp, EVHTP_PARSE_QUERY_FLAG_LENIENT);
+
+ htp->enable_nodelay = nodelay;
+ htp->enable_defer_accept = defer_accept;
+ htp->enable_reuseport = reuse_port;
+
+ memset(payload, 0x42, payload_sz);
+
+ evhtp_assert(evhtp_set_cb(htp, "/data", response_cb, payload));
+
+#ifndef EVHTP_DISABLE_EVTHR
+ if (num_threads > 0) {
+ evhtp_assert(evhtp_use_threads(htp, NULL, num_threads, NULL) != -1);
+ }
+#endif
+
+ evhtp_errno_assert(evhtp_bind_socket(htp, baddr, bport, backlog) >= 0);
+ event_base_loop(evbase, 0);
+ }
+
+
+ return 0;
+} /* main */
+
diff --git a/examples/test_query.c b/examples/test_query.c
index fe4adc2..7c21726 100644
--- a/examples/test_query.c
+++ b/examples/test_query.c
@@ -133,7 +133,7 @@
{ NULL, NULL },
} },
{ "hexa%z=some", 0, {
- { "hexa\%%z", "some" },
+ { "hexa%z", "some" },
{ NULL, NULL },
} },
{ "aaa=some\%az", 1 },
diff --git a/examples/v6_v4.c b/examples/v6_v4.c
new file mode 100644
index 0000000..367c3a7
--- /dev/null
+++ b/examples/v6_v4.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "evhtp-internal.h"
+#include "evhtp.h"
+
+static void
+_req_cb(evhtp_request_t * req, void * arg) {
+ const char * ver = (const char *)arg;
+
+ evbuffer_add(req->buffer_out, ver, strlen(ver));
+ evhtp_send_reply(req, EVHTP_RES_OK);
+}
+
+int
+main(int argc, char ** argv) {
+ struct event_base * evbase;
+ evhtp_t * htp_v6;
+ evhtp_t * htp_v4;
+ int rc;
+
+ evbase = event_base_new();
+ evhtp_alloc_assert(evbase);
+
+ htp_v6 = evhtp_new(evbase, NULL);
+ evhtp_alloc_assert(htp_v6);
+
+ htp_v4 = evhtp_new(evbase, NULL);
+ evhtp_alloc_assert(htp_v4);
+
+ evhtp_set_gencb(htp_v6, _req_cb, (void *)"ipv6");
+ evhtp_set_gencb(htp_v4, _req_cb, (void *)"ipv4");
+
+ rc = evhtp_bind_socket(htp_v6, "ipv6:::/128", 9090, 1024);
+ evhtp_errno_assert(rc != -1);
+
+ rc = evhtp_bind_socket(htp_v4, "ipv4:0.0.0.0", 9090, 1024);
+ evhtp_errno_assert(rc != -1);
+
+ event_base_loop(evbase, 0);
+
+ return 0;
+} /* main */
\ No newline at end of file
diff --git a/htparse/htparse.c b/htparse.c
similarity index 86%
rename from htparse/htparse.c
rename to htparse.c
index 51c9017..d4bcf3e 100644
--- a/htparse/htparse.c
+++ b/htparse.c
@@ -308,8 +308,8 @@
uint64_t value;
/* Trim whitespace after value. */
- while (n && isblank(str[n-1])) {
- n--;
+ while (n && isblank(str[n - 1])) {
+ n--;
}
if (n > 20) {
@@ -328,7 +328,7 @@
check = value * 10 + (*str - '0');
- if ((value && check <= value) || check > UINT64_MAX) {
+ if ((value && check <= value)) {
*err = 1;
return 0;
}
@@ -500,8 +500,7 @@
}
static int
-is_host_char(unsigned char ch)
-{
+is_host_char(unsigned char ch) {
char c = (unsigned char)(ch | 0x20);
if (c >= 'a' && c <= 'z') {
@@ -515,6 +514,95 @@
return 0;
}
+static htp_method
+get_method(const char * m, const size_t sz) {
+ switch (sz) {
+ case 3:
+ if (_str3_cmp(m, 'G', 'E', 'T', '\0')) {
+ return htp_method_GET;
+ }
+
+ if (_str3_cmp(m, 'P', 'U', 'T', '\0')) {
+ return htp_method_PUT;
+ }
+
+ break;
+ case 4:
+ if (m[1] == 'O') {
+ if (_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
+ return htp_method_POST;
+ }
+
+ if (_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
+ return htp_method_COPY;
+ }
+
+ if (_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
+ return htp_method_MOVE;
+ }
+
+ if (_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
+ return htp_method_LOCK;
+ }
+ } else {
+ if (_str4cmp(m, 'H', 'E', 'A', 'D')) {
+ return htp_method_HEAD;
+ }
+ }
+
+ break;
+ case 5:
+ if (_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
+ return htp_method_MKCOL;
+ }
+
+ if (_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
+ return htp_method_TRACE;
+ }
+
+ if (_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
+ return htp_method_PATCH;
+ }
+
+ break;
+ case 6:
+ if (_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
+ return htp_method_DELETE;
+ }
+
+ if (_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
+ return htp_method_UNLOCK;
+ }
+
+ break;
+ case 7:
+ if (_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', '\0')) {
+ return htp_method_OPTIONS;
+ }
+
+ if (_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', '\0')) {
+ return htp_method_CONNECT;
+ }
+
+ break;
+ case 8:
+ if (_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) {
+ return htp_method_PROPFIND;
+ }
+
+ break;
+
+ case 9:
+ if (_str9cmp(m, 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) {
+ return htp_method_PROPPATCH;
+ }
+
+ break;
+ } /* switch */
+
+ return htp_method_UNKNOWN;
+} /* get_method */
+
size_t
htparser_run(htparser * p, htparse_hooks * hooks, const char * data, size_t len) {
unsigned char ch;
@@ -547,23 +635,6 @@
case s_start:
htparse_log_debug("[%p] s_start", p);
- p->flags = 0;
- p->error = htparse_error_none;
- p->method = htp_method_UNKNOWN;
- p->multipart = 0;
- p->major = 0;
- p->minor = 0;
- p->content_len = 0;
- p->orig_content_len = 0;
- p->status = 0;
- p->status_count = 0;
- p->scheme_offset = NULL;
- p->host_offset = NULL;
- p->port_offset = NULL;
- p->path_offset = NULL;
- p->args_offset = NULL;
-
-
if (ch == CR || ch == LF) {
break;
}
@@ -573,12 +644,30 @@
return i + 1;
}
+
+ p->flags = 0;
+ p->error = htparse_error_none;
+ p->method = htp_method_UNKNOWN;
+ p->multipart = 0;
+ p->major = 0;
+ p->minor = 0;
+ p->content_len = 0;
+ p->orig_content_len = 0;
+ p->status = 0;
+ p->status_count = 0;
+ p->scheme_offset = NULL;
+ p->host_offset = NULL;
+ p->port_offset = NULL;
+ p->path_offset = NULL;
+ p->args_offset = NULL;
+
+
res = hook_on_msg_begin_run(p, hooks);
p->buf[p->buf_idx++] = ch;
p->buf[p->buf_idx] = '\0';
- if (p->type == htp_type_request) {
+ if (evhtp_likely(p->type == htp_type_request)) {
p->state = s_method;
} else if (p->type == htp_type_response && ch == 'H') {
p->state = s_http_H;
@@ -597,119 +686,32 @@
case s_method:
htparse_log_debug("[%p] s_method", p);
- if (ch == ' ') {
- char * m = p->buf;
+ do {
+ if (ch == ' ') {
+ p->method = get_method(p->buf, p->buf_idx);
+ res = hook_method_run(p, hooks, p->buf, p->buf_idx);
- switch (p->buf_idx) {
- case 3:
- if (_str3_cmp(m, 'G', 'E', 'T', '\0')) {
- p->method = htp_method_GET;
- break;
- }
+ p->buf_idx = 0;
+ p->state = s_spaces_before_uri;
- if (_str3_cmp(m, 'P', 'U', 'T', '\0')) {
- p->method = htp_method_PUT;
- break;
- }
+ if (res) {
+ p->error = htparse_error_user;
+ return i + 1;
+ }
- break;
- case 4:
- if (m[1] == 'O') {
- if (_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
- p->method = htp_method_POST;
- break;
- }
+ break;
+ } else {
+ if ((ch < 'A' || ch > 'Z') && ch != '_') {
+ p->error = htparse_error_inval_method;
+ return i + 1;
+ }
- if (_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
- p->method = htp_method_COPY;
- break;
- }
-
- if (_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
- p->method = htp_method_MOVE;
- break;
- }
-
- if (_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
- p->method = htp_method_LOCK;
- break;
- }
- } else {
- if (_str4cmp(m, 'H', 'E', 'A', 'D')) {
- p->method = htp_method_HEAD;
- break;
- }
- }
- break;
- case 5:
- if (_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
- p->method = htp_method_MKCOL;
- break;
- }
-
- if (_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
- p->method = htp_method_TRACE;
- break;
- }
-
- if (_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
- p->method = htp_method_PATCH;
- break;
- }
- break;
- case 6:
- if (_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
- p->method = htp_method_DELETE;
- break;
- }
-
- if (_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
- p->method = htp_method_UNLOCK;
- break;
- }
- break;
- case 7:
- if (_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', '\0')) {
- p->method = htp_method_OPTIONS;
- }
-
- if (_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', '\0')) {
- p->method = htp_method_CONNECT;
- }
- break;
- case 8:
- if (_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) {
- p->method = htp_method_PROPFIND;
- }
-
- break;
-
- case 9:
- if (_str9cmp(m, 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) {
- p->method = htp_method_PROPPATCH;
- }
- break;
- } /* switch */
-
- res = hook_method_run(p, hooks, p->buf, p->buf_idx);
- p->buf_idx = 0;
- p->state = s_spaces_before_uri;
-
- if (res) {
- p->error = htparse_error_user;
- return i + 1;
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
}
- break;
- }
-
- if ((ch < 'A' || ch > 'Z') && ch != '_') {
- p->error = htparse_error_inval_method;
- return i + 1;
- }
-
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
+ ch = data[++i];
+ } while (i < len);
break;
case s_spaces_before_uri:
@@ -724,27 +726,27 @@
*/
if (p->method == htp_method_CONNECT) {
switch (ch) {
- case ' ':
- break;
- case '[':
- /* Literal IPv6 address start. */
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
- p->host_offset = &p->buf[p->buf_idx];
+ case ' ':
+ break;
+ case '[':
+ /* Literal IPv6 address start. */
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
+ p->host_offset = &p->buf[p->buf_idx];
- p->state = s_host_ipv6;
- break;
- default:
- if (!is_host_char(ch)) {
- p->error = htparse_error_inval_reqline;
- return i + 1;
- }
- p->host_offset = &p->buf[p->buf_idx];
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
+ p->state = s_host_ipv6;
+ break;
+ default:
+ if (!is_host_char(ch)) {
+ p->error = htparse_error_inval_reqline;
+ return i + 1;
+ }
+ p->host_offset = &p->buf[p->buf_idx];
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
- p->state = s_host;
- break;
+ p->state = s_host;
+ break;
} /* switch */
break;
@@ -878,6 +880,7 @@
p->state = s_host_ipv6;
break;
}
+
if (is_host_char(ch)) {
p->buf[p->buf_idx++] = ch;
p->buf[p->buf_idx] = '\0';
@@ -885,6 +888,7 @@
}
res = hook_host_run(p, hooks, p->host_offset, (&p->buf[p->buf_idx] - p->host_offset));
+
if (res) {
p->error = htparse_error_user;
return i + 1;
@@ -1080,15 +1084,20 @@
break;
case s_check_uri:
- htparse_log_debug("[%p] s_check_uri", p);
res = 0;
- if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
- break;
- }
+ do {
+ htparse_log_debug("[%p] s_check_uri", p);
+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
+ } else {
+ break;
+ }
+
+ ch = data[++i];
+ } while (i < len);
switch (ch) {
case ' ':
@@ -1158,11 +1167,16 @@
res = 0;
- if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
- break;
- }
+ do {
+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
+ } else {
+ break;
+ }
+
+ ch = data[++i];
+ } while (i < len);
switch (ch) {
case ' ':
@@ -1327,7 +1341,7 @@
case s_minor_digit:
switch (ch) {
case ' ':
- if (p->type == htp_type_request) {
+ if (evhtp_likely(p->type == htp_type_request)) {
p->state = s_spaces_after_digit;
} else if (p->type == htp_type_response) {
p->state = s_status;
@@ -1481,9 +1495,8 @@
case s_hdrline_hdr_key:
htparse_log_debug("[%p] s_hdrline_hdr_key", p);
- res = 0;
- switch (ch) {
- case ':':
+ do {
+ if (evhtp_unlikely(ch == ':')) {
res = hook_hdr_key_run(p, hooks, p->buf, p->buf_idx);
/* figure out if the value of this header is valueable */
@@ -1522,28 +1535,39 @@
break;
} /* switch */
- p->buf_idx = 0;
- p->state = s_hdrline_hdr_space_before_val;
+ p->buf_idx = 0;
+ p->state = s_hdrline_hdr_space_before_val;
+
+ if (res) {
+ p->error = htparse_error_user;
+ return i + 1;
+ }
break;
- case CR:
- p->state = s_hdrline_hdr_almost_done;
- break;
- case LF:
- p->state = s_hdrline_hdr_done;
- break;
- default:
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
- break;
- } /* switch */
+ }
- if (res) {
- p->error = htparse_error_user;
- return i + 1;
- }
+ switch (ch) {
+ case CR:
+ p->state = s_hdrline_hdr_almost_done;
+ break;
+ case LF:
+ p->state = s_hdrline_hdr_done;
+ break;
+ default:
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
+ break;
+ }
+
+ if (p->state != s_hdrline_hdr_key) {
+ break;
+ }
+
+ ch = data[++i];
+ } while (i < len);
break;
+
case s_hdrline_hdr_space_before_val:
htparse_log_debug("[%p] s_hdrline_hdr_space_before_val", p);
@@ -1580,17 +1604,22 @@
} /* switch */
break;
case s_hdrline_hdr_val:
- htparse_log_debug("[%p] s_hdrline_hdr_val", p);
err = 0;
res = 0;
- switch (ch) {
- case CR:
+ do {
+ htparse_log_debug("[%p] s_hdrline_hdr_val", p);
+ if (ch == CR) {
switch (p->heval) {
case eval_hdr_val_none:
break;
case eval_hdr_val_hostname:
- res = hook_hostname_run(p, hooks, p->buf, p->buf_idx);
+ if (hook_hostname_run(p, hooks, p->buf, p->buf_idx)) {
+ p->state = s_hdrline_hdr_almost_done;
+ p->error = htparse_error_user;
+ return i + 1;
+ }
+
break;
case eval_hdr_val_content_length:
p->content_len = str_to_uint64(p->buf, p->buf_idx, &err);
@@ -1606,14 +1635,21 @@
break;
case eval_hdr_val_connection:
switch (p->buf[0]) {
+ char A_case;
+ char C_case;
+ const char * S_buf;
+
case 'K':
case 'k':
if (p->buf_idx != 10) {
break;
}
- if (_str9cmp((p->buf + 1),
- 'e', 'e', 'p', '-', 'A', 'l', 'i', 'v', 'e')) {
+ A_case = (p->buf[5] == 'A') ? 'A' : 'a';
+ S_buf = (const char *)(p->buf + 1);
+
+ if (_str9cmp(S_buf,
+ 'e', 'e', 'p', '-', A_case, 'l', 'i', 'v', 'e')) {
p->flags |= parser_flag_connection_keep_alive;
}
break;
@@ -1623,7 +1659,10 @@
break;
}
- if (_str5cmp(p->buf, 'c', 'l', 'o', 's', 'e')) {
+ C_case = (p->buf[0] == 'C') ? 'C' : 'c';
+ S_buf = (const char *)p->buf;
+
+ if (_str5cmp(S_buf, C_case, 'l', 'o', 's', 'e')) {
p->flags |= parser_flag_connection_close;
}
break;
@@ -1635,13 +1674,17 @@
}
switch (p->buf[0]) {
+ const char * S_buf;
+
case 'c':
case 'C':
if (p->buf_idx != 7) {
break;
}
- if (_str6cmp((p->buf + 1), 'h', 'u', 'n', 'k', 'e', 'd')) {
+ S_buf = (const char *)(p->buf + 1);
+
+ if (_str6cmp(S_buf, 'h', 'u', 'n', 'k', 'e', 'd')) {
p->flags |= parser_flag_chunked;
}
@@ -1655,9 +1698,13 @@
}
switch (p->buf[0]) {
+ const char * S_buf;
+
case 'm':
case 'M':
- if (_str8cmp((p->buf + 1), 'u', 'l', 't', 'i', 'p', 'a', 'r', 't')) {
+ S_buf = (const char *)(p->buf + 1);
+
+ if (_str8cmp(S_buf, 'u', 'l', 't', 'i', 'p', 'a', 'r', 't')) {
p->multipart = 1;
}
@@ -1670,22 +1717,28 @@
break;
} /* switch */
- p->state = s_hdrline_hdr_almost_done;
- break;
- case LF:
- /* LF before CR? invalid */
- p->error = htparse_error_inval_hdr;
- return i + 1;
- default:
- p->buf[p->buf_idx++] = ch;
- p->buf[p->buf_idx] = '\0';
- break;
- } /* switch */
+ p->state = s_hdrline_hdr_almost_done;
- if (res) {
- p->error = htparse_error_user;
- return i + 1;
- }
+ break;
+ }
+
+ switch (ch) {
+ case LF:
+ /* LF before CR? invalid */
+ p->error = htparse_error_inval_hdr;
+ return i + 1;
+ default:
+ p->buf[p->buf_idx++] = ch;
+ p->buf[p->buf_idx] = '\0';
+ break;
+ } /* switch */
+
+ if (p->state != s_hdrline_hdr_val) {
+ break;
+ }
+
+ ch = data[++i];
+ } while (i < len);
break;
case s_hdrline_hdr_almost_done:
@@ -1726,13 +1779,6 @@
return i + 1;
}
- res = hook_on_hdrs_complete_run(p, hooks);
-
- if (res) {
- p->error = htparse_error_user;
- return i + 1;
- }
-
break;
case LF:
/* got LFLF? is this valid? */
@@ -1759,7 +1805,7 @@
}
break;
- } /* switch */
+ } /* switch */
break;
case s_hdrline_almost_done:
htparse_log_debug("[%p] s_hdrline_almost_done", p);
@@ -1768,6 +1814,14 @@
switch (ch) {
case LF:
+ res = hook_on_hdrs_complete_run(p, hooks);
+
+ if (res) {
+ p->error = htparse_error_user;
+ return i + 1;
+ }
+
+
p->buf_idx = 0;
htparse_log_debug("[%p] HERE", p);
@@ -1793,7 +1847,7 @@
default:
p->error = htparse_error_inval_hdr;
return i + 1;
- } /* switch */
+ } /* switch */
if (res) {
p->error = htparse_error_user;
@@ -1968,35 +2022,14 @@
return i + 1;
} /* switch */
- /* If we successfully completed a request/response we return
- to caller, and leave it up to him to call us again if
- parsing should continue. */
- if (p->state == s_start) {
- return i + 1;
- }
- }
+ /* If we successfully completed a request/response we return
+ * to caller, and leave it up to him to call us again if
+ * parsing should continue. */
+ if (p->state == s_start) {
+ return i + 1;
+ }
+ } /* switch */
return i;
} /* htparser_run */
-EXPORT_SYMBOL(htparser_run);
-EXPORT_SYMBOL(htparser_should_keep_alive);
-EXPORT_SYMBOL(htparser_get_scheme);
-EXPORT_SYMBOL(htparser_get_method);
-EXPORT_SYMBOL(htparser_get_methodstr);
-EXPORT_SYMBOL(htparser_get_methodstr_m);
-EXPORT_SYMBOL(htparser_set_major);
-EXPORT_SYMBOL(htparser_set_minor);
-EXPORT_SYMBOL(htparser_get_major);
-EXPORT_SYMBOL(htparser_get_minor);
-EXPORT_SYMBOL(htparser_get_multipart);
-EXPORT_SYMBOL(htparser_get_status);
-EXPORT_SYMBOL(htparser_get_content_length);
-EXPORT_SYMBOL(htparser_get_content_pending);
-EXPORT_SYMBOL(htparser_get_total_bytes_read);
-EXPORT_SYMBOL(htparser_get_error);
-EXPORT_SYMBOL(htparser_get_strerror);
-EXPORT_SYMBOL(htparser_get_userdata);
-EXPORT_SYMBOL(htparser_set_userdata);
-EXPORT_SYMBOL(htparser_init);
-EXPORT_SYMBOL(htparser_new);
diff --git a/htparse/htparse.h b/htparse.h
similarity index 60%
rename from htparse/htparse.h
rename to htparse.h
index a2b7719..da2fd53 100644
--- a/htparse/htparse.h
+++ b/htparse.h
@@ -1,6 +1,12 @@
#ifndef __HTPARSE_H__
#define __HTPARSE_H__
+#include "evhtp-config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct htparser;
enum htp_type {
@@ -62,8 +68,8 @@
typedef enum htp_type htp_type;
typedef enum htpparse_error htpparse_error;
-typedef int (*htparse_hook)(htparser *);
-typedef int (*htparse_data_hook)(htparser *, const char *, size_t);
+typedef int (* htparse_hook)(htparser *);
+typedef int (* htparse_data_hook)(htparser *, const char *, size_t);
struct htparse_hooks {
@@ -88,27 +94,31 @@
};
-size_t htparser_run(htparser *, htparse_hooks *, const char *, size_t);
-int htparser_should_keep_alive(htparser * p);
-htp_scheme htparser_get_scheme(htparser *);
-htp_method htparser_get_method(htparser *);
-const char * htparser_get_methodstr(htparser *);
-const char * htparser_get_methodstr_m(htp_method);
-void htparser_set_major(htparser *, unsigned char);
-void htparser_set_minor(htparser *, unsigned char);
-unsigned char htparser_get_major(htparser *);
-unsigned char htparser_get_minor(htparser *);
-unsigned char htparser_get_multipart(htparser *);
-unsigned int htparser_get_status(htparser *);
-uint64_t htparser_get_content_length(htparser *);
-uint64_t htparser_get_content_pending(htparser *);
-uint64_t htparser_get_total_bytes_read(htparser *);
-htpparse_error htparser_get_error(htparser *);
-const char * htparser_get_strerror(htparser *);
-void * htparser_get_userdata(htparser *);
-void htparser_set_userdata(htparser *, void *);
-void htparser_init(htparser *, htp_type);
-htparser * htparser_new(void);
+EVHTP_EXPORT size_t htparser_run(htparser *, htparse_hooks *, const char *, size_t);
+EVHTP_EXPORT int htparser_should_keep_alive(htparser * p);
+EVHTP_EXPORT htp_scheme htparser_get_scheme(htparser *);
+EVHTP_EXPORT htp_method htparser_get_method(htparser *);
+EVHTP_EXPORT const char * htparser_get_methodstr(htparser *);
+EVHTP_EXPORT const char * htparser_get_methodstr_m(htp_method);
+EVHTP_EXPORT void htparser_set_major(htparser *, unsigned char);
+EVHTP_EXPORT void htparser_set_minor(htparser *, unsigned char);
+EVHTP_EXPORT unsigned char htparser_get_major(htparser *);
+EVHTP_EXPORT unsigned char htparser_get_minor(htparser *);
+EVHTP_EXPORT unsigned char htparser_get_multipart(htparser *);
+EVHTP_EXPORT unsigned int htparser_get_status(htparser *);
+EVHTP_EXPORT uint64_t htparser_get_content_length(htparser *);
+EVHTP_EXPORT uint64_t htparser_get_content_pending(htparser *);
+EVHTP_EXPORT uint64_t htparser_get_total_bytes_read(htparser *);
+EVHTP_EXPORT htpparse_error htparser_get_error(htparser *);
+EVHTP_EXPORT const char * htparser_get_strerror(htparser *);
+EVHTP_EXPORT void * htparser_get_userdata(htparser *);
+EVHTP_EXPORT void htparser_set_userdata(htparser *, void *);
+EVHTP_EXPORT void htparser_init(htparser *, htp_type);
+EVHTP_EXPORT htparser * htparser_new(void);
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/htparse/Makefile b/htparse/Makefile
deleted file mode 100644
index 205e947..0000000
--- a/htparse/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-SRC = htparse.c
-OUT = libhtparse.a
-OBJ = $(SRC:.c=.o)
-INCLUDES = -I.
-CFLAGS += -ggdb
-LDFLAGS +=
-CC = gcc
-
-.SUFFIXES: .c
-
-default: $(OUT) test
-
-.c.o:
- $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@
-
-$(OUT): $(OBJ)
- ar rcs $(OUT) $(OBJ)
-
-test: $(OUT) test.c
- $(CC) $(INCLUDES) $(CFLAGS) test.c -o test $(OUT)
-
-clean:
- rm -f $(OBJ) $(OUT) test
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000..25eac1c
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_custom_target(tools)
+
+add_executable(lambda-pp EXCLUDE_FROM_ALL lambda-pp.c)
+
+add_dependencies(tools lambda-pp)
diff --git a/tools/lambda-pp.c b/tools/lambda-pp.c
new file mode 100644
index 0000000..2ef8c25
--- /dev/null
+++ b/tools/lambda-pp.c
@@ -0,0 +1,684 @@
+/*
+* Copyright (C) 2014
+* Wolfgang Bumiller
+* Dale Weiler
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of
+* this software and associated documentation files (the "Software"), to deal in
+* the Software without restriction, including without limitation the rights to
+* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+* of the Software, and to permit persons to whom the Software is furnished to do
+* so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all
+* copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#define isalpha(a) ((((unsigned)(a)|32)-'a') < 26)
+#define isdigit(a) (((unsigned)(a)-'0') < 10)
+#define isalnum(a) (isalpha(a) || isdigit(a))
+#define isspace(a) (((a) >= '\t' && (a) <= '\r') || (a) == ' ')
+
+static const char *DefaultKeyword = "lambda";
+
+typedef struct {
+ size_t begin;
+ size_t length;
+} lambda_range_t;
+
+typedef struct {
+ size_t pos;
+ size_t line;
+} lambda_position_t;
+
+typedef struct {
+ const char *file;
+ char *data;
+ size_t length;
+ size_t line;
+ const char *keyword;
+ size_t keylength;
+ bool short_enabled;
+} lambda_source_t;
+
+typedef struct {
+ size_t start;
+ lambda_range_t decl;
+ lambda_range_t body;
+ size_t name_offset;
+ size_t decl_line;
+ size_t body_line;
+ size_t end_line;
+ bool is_short;
+} lambda_t;
+
+typedef struct {
+ union {
+ char *chars;
+ lambda_t *funcs;
+ lambda_position_t *positions;
+ };
+ size_t size;
+ size_t elements;
+ size_t length;
+} lambda_vector_t;
+
+typedef struct {
+ lambda_vector_t lambdas;
+ lambda_vector_t positions;
+} parse_data_t;
+
+typedef enum {
+ PARSE_NORMAL, PARSE_TYPE, PARSE_LAMBDA, PARSE_LAMBDA_EXPRESSION
+} parse_type_t;
+
+static size_t parse(lambda_source_t *source, parse_data_t *data, size_t j, parse_type_t parsetype, size_t *nameofs);
+
+/* Vector */
+static inline bool lambda_vector_init(lambda_vector_t *vec, size_t size) {
+ vec->length = 32;
+ vec->size = size;
+ vec->elements = 0;
+ return (vec->chars = (char *)malloc(vec->length * vec->size));
+}
+
+static inline void lambda_vector_destroy(lambda_vector_t *vec) {
+ free(vec->chars);
+}
+
+static inline bool lambda_vector_resize(lambda_vector_t *vec) {
+ if (vec->elements != vec->length)
+ return true;
+ vec->length <<= 1;
+ char *temp = realloc(vec->chars, vec->length * vec->size);
+ if (!temp)
+ return false;
+ vec->chars = temp;
+ return true;
+}
+
+static inline bool lambda_vector_push_char(lambda_vector_t *vec, char ch) {
+ if (!lambda_vector_resize(vec))
+ return false;
+ vec->chars[vec->elements++] = ch;
+ return true;
+}
+
+static inline bool lambda_vector_create_lambda(lambda_vector_t *vec, size_t *idx) {
+ if (!lambda_vector_resize(vec))
+ return false;
+ *idx = vec->elements++;
+ memset(&vec->funcs[*idx], 0, sizeof(lambda_t));
+ return true;
+}
+
+static inline bool lambda_vector_push_position(lambda_vector_t *vec, size_t pos, size_t line) {
+ if (!lambda_vector_resize(vec))
+ return false;
+ vec->positions[vec->elements].pos = pos;
+ vec->positions[vec->elements].line = line;
+ vec->elements++;
+ return true;
+}
+
+static inline void lambda_source_init(lambda_source_t *source) {
+ memset(source, 0, sizeof(*source));
+ source->keyword = DefaultKeyword;
+ source->short_enabled = true;
+}
+
+/* Source */
+static void parse_error(lambda_source_t *source, const char *message, ...) {
+ char buffer[2048];
+ va_list va;
+ va_start(va, message);
+ vsnprintf(buffer, sizeof(buffer), message, va);
+ va_end(va);
+ fprintf(stderr, "%s:%zu error: %s\n", source->file, source->line, buffer);
+ fflush(stderr);
+}
+
+static bool parse_open(lambda_source_t *source, FILE *handle) {
+ if (!handle)
+ return false;
+
+ source->line = 1;
+
+ if (fseek(handle, 0, SEEK_END) != -1) {
+ source->length = ftell(handle);
+ fseek(handle, 0, SEEK_SET);
+
+ if (!(source->data = (char *)malloc(source->length)))
+ goto parse_open_oom;
+ if (fread(source->data, source->length, 1, handle) != 1)
+ goto parse_open_failed;
+ }
+ else {
+ static const size_t bs = 4096;
+ source->length = 0;
+ if (!(source->data = (char*)malloc(bs)))
+ goto parse_open_oom;
+ while (true) {
+ size_t r = fread(source->data, 1, bs, handle);
+ source->length += r;
+ if (feof(handle))
+ break;
+ if (ferror(handle) && errno != EINTR)
+ goto parse_open_failed;
+ char *temp = (char*)realloc(source->data, source->length + bs);
+ if (!temp)
+ goto parse_open_oom;
+ source->data = temp;
+ }
+ }
+
+ fclose(handle);
+ return true;
+
+parse_open_oom:
+ parse_error(source, "out of memory");
+parse_open_failed:
+ free(source->data);
+ fclose(handle);
+ return false;
+}
+
+static inline void parse_close(lambda_source_t *source) {
+ free(source->data);
+}
+
+/* Parser */
+static inline size_t parse_skip_string(lambda_source_t *source, size_t i, char check) {
+ while (i != source->length) {
+ if (source->data[i] == check)
+ return i + 1;
+ else if (source->data[i] == '\\')
+ if (++i == source->length)
+ break;
+ ++i;
+ }
+ return i;
+}
+
+static inline size_t parse_skip_white(lambda_source_t *source, size_t i) {
+ while (i != source->length && isspace(source->data[i])) {
+ if (source->data[i] == '\n')
+ source->line++;
+ ++i;
+ }
+ return i;
+}
+
+static size_t parse_word(lambda_source_t *source, parse_data_t *data, size_t j, size_t i) {
+ if (j != i) {
+ if (strncmp(source->data + j, source->keyword, source->keylength) == 0)
+ return parse(source, data, i, PARSE_LAMBDA, false);
+ }
+ if (source->data[i] == '\n')
+ source->line++;
+ else if (!strncmp(source->data + i, "//", 2)) {
+ /* Single line comments */
+ i = strchr(source->data + i, '\n') - source->data;
+ } else if (!strncmp(source->data + i, "/*", 2)) {
+ /* Multi line comments */
+ i = strstr(source->data + i, "*/") - source->data;
+ }
+ return i;
+}
+
+#define ERROR ((size_t)-1)
+
+static size_t parse(lambda_source_t *source, parse_data_t *data, size_t i, parse_type_t parsetype, size_t *nameofs) {
+ lambda_vector_t parens;
+ size_t lambda = 0;
+ bool mark = (!parsetype && !nameofs);
+ size_t protopos = i;
+ bool protomove = true;
+ bool preprocessor = false;
+ bool expectbody = false;
+ bool movename = false;
+ /* 'mark' actually means this is the outer most call and we should
+ * remember where to put prototypes now!
+ * when protomove is true we move the protopos along whitespace so that
+ * the lambdas don't get stuck to the tail of hte previous functions.
+ * Also we need to put lambdas after #include lines so if we encounter
+ * a preprocessor directive we create another position marker starting
+ * at the nest new line
+ */
+
+ lambda_vector_init(&parens, sizeof(char));
+
+
+ if (parsetype == PARSE_LAMBDA) {
+ if (!lambda_vector_create_lambda(&data->lambdas, &lambda))
+ goto parse_oom;
+ lambda_t *l = &data->lambdas.funcs[lambda];
+ l->start = i - 6;
+ i = parse_skip_white(source, i);
+ l->decl.begin = i;
+ l->decl_line = source->line;
+ size_t ofs = 0;
+ if ((i = parse(source, data, i, PARSE_TYPE, &ofs)) == ERROR)
+ goto parse_error;
+ l->name_offset = ofs - l->decl.begin;
+ l->decl.length = i - l->decl.begin;
+ l->body.begin = i;
+ l->body_line = source->line;
+ i = parse_skip_white(source, i);
+ if (source->short_enabled) {
+ if (source->data[i] == '=' && source->data[i+1] == '>') {
+ l->body.begin = i += 2;
+ l->is_short = true;
+ parsetype = PARSE_LAMBDA_EXPRESSION;
+ }
+ }
+ }
+
+ size_t j = i;
+ while (i < source->length) {
+ if (mark && !parens.elements) {
+ if (protomove) {
+ if (isspace(source->data[i])) {
+ if (source->data[i] == '\n')
+ source->line++;
+ protopos = j = ++i;
+ continue;
+ }
+ protomove = false;
+ if (!lambda_vector_push_position(&data->positions, protopos, source->line))
+ goto parse_oom;
+ }
+
+ if (source->data[i] == ';') {
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ j = ++i;
+ protomove = true;
+ protopos = i;
+ continue;
+ }
+
+ if (source->data[i] == '#') {
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ j = ++i;
+ protomove = false;
+ protopos = i;
+ preprocessor = true;
+ continue;
+ }
+ if (preprocessor && source->data[i] == '\n') {
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ j = ++i;
+ protomove = true;
+ protopos = i;
+ preprocessor = false;
+ continue;
+ }
+ }
+
+ if (movename) {
+ if (source->data[i] != '*' && source->data[i] != '(' && !isspace(source->data[i]))
+ movename = false;
+ else if (source->data[i] != '(')
+ *nameofs = i+1;
+ }
+
+ if (source->data[i] == '"') {
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ j = i = parse_skip_string(source, i+1, source->data[i]);
+ } else if (source->data[i] == '\'') {
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ j = i = parse_skip_string(source, i+1, source->data[i]);
+ } else if (strchr("([{", source->data[i])) {
+ if (nameofs && !parens.elements) {
+ if (expectbody && source->data[i] == '{') {
+ lambda_vector_destroy(&parens);
+ return i;
+ }
+ if (!expectbody && source->data[i] == '(') {
+ expectbody = true;
+ movename = true;
+ *nameofs = i;
+ }
+ }
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ if (!lambda_vector_push_char(&parens, strchr("([{)]}", source->data[i])[3]))
+ goto parse_oom;
+ j = ++i;
+ } else if (strchr(")]}", source->data[i])) {
+ if (!parens.elements) {
+ parse_error(source, "too many closing parenthesis");
+ goto parse_error;
+ }
+ char back = parens.chars[parens.elements >= 1 ? parens.elements - 1 : 0];
+ if (source->data[i] != back) {
+ parse_error(source, "mismatching `%c' and `%c'", back, source->data[i]);
+ goto parse_error;
+ }
+ if (parens.elements != 0)
+ parens.elements--;
+ if (source->data[i] == '}' && !parens.elements) {
+ if (parsetype == PARSE_LAMBDA)
+ goto finish_lambda;
+ else if (nameofs) {
+ if (!expectbody)
+ movename = true;
+ }
+ }
+ bool domark = (mark && !parens.elements && source->data[i] == '}');
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ j = ++i;
+ if (domark) {
+ protopos = i;
+ protomove = true;
+ }
+ } else if (source->data[i] != '_' && !isalnum(source->data[i])) {
+ if (!nameofs && (i = parse_word(source, data, j, i)) == ERROR)
+ goto parse_error;
+ if (!parens.elements) {
+ if (parsetype == PARSE_LAMBDA_EXPRESSION && source->data[i] == ';')
+ goto finish_lambda;
+ if (source->short_enabled) {
+ if (parsetype == PARSE_TYPE && expectbody && source->data[i] == '=' && source->data[i+1] == '>') {
+ lambda_vector_destroy(&parens);
+ return i;
+ }
+ }
+ }
+ j = ++i;
+ } else
+ ++i;
+ }
+
+ lambda_vector_destroy(&parens);
+ return i;
+
+parse_oom:
+ parse_error(source, "out of memory");
+parse_error:
+ lambda_vector_destroy(&parens);
+ return ERROR;
+finish_lambda:
+ {
+ lambda_t *l = &data->lambdas.funcs[lambda];
+ l->body.length = i - l->body.begin;
+ l->end_line = source->line;
+ lambda_vector_destroy(&parens);
+ return i;
+ }
+}
+
+/* Generator */
+static inline void generate_marker(FILE *out, const char *file, size_t line, bool newline) {
+ fprintf(out, "%s#line %zu \"%s\"\n", newline ? "\n" : "", line, file);
+}
+
+static inline void generate_begin(FILE *out, lambda_source_t *source, lambda_vector_t *lambdas, size_t idx) {
+ generate_marker(out, source->file, lambdas->funcs[idx].decl_line, true);
+ fprintf(out, "static ");
+ size_t ofs = lambdas->funcs[idx].name_offset;
+ fwrite(source->data + lambdas->funcs[idx].decl.begin, ofs, 1, out);
+ fprintf(out, " lambda_%zu", idx);
+ fwrite(source->data + lambdas->funcs[idx].decl.begin+ofs, lambdas->funcs[idx].decl.length-ofs, 1, out);
+}
+
+static size_t next_prototype_position(parse_data_t *data, size_t lam, size_t proto) {
+ if (lam == data->lambdas.elements)
+ return data->positions.elements;
+ for (; proto != data->positions.elements; ++proto) {
+ if (data->positions.positions[proto].pos > data->lambdas.funcs[lam].start)
+ return proto-1;
+ }
+ return data->positions.elements-1;
+}
+
+static void generate_code(FILE *out, lambda_source_t *source, size_t pos, size_t len, parse_data_t *data, size_t lam, bool source_only);
+static void generate_functions(FILE *out, lambda_source_t *source, parse_data_t *data, size_t lam, size_t proto) {
+ size_t end = (proto+1) == data->positions.elements ? (size_t)-1 : data->positions.positions[proto+1].pos;
+ size_t first = lam;
+ for (; lam != data->lambdas.elements; ++lam) {
+ if (data->lambdas.funcs[lam].start > end)
+ break;
+ }
+ while (lam-- != first) {
+ lambda_t *lambda = &data->lambdas.funcs[lam];
+ generate_begin(out, source, &data->lambdas, lam);
+ if (lambda->is_short)
+ fprintf(out, "{");
+ generate_code(out, source, lambda->body.begin, lambda->body.length + 1, data, lam + 1, true);
+ if (lambda->is_short)
+ fprintf(out, "}");
+ }
+ fprintf(out, "\n");
+}
+
+/* when generating the actual code we also take prototype-positioning into account */
+static void generate_code(FILE *out, lambda_source_t *source, size_t pos, size_t len, parse_data_t *data, size_t lam, bool source_only) {
+ /* we know that positions always has at least 1 element, the 0, so the first search is there */
+ size_t proto = source_only ? data->positions.elements : next_prototype_position(data, lam, 1);
+ while (len) {
+ if (proto != data->positions.elements) {
+ lambda_position_t *lambdapos = &data->positions.positions[proto];
+ size_t point = lambdapos->pos;
+ if (pos <= point && pos+len >= point) {
+ /* we insert prototypes here! */
+ size_t length = point - pos;
+ fwrite(source->data + pos, length, 1, out);
+ generate_functions(out, source, data, lam, proto);
+ generate_marker(out, source->file, lambdapos->line, true);
+ len -= length;
+ pos += length;
+ }
+ }
+
+ if (lam == data->lambdas.elements || data->lambdas.funcs[lam].start > pos + len) {
+ fwrite(source->data + pos, len, 1, out);
+ return;
+ }
+
+ lambda_t *lambda = &data->lambdas.funcs[lam];
+ size_t length = lambda->body.begin + lambda->body.length + 1 - pos;
+
+ fwrite(source->data + pos, lambda->start - pos, 1, out);
+ fprintf(out, "(&lambda_%zu)", lam);
+
+ len -= length;
+ pos += length;
+
+ for (++lam; lam != data->lambdas.elements && data->lambdas.funcs[lam].start < pos; ++lam)
+ ;
+ proto = next_prototype_position(data, lam, proto);
+ }
+}
+
+
+static void generate(FILE *out, lambda_source_t *source) {
+ parse_data_t data;
+ lambda_vector_init(&data.lambdas, sizeof(data.lambdas.funcs[0]));
+ lambda_vector_init(&data.positions, sizeof(data.positions.positions[0]));
+ if (parse(source, &data, 0, PARSE_NORMAL, false) == ERROR) {
+ lambda_vector_destroy(&data.lambdas);
+ lambda_vector_destroy(&data.positions);
+ return;
+ }
+
+ generate_marker(out, source->file, 1, false);
+
+ generate_code(out, source, 0, source->length, &data, 0, false);
+
+ /* there are cases where we get no newline at the end of the file */
+ fprintf(out, "\n");
+
+ lambda_vector_destroy(&data.lambdas);
+ lambda_vector_destroy(&data.positions);
+}
+
+static void usage(const char *prog, FILE *out) {
+ fprintf(out, "usage: %s [options] [<file>]\n", prog);
+ fprintf(out,
+ "options:\n"
+ " -h, --help print this help message\n"
+ " -V, --version show the current program version\n"
+ " -k, --keyword=WORD change the lambda keyword to WORD\n"
+ " -o, --output=FILE write to FILE instead of stdout\n"
+ " -s enable shortened syntax (default)\n"
+ " -S disable shortened syntax\n");
+}
+
+static void version(FILE *out) {
+ fprintf(out, "lambdapp 0.1\n");
+}
+
+/* returns false when the parameter doesn't match,
+ * returns true and sets argarg when the parameter does match,
+ * returns true and sets arg to -1 on error
+ */
+static bool isparam(int argc, char **argv, int *arg, char sh, const char *lng, char **argarg) {
+ if (argv[*arg][0] != '-')
+ return false;
+ /* short version */
+ if (argv[*arg][1] == sh) {
+ if (argv[*arg][2]) {
+ *argarg = argv[*arg]+2;
+ return true;
+ }
+ ++*arg;
+ if (*arg == argc) {
+ fprintf(stderr, "%s: option -%c requires an argument\n", argv[0], sh);
+ usage(argv[0], stderr);
+ *arg = -1;
+ return true;
+ }
+ *argarg = argv[*arg];
+ return true;
+ }
+ /* long version */
+ if (argv[*arg][1] != '-')
+ return false;
+ size_t len = strlen(lng);
+ if (strncmp(argv[*arg]+2, lng, len))
+ return false;
+ if (argv[*arg][len+2] == '=') {
+ *argarg = argv[*arg] + 3 + len;
+ return true;
+ }
+ if (!argv[*arg][len+2]) {
+ ++*arg;
+ if (*arg == argc) {
+ fprintf(stderr, "%s: option --%s requires an argument\n", argv[0], lng);
+ usage(argv[0], stderr);
+ *arg = -1;
+ return true;
+ }
+ *argarg = argv[*arg];
+ return true;
+ }
+ return false;
+}
+
+int main(int argc, char **argv) {
+ lambda_source_t source;
+ const char *file = NULL;
+ const char *output = NULL;
+ FILE *outfile = stdout;
+
+ lambda_source_init(&source);
+
+ int i = 1;
+ for (; i != argc; ++i) {
+ char *argarg;
+
+ if (!strcmp(argv[i], "--")) {
+ ++i;
+ break;
+ }
+ if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ usage(argv[0], stdout);
+ return 0;
+ }
+ if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
+ version(stdout);
+ return 0;
+ }
+ if (!strcmp(argv[i], "-s")) {
+ source.short_enabled = true;
+ continue;
+ }
+ if (!strcmp(argv[i], "-S")) {
+ source.short_enabled = false;
+ continue;
+ }
+ if (isparam(argc, argv, &i, 'k', "keyword", &argarg)) {
+ if (i < 0)
+ return 1;
+ source.keyword = argarg;
+ continue;
+ }
+ if (isparam(argc, argv, &i, 'o', "output", &argarg)) {
+ if (i < 0)
+ return 1;
+ output = argarg;
+ continue;
+ }
+ if (argv[i][0] == '-') {
+ fprintf(stderr, "%s: unrecognized option: %s\n", argv[0], argv[i]);
+ usage(argv[0], stderr);
+ return 1;
+ }
+ if (file) {
+ fprintf(stderr, "%s: only 1 file allowed\n", argv[0]);
+ usage(argv[0], stderr);
+ return 1;
+ }
+ file = argv[i];
+ }
+ if (!file && i != argc)
+ file = argv[i++];
+ if (i != argc) {
+ fprintf(stderr, "%s: only 1 file allowed\n", argv[0]);
+ usage(argv[0], stderr);
+ return 1;
+ }
+
+ source.file = file ? file : "<stdin>";
+ if (!parse_open(&source, file ? fopen(file, "r") : stdin)) {
+ fprintf(stderr, "failed to open file %s %s\n", source.file, strerror(errno));
+ return 1;
+ }
+
+ source.keylength = strlen(source.keyword);
+
+ if (output) {
+ outfile = fopen(output, "w");
+ if (!outfile) {
+ fprintf(stderr, "failed to open file %s: %s\n", output, strerror(errno));
+ return 1;
+ }
+ }
+ generate(outfile, &source);
+ if (outfile != stdout)
+ fclose(outfile);
+ parse_close(&source);
+
+ return 0;
+}
diff --git a/zimg_vs_nginx.png b/zimg_vs_nginx.png
new file mode 100644
index 0000000..b334e52
--- /dev/null
+++ b/zimg_vs_nginx.png
Binary files differ