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
-*****
+| ![LOGO](http://i.imgur.com/uBd4iIz.png) | <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
+
+![ZIMG GRAPH](/zimg_vs_nginx.png)
+
+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!)
+![HI NGINX](http://i.imgur.com/kiSkSLH.png)
+
+<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