Merge branch 'release/0.4.5'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46ee5e3..4437390 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 set(PROJECT_MAJOR_VERSION 0)
 set(PROJECT_MINOR_VERSION 4)
-set(PROJECT_PATCH_VERSION 4)
+set(PROJECT_PATCH_VERSION 5)
 
 set (PROJECT_VERSION ${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}.${PROJECT_PATCH_VERSION})
 set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
@@ -102,8 +102,8 @@
 	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_SYS_UN")
 endif(NOT HAVE_SYS_UN)
 
-OPTION(DISABLE_SSL   "Disable ssl support"      OFF)
-OPTION(DISABLE_EVTHR "Disable evthread support" OFF)
+OPTION(EVHTP_DISABLE_SSL   "Disable ssl support"      OFF)
+OPTION(EVHTP_DISABLE_EVTHR "Disable evthread support" OFF)
 
 SET(CMAKE_INCLUDE_CURRENT_DIR ON)
 
@@ -114,9 +114,9 @@
 message("Dbg CFLAGS: ${CMAKE_C_FLAGS_DEBUG}")
 message("Rel CFLAGS: ${CMAKE_C_FLAGS_RELEASE}")
 
-find_package(LibEvent)
+find_package(LibEvent REQUIRED)
 find_package(OpenSSL)
-find_path(LIBEVENT_INCLUDE_DIR event2/event.h)
+find_path(LIBEVENT_INCLUDE_DIR event2/event.h REQUIRED)
 
 include_directories(
 	${CMAKE_CURRENT_BINARY_DIR}/compat
@@ -136,19 +136,19 @@
 		${OPENSSL_LIBRARIES})
 
 if (NOT ${LIBEVENT_PTHREADS_FOUND})
-	set(DISABLE_EVTHR 1)
+	set(EVHTP_DISABLE_EVTHR 1)
 endif(NOT ${LIBEVENT_PTHREADS_FOUND})
 
 if (NOT ${LIBEVENT_OPENSSL_FOUND})
-	set (DISABLE_SSL 1)
+	set (EVHTP_DISABLE_SSL 1)
 endif(NOT ${LIBEVENT_OPENSSL_FOUND})
 
 set(LIBEVHTP_SOURCES evhtp.c htparse/htparse.c)
 
-if (NOT DISABLE_EVTHR)
+if (NOT EVHTP_DISABLE_EVTHR)
 	set (LIBEVHTP_EXTERNAL_LIBS ${LIBEVHTP_EXTERNAL_LIBS} pthread)
 	set (LIBEVHTP_SOURCES ${LIBEVHTP_SOURCES} evthr/evthr.c)
-endif(NOT DISABLE_EVTHR)
+endif(NOT EVHTP_DISABLE_EVTHR)
 
 add_library(libevhtp STATIC ${LIBEVHTP_SOURCES} ${ONIG_SOURCES})
 set_target_properties(libevhtp PROPERTIES OUTPUT_NAME "evhtp")
diff --git a/CMakeModules/BaseConfig.cmake b/CMakeModules/BaseConfig.cmake
index 5d67d42..5bab008 100644
--- a/CMakeModules/BaseConfig.cmake
+++ b/CMakeModules/BaseConfig.cmake
@@ -13,13 +13,13 @@
 
 endif(CMAKE_COMPILER_IS_GNUCC)
 
-if (DISABLE_EVTHR)
-       set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDISABLE_EVTHR")
-endif(DISABLE_EVTHR)
+if (EVHTP_DISABLE_EVTHR)
+       set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DEVHTP_DISABLE_EVTHR")
+endif(EVHTP_DISABLE_EVTHR)
 
-if (DISABLE_SSL)
-			set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDISABLE_SSL")
-endif(DISABLE_SSL)
+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)
diff --git a/ChangeLog b/ChangeLog
index 9e39120..e984e0b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+v0.4.5
+=====================================
+
+NOTE: Any code which accesses connection->ssl_ctx directly must change to use connection->ssl.
+
+2011-12-28  Mark Ellzey <mark.thomas@mandiant.com>
+
+  * CMakeLists.txt: Set libevent as a required dependency
+
+2011-12-27  Mark Ellzey <mark.thomas@mandiant.com>
+
+  * evhtp.c: inline enum's should not be static.
+
+  * CMakeLists.txt, CMakeModules/BaseConfig.cmake, evhtp.h: Changes to DISABLE
+  to EVHTP_DISABLE, also fixed enum hook missing from last merge.
+
+  * evthr/evthr.h: Added #ifndef _GNU_SOURCE before setting it again.
+
+2011-12-27  Andy Hochhaus <ahochhaus@samegoal.com>
+
+  * evhtp.h, evthr/evthr.h, htparse/htparse.h: Fix C++/clang++ build.
+
+2011-12-27  Mark Ellzey <mark.thomas@mandiant.com>
+
+  * evhtp.c, htparse/htparse.c, htparse/htparse.h: Added
+  htparser_set_(major|minor). fixed edgecase where major/minor is not yet set.
+
+  * evhtp.c, evhtp.h, htparse/htparse.c: added on_headers_start hook (before
+  header parsing, post requestline parsing).
+
+2011-12-20  Mark Ellzey <mark.thomas@mandiant.com>
+
+  * evhtp.c, evhtp.h: Added evhtp_unescape_string() to unescape query type
+  strings.
+
+2011-12-16  Mark Ellzey <mark.thomas@mandiant.com>
+
+  * README.markdown: Documentation updates
+
+  * README.markdown: Documentation updates.
+
+  * README.markdown: Initial markdown-based API documentation.
+
+
 v0.4.4
 =====================================
 2011-12-15  Mark Ellzey <mark.thomas@mandiant.com>
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..9f913b1
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,75 @@
+# Libevhtp
+*****
+
+This document describes details on using the evhtp API
+
+## Required Dependencies
+* [gcc](http://gcc.gnu.org/)
+* [Libevent2](http://libevent.org)
+
+## Optional Dependencies
+* [OpenSSL](http://openssl.org)
+* pthreads
+
+## Overview
+***
+
+Libevhtp was created as a replacement API for Libevent's current HTTP API.  The reality of libevent's http interface is that it was created as a JIT server, meaning the developer never thought of it being used for creating a full-fledged HTTP service. Infact I am under the impression that the libevent http API was designed almost as an example of what you can do with libevent. It's not Apache in a box, but more and more developers are attempting to use it as so.
+
+### Libevent's HTTP pitfalls
+***
+
+* It was not designed to be a fully functional HTTP server.
+* The code is messy, abstractions are almost non-existent, and feature-creep has made long-term maintainability very hard.
+* The parsing code is slow and requires data to be buffered before a full parse can be completed. This results in extranious memory usage and lots of string comparison functions.
+* There is no method for a user to access various parts of the request processing cycle. For example if the "Content-Length" header has a value of 50000, your callback is not executed until all 50000 bytes have been read.
+* Setting callback URI's do exact matches; meaning if you set a callback for "/foo/", requests for "/foo/bar/" are ignored.
+* Creating an HTTPS server is hard, it requires a bunch of work to be done on the underlying bufferevents.
+* As far as I know, streaming data back to a client is hard, if not impossible without messing with underlying bufferevents.
+* It's confusing to work with, this is probably due to the lack of proper documentation.
+
+Libevhtp attempts to address these problems along with a wide variety of cool mechanisms allowing a developer to have complete control over your server operations. This is not to say the API cannot be used in a very simplistic manner - a developer can easily create a backwards compatible version of libevent's HTTP server to libevhtp.
+
+### A bit about the architecture of libevhtp
+***
+
+#### Bootstrapping 
+
+1.	Create a parent evhtp_t structure.
+2.	Assign callbacks to the parent for specific URIs or posix-regex based URI's
+3.	Optionally assign per-connection hooks (see hooks) to the callbacks.
+4.	Optionally assign pre-accept and post-accept callbacks for incoming connections.	
+5.	Optionally enable built-in threadpool for connection handling (lock-free, and non-blocking).
+6.	Optionally morph your server to HTTPS.
+7.	Start the evhtp listener.
+
+#### Request handling.
+
+1.	Optionally deal with pre-accept and post-accept callbacks if they exist, allowing for a connection to be rejected if the function deems it as unacceptable.
+2.	Optionally assign per-request hooks (see hooks) for a request (the most optimal place for setting these hooks is on a post-accept callback).
+3.	Deal with either per-connection or per-request hook callbacks if they exist.
+4.	Once the request has been fully processed, inform evhtp to send a reply.
+
+##### A very basic example with no optional conditions.
+
+	#include <stdio.h>
+	#include <evhtp.h>
+
+	void
+	testcb(evhtp_request_t * req, void * a) {
+	    evbuffer_add_reference(req->buffer_out, "foobar", 6, NULL, NULL);
+	    evhtp_send_reply(req, EVHTP_RES_OK);
+	}
+
+	int
+	main(int argc, char ** argv) {
+	    evbase_t * evbase = event_base_new();
+	    evhtp_t  * htp    = evhtp_new(evbase, NULL);
+	
+	    evhtp_set_cb(htp, "/test", testcb, NULL);
+	    evhtp_bind_socket(htp, "0.0.0.0", 8080, 1024);
+	    event_base_loop(evbase, 0);
+	    return 0;
+	}
+
+
diff --git a/evhtp.c b/evhtp.c
index bb22c10..cc88180 100644
--- a/evhtp.c
+++ b/evhtp.c
@@ -28,6 +28,7 @@
 static int                  _evhtp_request_parser_chunk_new(htparser * p);
 static int                  _evhtp_request_parser_chunk_fini(htparser * p);
 static int                  _evhtp_request_parser_chunks_fini(htparser * p);
+static int                  _evhtp_request_parser_headers_start(htparser * p);
 
 static void                 _evhtp_connection_readcb(evbev_t * bev, void * arg);
 
@@ -205,7 +206,7 @@
     .path               = _evhtp_request_parser_path,
     .args               = _evhtp_request_parser_args,
     .uri                = NULL,
-    .on_hdrs_begin      = NULL,
+    .on_hdrs_begin      = _evhtp_request_parser_headers_start,
     .hdr_key            = _evhtp_request_parser_header_key,
     .hdr_val            = _evhtp_request_parser_header_val,
     .on_hdrs_complete   = _evhtp_request_parser_headers,
@@ -440,6 +441,13 @@
     return EVHTP_RES_OK;
 }
 
+static evhtp_res
+_evhtp_headers_start_hook(evhtp_request_t * request) {
+    HOOK_REQUEST_RUN_NARGS(request, on_headers_start);
+
+    return EVHTP_RES_OK;
+}
+
 /**
  * @brief runs the user-definedhook called just prior to a connection being
  *        closed
@@ -838,6 +846,17 @@
 }
 
 static int
+_evhtp_request_parser_headers_start(htparser * p) {
+    evhtp_connection_t * c = htparser_get_userdata(p);
+
+    if ((c->request->status = _evhtp_headers_start_hook(c->request)) != EVHTP_RES_OK) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
 _evhtp_request_parser_header_key(htparser * p, const char * data, size_t len) {
     evhtp_connection_t * c = htparser_get_userdata(p);
     char               * key_s;     /* = strndup(data, len); */
@@ -1124,8 +1143,12 @@
             }
             break;
         default:
+            /* this sometimes happens when a response is made but paused before
+             * the method has been parsed */
+            htparser_set_major(request->conn->parser, 1);
+            htparser_set_minor(request->conn->parser, 0);
             break;
-    }
+    } /* switch */
 
     /* add the status line */
     evbuffer_add_printf(buf, "HTTP/%d.%d %d %s\r\n",
@@ -1225,12 +1248,12 @@
 _evhtp_connection_accept(evbase_t * evbase, evhtp_connection_t * connection) {
 #ifndef DISABLE_SSL
     if (connection->htp->ssl_ctx != NULL) {
-        connection->ssl_ctx = SSL_new(connection->htp->ssl_ctx);
-        connection->bev     = bufferevent_openssl_socket_new(evbase,
-                                                             connection->sock, connection->ssl_ctx,
-                                                             BUFFEREVENT_SSL_ACCEPTING,
-                                                             BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
-        SSL_set_app_data(connection->ssl_ctx, connection);
+        connection->ssl = SSL_new(connection->htp->ssl_ctx);
+        connection->bev = bufferevent_openssl_socket_new(evbase,
+                                                         connection->sock, connection->ssl,
+                                                         BUFFEREVENT_SSL_ACCEPTING,
+                                                         BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
+        SSL_set_app_data(connection->ssl, connection);
         goto end;
     }
 #endif
@@ -1275,7 +1298,7 @@
     connection->evbase    = NULL;
     connection->bev       = NULL;
     connection->thread    = NULL;
-    connection->ssl_ctx   = NULL;
+    connection->ssl       = NULL;
     connection->hooks     = NULL;
     connection->request   = NULL;
     connection->resume_ev = NULL;
@@ -1754,6 +1777,87 @@
     } /* switch */
 }
 
+enum unscape_state {
+    unscape_state_start = 0,
+    unscape_state_hex1,
+    unscape_state_hex2
+};
+
+int
+evhtp_unescape_string(unsigned char ** out, unsigned char * str, size_t str_len) {
+    unsigned char    * optr;
+    unsigned char    * sptr;
+    unsigned char      d;
+    unsigned char      ch;
+    unsigned char      c;
+    size_t             i;
+    enum unscape_state state;
+
+    if (out == NULL || *out == NULL) {
+        return -1;
+    }
+
+    state = unscape_state_start;
+    optr  = *out;
+    sptr  = str;
+    d     = 0;
+
+    for (i = 0; i < str_len; i++) {
+        ch = *sptr++;
+
+        switch (state) {
+            case unscape_state_start:
+                if (ch == '%') {
+                    state = unscape_state_hex1;
+                    break;
+                }
+
+                *optr++ = ch;
+
+                break;
+            case unscape_state_hex1:
+                if (ch >= '0' && ch <= '9') {
+                    d     = (unsigned char)(ch - '0');
+                    state = unscape_state_hex2;
+                    break;
+                }
+
+                c = (unsigned char)(ch | 0x20);
+
+                if (c >= 'a' && c <= 'f') {
+                    d     = (unsigned char)(c - 'a' + 10);
+                    state = unscape_state_hex2;
+                    break;
+                }
+
+                state   = unscape_state_start;
+                *optr++ = ch;
+                break;
+            case unscape_state_hex2:
+                state   = unscape_state_start;
+
+                if (ch >= '0' && ch <= '9') {
+                    ch      = (unsigned char)((d << 4) + ch - '0');
+
+                    *optr++ = ch;
+                    break;
+                }
+
+                c = (unsigned char)(ch | 0x20);
+
+                if (c >= 'a' && c <= 'f') {
+                    ch      = (unsigned char)((d << 4) + c - 'a' + 10);
+                    *optr++ = ch;
+                    break;
+                }
+
+                break;
+        } /* switch */
+    }
+
+    return 0;
+}         /* evhtp_unescape_string */
+
 evhtp_query_t *
 evhtp_parse_query(const char * query, size_t len) {
     evhtp_query_t    * query_args;
@@ -2185,8 +2289,12 @@
     }
 
     switch (type) {
+        case evhtp_hook_on_headers_start:
+            (*hooks)->on_headers_start       = (evhtp_hook_headers_start_cb)cb;
+            (*hooks)->on_headers_start_arg   = arg;
+            break;
         case evhtp_hook_on_header:
-            (*hooks)->on_header              = (evhtp_hook_header_cb)cb;
+            (*hooks)->on_header = (evhtp_hook_header_cb)cb;
             (*hooks)->on_header_arg          = arg;
             break;
         case evhtp_hook_on_headers:
@@ -2194,11 +2302,11 @@
             (*hooks)->on_headers_arg         = arg;
             break;
         case evhtp_hook_on_path:
-            (*hooks)->on_path                = (evhtp_hook_path_cb)cb;
+            (*hooks)->on_path = (evhtp_hook_path_cb)cb;
             (*hooks)->on_path_arg            = arg;
             break;
         case evhtp_hook_on_read:
-            (*hooks)->on_read                = (evhtp_hook_read_cb)cb;
+            (*hooks)->on_read = (evhtp_hook_read_cb)cb;
             (*hooks)->on_read_arg            = arg;
             break;
         case evhtp_hook_on_request_fini:
@@ -2210,7 +2318,7 @@
             (*hooks)->on_connection_fini_arg = arg;
             break;
         case evhtp_hook_on_error:
-            (*hooks)->on_error               = (evhtp_hook_err_cb)cb;
+            (*hooks)->on_error = (evhtp_hook_err_cb)cb;
             (*hooks)->on_error_arg           = arg;
             break;
         case evhtp_hook_on_new_chunk:
@@ -2527,10 +2635,10 @@
         bufferevent_shutdown(connection->bev, _evhtp_shutdown_eventcb);
 #else
 #ifndef DISABLE_SSL
-        if (connection->ssl_ctx != NULL) {
-            SSL_set_shutdown(connection->ssl_ctx,
+        if (connection->ssl != NULL) {
+            SSL_set_shutdown(connection->ssl,
                              SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
-            SSL_shutdown(connection->ssl_ctx);
+            SSL_shutdown(connection->ssl);
         }
 #endif
         bufferevent_free(connection->bev);
diff --git a/evhtp.h b/evhtp.h
index 0d9de52..2e85f7f 100644
--- a/evhtp.h
+++ b/evhtp.h
@@ -1,7 +1,7 @@
 #ifndef __EVHTP__H__
 #define __EVHTP__H__
 
-#ifndef DISABLE_EVTHR
+#ifndef EVHTP_DISABLE_EVTHR
 #include <evthr.h>
 #endif
 
@@ -13,56 +13,60 @@
 #include <event2/buffer.h>
 #include <event2/bufferevent.h>
 
-#ifndef DISABLE_SSL
+#ifndef EVHTP_DISABLE_SSL
 #include <event2/bufferevent_ssl.h>
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #endif
 
-#ifndef DISABLE_SSL
-typedef SSL_SESSION                evhtp_ssl_sess_t;
-typedef SSL                        evhtp_ssl_t;
-typedef SSL_CTX                    evhtp_ssl_ctx_t;
-typedef X509                       evhtp_x509_t;
-typedef X509_STORE_CTX             evhtp_x509_store_ctx_t;
-#else
-typedef void                       evhtp_ssl_sess_t;
-typedef void                       evhtp_ssl_t;
-typedef void                       evhtp_ssl_ctx_t;
-typedef void                       evhtp_x509_t;
-typedef void                       evhtp_x509_store_ctx_t;
+#ifdef __cplusplus
+extern "C" {
 #endif
 
-typedef struct evbuffer            evbuf_t;
-typedef struct event               event_t;
-typedef struct evconnlistener      evserv_t;
-typedef struct bufferevent         evbev_t;
-#ifdef DISABLE_EVTHR
-typedef struct event_base          evbase_t;
-typedef void                       evthr_t;
-typedef void                       evthr_pool_t;
-typedef void                       evhtp_mutex_t;
+#ifndef EVHTP_DISABLE_SSL
+typedef SSL_SESSION               evhtp_ssl_sess_t;
+typedef SSL                       evhtp_ssl_t;
+typedef SSL_CTX                   evhtp_ssl_ctx_t;
+typedef X509                      evhtp_x509_t;
+typedef X509_STORE_CTX            evhtp_x509_store_ctx_t;
 #else
-typedef pthread_mutex_t            evhtp_mutex_t;
+typedef void                      evhtp_ssl_sess_t;
+typedef void                      evhtp_ssl_t;
+typedef void                      evhtp_ssl_ctx_t;
+typedef void                      evhtp_x509_t;
+typedef void                      evhtp_x509_store_ctx_t;
 #endif
 
-typedef struct evhtp_s             evhtp_t;
-typedef struct evhtp_defaults_s    evhtp_defaults_t;
-typedef struct evhtp_callbacks_s   evhtp_callbacks_t;
-typedef struct evhtp_callback_s    evhtp_callback_t;
-typedef struct evhtp_defaults_s    evhtp_defaults_5;
-typedef struct evhtp_kv_s          evhtp_kv_t;
-typedef struct evhtp_kvs_s         evhtp_kvs_t;
-typedef struct evhtp_uri_s         evhtp_uri_t;
-typedef struct evhtp_path_s        evhtp_path_t;
-typedef struct evhtp_authority_s   evhtp_authority_t;
-typedef struct evhtp_request_s     evhtp_request_t;
-typedef struct evhtp_hooks_s       evhtp_hooks_t;
-typedef struct evhtp_connection_s  evhtp_connection_t;
-typedef struct evhtp_ssl_cfg_s     evhtp_ssl_cfg_t;
-typedef uint16_t                   evhtp_res;
-typedef uint8_t                    evhtp_error_flags;
+typedef struct evbuffer           evbuf_t;
+typedef struct event              event_t;
+typedef struct evconnlistener     evserv_t;
+typedef struct bufferevent        evbev_t;
+#ifdef EVHTP_DISABLE_EVTHR
+typedef struct event_base         evbase_t;
+typedef void                      evthr_t;
+typedef void                      evthr_pool_t;
+typedef void                      evhtp_mutex_t;
+#else
+typedef pthread_mutex_t           evhtp_mutex_t;
+#endif
+
+typedef struct evhtp_s            evhtp_t;
+typedef struct evhtp_defaults_s   evhtp_defaults_t;
+typedef struct evhtp_callbacks_s  evhtp_callbacks_t;
+typedef struct evhtp_callback_s   evhtp_callback_t;
+typedef struct evhtp_defaults_s   evhtp_defaults_5;
+typedef struct evhtp_kv_s         evhtp_kv_t;
+typedef struct evhtp_kvs_s        evhtp_kvs_t;
+typedef struct evhtp_uri_s        evhtp_uri_t;
+typedef struct evhtp_path_s       evhtp_path_t;
+typedef struct evhtp_authority_s  evhtp_authority_t;
+typedef struct evhtp_request_s    evhtp_request_t;
+typedef struct evhtp_hooks_s      evhtp_hooks_t;
+typedef struct evhtp_connection_s evhtp_connection_t;
+typedef struct evhtp_ssl_cfg_s    evhtp_ssl_cfg_t;
+typedef uint16_t                  evhtp_res;
+typedef uint8_t                   evhtp_error_flags;
 
 
 #define evhtp_header_s  evhtp_kv_s
@@ -73,6 +77,42 @@
 #define evhtp_headers_t evhtp_kvs_t
 #define evhtp_query_t   evhtp_kvs_t
 
+enum evhtp_ssl_scache_type {
+    evhtp_ssl_scache_type_disabled = 0,
+    evhtp_ssl_scache_type_internal,
+    evhtp_ssl_scache_type_user,
+    evhtp_ssl_scache_type_builtin
+};
+
+/**
+ * @brief types associated with where a developer can hook into
+ *        during the request processing cycle.
+ */
+enum evhtp_hook_type {
+    evhtp_hook_on_header,       /**< type which defines to hook after one header has been parsed */
+    evhtp_hook_on_headers,      /**< type which defines to hook after all headers have been parsed */
+    evhtp_hook_on_path,         /**< type which defines to hook once a path has been parsed */
+    evhtp_hook_on_read,         /**< type which defines to hook whenever the parser recieves data in a body */
+    evhtp_hook_on_request_fini, /**< type which defines to hook before the request is free'd */
+    evhtp_hook_on_connection_fini,
+    evhtp_hook_on_new_chunk,
+    evhtp_hook_on_chunk_complete,
+    evhtp_hook_on_chunks_complete,
+    evhtp_hook_on_headers_start,
+    evhtp_hook_on_error         /**< type which defines to hook whenever an error occurs */
+};
+
+enum evhtp_callback_type {
+    evhtp_callback_type_hash,
+    evhtp_callback_type_regex
+};
+
+enum evhtp_proto {
+    EVHTP_PROTO_INVALID,
+    EVHTP_PROTO_10,
+    EVHTP_PROTO_11
+};
+
 typedef enum evhtp_hook_type       evhtp_hook_type;
 typedef enum evhtp_callback_type   evhtp_callback_type;
 typedef enum evhtp_proto           evhtp_proto;
@@ -92,6 +132,7 @@
 typedef evhtp_res (*evhtp_hook_chunk_new_cb)(evhtp_request_t * r, uint64_t len, void * arg);
 typedef evhtp_res (*evhtp_hook_chunk_fini_cb)(evhtp_request_t * r, void * arg);
 typedef evhtp_res (*evhtp_hook_chunks_fini_cb)(evhtp_request_t * r, void * arg);
+typedef evhtp_res (*evhtp_hook_headers_start_cb)(evhtp_request_t * r, void * arg);
 
 typedef int (*evhtp_kvs_iterator)(evhtp_kv_t * kv, void * arg);
 typedef int (*evhtp_headers_iterator)(evhtp_header_t * header, void * arg);
@@ -104,10 +145,10 @@
 typedef evhtp_ssl_sess_t * (*evhtp_ssl_scache_get)(evhtp_connection_t * connection, unsigned char * sid, int sid_len);
 typedef void * (*evhtp_ssl_scache_init)(evhtp_t *);
 
-#define EVHTP_VERSION          "0.4.4"
+#define EVHTP_VERSION          "0.4.5"
 #define EVHTP_VERSION_MAJOR    0
 #define EVHTP_VERSION_MINOR    4
-#define EVHTP_VERSION_PATCH    4
+#define EVHTP_VERSION_PATCH    5
 
 #define evhtp_headers_iterator evhtp_kvs_iterator
 
@@ -172,42 +213,6 @@
 #define EVHTP_RES_VERNSUPPORT  505
 #define EVHTP_RES_BWEXEED      509
 
-enum evhtp_ssl_scache_type {
-    evhtp_ssl_scache_type_disabled = 0,
-    evhtp_ssl_scache_type_internal,
-    evhtp_ssl_scache_type_user,
-    evhtp_ssl_scache_type_builtin
-};
-
-/**
- * @brief types associated with where a developer can hook into
- *        during the request processing cycle.
- */
-enum evhtp_hook_type {
-    evhtp_hook_on_header,       /**< type which defines to hook after one header has been parsed */
-    evhtp_hook_on_headers,      /**< type which defines to hook after all headers have been parsed */
-    evhtp_hook_on_path,         /**< type which defines to hook once a path has been parsed */
-    evhtp_hook_on_read,         /**< type which defines to hook whenever the parser recieves data in a body */
-    evhtp_hook_on_request_fini, /**< type which defines to hook before the request is free'd */
-    evhtp_hook_on_connection_fini,
-    evhtp_hook_on_new_chunk,
-    evhtp_hook_on_chunk_complete,
-    evhtp_hook_on_chunks_complete,
-    evhtp_hook_on_error         /**< type which defines to hook whenever an error occurs */
-};
-
-enum evhtp_callback_type {
-    evhtp_callback_type_hash,
-    evhtp_callback_type_regex
-};
-
-enum evhtp_proto {
-    EVHTP_PROTO_INVALID,
-    EVHTP_PROTO_10,
-    EVHTP_PROTO_11
-};
-
-
 struct evhtp_defaults_s {
     evhtp_callback_cb    cb;
     evhtp_pre_accept_cb  pre_accept;
@@ -377,7 +382,7 @@
     evbase_t        * evbase;
     evbev_t         * bev;
     evthr_t         * thread;
-    evhtp_ssl_t     * ssl_ctx;
+    evhtp_ssl_t     * ssl;
     evhtp_hooks_t   * hooks;
     htparser        * parser;
     event_t         * resume_ev;
@@ -388,6 +393,7 @@
 };
 
 struct evhtp_hooks_s {
+    evhtp_hook_headers_start_cb   on_headers_start;
     evhtp_hook_header_cb          on_header;
     evhtp_hook_headers_cb         on_headers;
     evhtp_hook_path_cb            on_path;
@@ -399,6 +405,7 @@
     evhtp_hook_chunk_fini_cb      on_chunk_fini;
     evhtp_hook_chunks_fini_cb     on_chunks_fini;
 
+    void * on_headers_start_arg;
     void * on_header_arg;
     void * on_headers_arg;
     void * on_path_arg;
@@ -643,6 +650,17 @@
 
 
 /**
+ * @brief Unescapes strings like '%7B1,%202,%203%7D' would become '{1, 2, 3}'
+ *
+ * @param out double pointer where output is stored. This is allocated by the user.
+ * @param str the string to unescape
+ * @param str_len the length of the string to unescape
+ *
+ * @return 0 on success, -1 on error
+ */
+int evhtp_unescape_string(unsigned char ** out, unsigned char * str, size_t str_len);
+
+/**
  * @brief creates a new evhtp_header_t key/val structure
  *
  * @param key a null terminated string
@@ -777,5 +795,9 @@
  * @param connection
  */
 void evhtp_connection_free(evhtp_connection_t * connection);
-#endif /* __EVHTP__H__ */
 
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EVHTP__H__ */
diff --git a/evthr/evthr.h b/evthr/evthr.h
index 1f59aa2..0c2335b 100644
--- a/evthr/evthr.h
+++ b/evthr/evthr.h
@@ -1,4 +1,6 @@
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
 #ifndef __EVTHR_H__
 #define __EVTHR_H__
 
@@ -8,6 +10,14 @@
 #include <event2/event.h>
 #include <event2/thread.h>
 
+enum evthr_res {
+    EVTHR_RES_OK = 0,
+    EVTHR_RES_BACKLOG,
+    EVTHR_RES_RETRY,
+    EVTHR_RES_NOCB,
+    EVTHR_RES_FATAL
+};
+
 struct evthr_pool;
 struct evthr;
 
@@ -21,14 +31,6 @@
 typedef void (*evthr_cb)(evthr_t * thr, void * cmd_arg, void * shared);
 typedef void (*evthr_init_cb)(evthr_t * thr, void * shared);
 
-enum evthr_res {
-    EVTHR_RES_OK = 0,
-    EVTHR_RES_BACKLOG,
-    EVTHR_RES_RETRY,
-    EVTHR_RES_NOCB,
-    EVTHR_RES_FATAL
-};
-
 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);
diff --git a/htparse/htparse.c b/htparse/htparse.c
index 0ab94b6..ddf641b 100644
--- a/htparse/htparse.c
+++ b/htparse/htparse.c
@@ -370,6 +370,16 @@
     return method_strmap[p->method];
 }
 
+void
+htparser_set_major(htparser * p, unsigned char major) {
+    p->major = major;
+}
+
+void
+htparser_set_minor(htparser * p, unsigned char minor) {
+    p->minor = minor;
+}
+
 unsigned char
 htparser_get_major(htparser * p) {
     return p->major;
diff --git a/htparse/htparse.h b/htparse/htparse.h
index de460e2..b5d873b 100644
--- a/htparse/htparse.h
+++ b/htparse/htparse.h
@@ -3,17 +3,6 @@
 
 struct htparser;
 
-typedef struct htparser      htparser;
-typedef struct htparse_hooks htparse_hooks;
-
-typedef enum htp_scheme      htp_scheme;
-typedef enum htp_method      htp_method;
-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);
-
 enum htp_type {
     htp_type_request = 0,
     htp_type_response
@@ -62,6 +51,17 @@
     htparse_error_generic
 };
 
+typedef struct htparser      htparser;
+typedef struct htparse_hooks htparse_hooks;
+
+typedef enum htp_scheme      htp_scheme;
+typedef enum htp_method      htp_method;
+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);
+
 
 struct htparse_hooks {
     htparse_hook      on_msg_begin;
@@ -89,6 +89,8 @@
 htp_scheme     htparser_get_scheme(htparser *);
 htp_method     htparser_get_method(htparser *);
 const char   * htparser_get_methodstr(htparser *);
+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 int   htparser_get_status(htparser *);