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 *);