Initial commit
This commit is contained in:
commit
ea3ff86b28
9 changed files with 648 additions and 0 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "http_parser"]
|
||||||
|
path = http_parser
|
||||||
|
url = https://github.com/ry/http-parser.git
|
37
CMakeLists.txt
Normal file
37
CMakeLists.txt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(reason)
|
||||||
|
|
||||||
|
set(PROJECT_MAJOR_VERSION 0)
|
||||||
|
set(PROJECT_MINOR_VERSION 1)
|
||||||
|
set(PROJECT_PATCH_VERSION 0)
|
||||||
|
|
||||||
|
set (PROJECT_VERSION ${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}.${PROJECT_PATCH_VERSION})
|
||||||
|
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
|
||||||
|
|
||||||
|
include(BaseConfig)
|
||||||
|
|
||||||
|
message("Build Type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
message("Std CFLAGS: ${CMAKE_C_FLAGS}")
|
||||||
|
message("Dbg CFLAGS: ${CMAKE_C_FLAGS_DEBUG}")
|
||||||
|
message("Rel CFLAGS: ${CMAKE_C_FLAGS_RELEASE}")
|
||||||
|
|
||||||
|
find_package(LibEvent)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/http_parser
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBEVHTP_EXTERNAL_LIBS
|
||||||
|
${LIBEVENT_LIBRARY}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/build
|
||||||
|
)
|
||||||
|
set(LIBEVHTP_SOURCES http_parser/http_parser.c evhtp.c)
|
||||||
|
|
||||||
|
add_library(libevhtp STATIC ${LIBEVHTP_SOURCES})
|
||||||
|
set_target_properties(libevhtp PROPERTIES OUTPUT_NAME "evhtp")
|
||||||
|
target_link_libraries(libevhtp ${LIVEVHTP_EXTERNAL_LIBS})
|
||||||
|
|
||||||
|
add_executable(test test.c)
|
||||||
|
target_link_libraries(test libevhtp event)
|
20
CMakeModules/BaseConfig.cmake
Normal file
20
CMakeModules/BaseConfig.cmake
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
if (CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
|
set(RSN_BASE_C_FLAGS "-std=c99 -Wall")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RSN_BASE_C_FLAGS}")
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${RSN_BASE_C_FLAGS} -DDEBUG -ggdb")
|
||||||
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RSN_BASE_C_FLAGS}")
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshorten-64-to-32 -D_BSD_SOURCE")
|
||||||
|
endif(APPLE)
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_BSD_SOURCE -D_POSIX_C_SOURCE=199309L")
|
||||||
|
endif(UNIX)
|
||||||
|
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
endif(NOT CMAKE_BUILD_TYPE)
|
21
CMakeModules/FindLibEvent.cmake
Normal file
21
CMakeModules/FindLibEvent.cmake
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# - Try to find the LibEvent config processing library
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# LIBEVENT_FOUND - System has LibEvent
|
||||||
|
# LIBEVENT_INCLUDE_DIR - the LibEvent include directory
|
||||||
|
# LIBEVENT_LIBRARIES 0 The libraries needed to use LibEvent
|
||||||
|
|
||||||
|
FIND_PATH(LIBEVENT_INCLUDE_DIR NAMES event.h)
|
||||||
|
FIND_LIBRARY(LIBEVENT_LIBRARY NAMES event)
|
||||||
|
FIND_LIBRARY(LIBEVENT_CORE_LIBRARY NAMES event_core)
|
||||||
|
FIND_LIBRARY(LIBEVENT_PTHREADS_LIBRARY NAMES event_pthreads)
|
||||||
|
FIND_LIBRARY(LIBEVENT_EXTRA_LIBRARY NAMES event_extra)
|
||||||
|
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibEvent DEFAULT_MSG LIBEVENT_LIBRARY LIBEVENT_INCLUDE_DIR)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibEventPthreads DEFAULT_MSG LIBEVENT_PTHREADS_LIBRARY LIBEVENT_INCLUDE_DIR)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibEventCore DEFAULT_MSG LIBEVENT_CORE_LIBRARY LIBEVENT_INCLUDE_DIR)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibEventExtra DEFAULT_MSG LIBEVENT_EXTRA_LIBRARY LIBEVENT_INCLUDE_DIR)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(LIBEVENT_INCLUDE_DIR LIBEVENT_LIBRARY LIBEVENT_PTHREADS_LIBRARY LIBEVENT_CORE_LIBRARY LIBEVENT_EXTRA_LIBRARY)
|
0
build/placeholder
Normal file
0
build/placeholder
Normal file
374
evhtp.c
Normal file
374
evhtp.c
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "evhtp.h"
|
||||||
|
|
||||||
|
evhtp_request_t *
|
||||||
|
evhtp_request_new(void) {
|
||||||
|
evhtp_request_t * request = NULL;
|
||||||
|
|
||||||
|
if (!(request = calloc(sizeof(evhtp_request_t), sizeof(char)))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INIT(&request->headers);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evhtp_conn_hook(evhtp_connection_t * conn, evhtp_hook_type type, void * cb) {
|
||||||
|
if (conn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->hooks == NULL) {
|
||||||
|
if (!(conn->hooks = calloc(sizeof(evhtp_conn_hooks_t), sizeof(char)))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case EVHTP_HOOK_POST_HEADERS:
|
||||||
|
conn->hooks->post_headers_cb = (evhtp_hook_post_headers)cb;
|
||||||
|
break;
|
||||||
|
case EVHTP_HOOK_SINGLE_HEADER:
|
||||||
|
conn->hooks->single_header_cb = (evhtp_hook_single_header)cb;
|
||||||
|
break;
|
||||||
|
case EVHTP_HOOK_ON_PATH:
|
||||||
|
conn->hooks->path_cb = (evhtp_hook_on_path)cb;
|
||||||
|
break;
|
||||||
|
case EVHTP_HOOK_ON_BODY_READ:
|
||||||
|
conn->hooks->body_read_cb = (evhtp_hook_on_body_read)cb;
|
||||||
|
break;
|
||||||
|
case EVHTP_HOOK_COMPLETE:
|
||||||
|
conn->hooks->complete_cb = (evhtp_hook_complete)cb;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evhtp_headers_for_each(evhtp_headers_t * headers, evhtp_headers_iter_cb cb, void * arg) {
|
||||||
|
evhtp_header_t * header = NULL;
|
||||||
|
|
||||||
|
if (!headers || !cb) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH(header, headers, next) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if ((res = cb(header, arg))) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_start_cb(http_parser * p) {
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)p->data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(conn->request = evhtp_request_new())) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_headers_complete_cb(http_parser * p) {
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)p->data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->hooks && conn->hooks->post_headers_cb) {
|
||||||
|
evhtp_headers_t * hdrs = &conn->request->headers;
|
||||||
|
|
||||||
|
if (conn->hooks->post_headers_cb(conn, hdrs, conn->arg) != EVHTP_RES_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->request->method = p->method;
|
||||||
|
conn->request->major = p->http_major;
|
||||||
|
conn->request->minor = p->http_minor;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_end_cb(http_parser * p) {
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)p->data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->hooks && conn->hooks->complete_cb) {
|
||||||
|
if (conn->hooks->complete_cb(conn, conn->request, conn->arg) != EVHTP_RES_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_path_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
char * uri;
|
||||||
|
|
||||||
|
if (len == 0 || buf == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)p->data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->request->uri = malloc(len + 1);
|
||||||
|
conn->request->uri[len] = '\0';
|
||||||
|
|
||||||
|
memcpy(conn->request->uri, buf, len);
|
||||||
|
|
||||||
|
if (conn->hooks && conn->hooks->path_cb) {
|
||||||
|
if (conn->hooks->path_cb(conn, conn->request->uri, conn->arg) != EVHTP_RES_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_query_str_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_url_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_fragment_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_header_key_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
evhtp_header_t * header = NULL;
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)p->data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(header = calloc(sizeof(evhtp_header_t), sizeof(char)))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
header->key = malloc(len + 1);
|
||||||
|
header->key[len] = '\0';
|
||||||
|
|
||||||
|
memcpy(header->key, buf, len);
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&conn->request->headers, header, next);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_header_val_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
evhtp_header_t * header = NULL;
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)p->data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(header = TAILQ_LAST(&conn->request->headers, evhtp_headers))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
header->val = malloc(len + 1);
|
||||||
|
header->val[len] = '\0';
|
||||||
|
|
||||||
|
memcpy(header->val, buf, len);
|
||||||
|
|
||||||
|
if (conn->hooks && conn->hooks->single_header_cb) {
|
||||||
|
if (conn->hooks->single_header_cb(conn, header, conn->arg) != EVHTP_RES_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_htp_body_cb(http_parser * p, const char * buf, size_t len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evhtp_connection_free(evhtp_connection_t * conn) {
|
||||||
|
if (conn == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->hooks) {
|
||||||
|
/* evhtp_conn_hooks_free() */
|
||||||
|
free(conn->hooks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->parser) {
|
||||||
|
free(conn->parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->bev) {
|
||||||
|
bufferevent_free(conn->bev);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_htp_recv_cb(evbev_t * bev, void * arg) {
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
struct evbuffer * ibuf = NULL;
|
||||||
|
size_t nread = 0;
|
||||||
|
|
||||||
|
if (!(conn = (evhtp_connection_t *)arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ibuf = bufferevent_get_input(bev);
|
||||||
|
nread = http_parser_execute(conn->parser, &conn->evhtp->psets,
|
||||||
|
(const char *)evbuffer_pullup(ibuf, evbuffer_get_length(ibuf)),
|
||||||
|
evbuffer_get_length(ibuf));
|
||||||
|
|
||||||
|
evbuffer_drain(ibuf, nread);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_htp_accept_cb(evserv_t * serv, int fd, struct sockaddr * s, int sl, void * arg) {
|
||||||
|
evhtp_t * htp = NULL;
|
||||||
|
evbase_t * evbase = NULL;
|
||||||
|
evbev_t * bev = NULL;
|
||||||
|
evhtp_connection_t * conn = NULL;
|
||||||
|
|
||||||
|
if (!(htp = (evhtp_t *)arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (htp->pre_accept_cb != NULL) {
|
||||||
|
if (htp->pre_accept_cb(fd, s, sl, htp->arg) != EVHTP_RES_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evbase = evconnlistener_get_base(serv);
|
||||||
|
bev = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE);
|
||||||
|
|
||||||
|
if (!(conn = calloc(sizeof(evhtp_connection_t), sizeof(char)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->bev = bev;
|
||||||
|
conn->evhtp = htp;
|
||||||
|
conn->parser = malloc(sizeof(http_parser));
|
||||||
|
conn->parser->data = conn;
|
||||||
|
|
||||||
|
http_parser_init(conn->parser, HTTP_REQUEST);
|
||||||
|
|
||||||
|
if (htp->post_accept_cb != NULL) {
|
||||||
|
if (htp->post_accept_cb(conn, htp->arg) != EVHTP_RES_OK) {
|
||||||
|
evhtp_connection_free(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferevent_setcb(bev, _htp_recv_cb, NULL, NULL, (void *)conn);
|
||||||
|
bufferevent_enable(bev, EV_READ | EV_WRITE);
|
||||||
|
} /* _htp_accept_cb */
|
||||||
|
|
||||||
|
int
|
||||||
|
evhtp_set_pre_accept_cb(evhtp_t * htp, evhtp_pre_accept cb) {
|
||||||
|
if (htp == NULL || cb == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
htp->pre_accept_cb = cb;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evhtp_set_post_accept_cb(evhtp_t * htp, evhtp_post_accept cb) {
|
||||||
|
if (htp == NULL || cb == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
htp->post_accept_cb = cb;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
evhtp_t *
|
||||||
|
evhtp_new(evbase_t * evbase, evhtp_cfg * cfg, void * arg) {
|
||||||
|
struct sockaddr_in sin = { 0 };
|
||||||
|
evhtp_t * htp = NULL;
|
||||||
|
|
||||||
|
if (evbase == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(htp = calloc(sizeof(evhtp_t), sizeof(char)))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(cfg->bind_port);
|
||||||
|
sin.sin_addr.s_addr = inet_addr(cfg->bind_addr);
|
||||||
|
|
||||||
|
htp->psets.on_message_begin = _htp_start_cb;
|
||||||
|
htp->psets.on_headers_complete = _htp_headers_complete_cb;
|
||||||
|
htp->psets.on_message_complete = _htp_end_cb;
|
||||||
|
htp->psets.on_path = _htp_path_cb;
|
||||||
|
htp->psets.on_query_string = _htp_query_str_cb;
|
||||||
|
htp->psets.on_url = _htp_url_cb;
|
||||||
|
htp->psets.on_fragment = _htp_fragment_cb;
|
||||||
|
htp->psets.on_header_field = _htp_header_key_cb;
|
||||||
|
htp->psets.on_header_value = _htp_header_val_cb;
|
||||||
|
htp->psets.on_body = _htp_body_cb;
|
||||||
|
|
||||||
|
htp->evbase = evbase;
|
||||||
|
htp->config = cfg;
|
||||||
|
htp->pre_accept_cb = NULL;
|
||||||
|
htp->post_accept_cb = NULL;
|
||||||
|
htp->arg = arg;
|
||||||
|
|
||||||
|
htp->serv = evconnlistener_new_bind(evbase,
|
||||||
|
_htp_accept_cb, (void *)htp, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1,
|
||||||
|
(struct sockaddr *)&sin, sizeof(sin));
|
||||||
|
|
||||||
|
return htp;
|
||||||
|
} /* evhtp_new */
|
||||||
|
|
116
evhtp.h
Normal file
116
evhtp.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#ifndef __EVHTP_H__
|
||||||
|
#define __EVHTP_H__
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <event.h>
|
||||||
|
#include <event2/listener.h>
|
||||||
|
#include <http_parser.h>
|
||||||
|
|
||||||
|
typedef enum http_method evhtp_method;
|
||||||
|
typedef uint8_t evhtp_ver_major;
|
||||||
|
typedef uint8_t evhtp_ver_minor;
|
||||||
|
|
||||||
|
typedef struct event_base evbase_t;
|
||||||
|
typedef struct bufferevent evbev_t;
|
||||||
|
typedef struct evconnlistener evserv_t;
|
||||||
|
typedef struct evhtp_cfg evhtp_cfg;
|
||||||
|
typedef struct evhtp evhtp_t;
|
||||||
|
typedef struct evhtp_connection evhtp_connection_t;
|
||||||
|
typedef struct evhtp_headers evhtp_headers_t;
|
||||||
|
typedef struct evhtp_header evhtp_header_t;
|
||||||
|
typedef struct evhtp_conn_hooks evhtp_conn_hooks_t;
|
||||||
|
typedef struct evhtp_request evhtp_request_t;
|
||||||
|
|
||||||
|
typedef enum evhtp_hook_type evhtp_hook_type;
|
||||||
|
typedef enum evhtp_res evhtp_res;
|
||||||
|
|
||||||
|
typedef evhtp_res (*evhtp_pre_accept)(int fd, struct sockaddr *, int, void *);
|
||||||
|
typedef evhtp_res (*evhtp_post_accept)(evhtp_connection_t *, void *);
|
||||||
|
|
||||||
|
typedef evhtp_res (*evhtp_hook_post_headers)(evhtp_connection_t *, evhtp_headers_t *, void *);
|
||||||
|
typedef evhtp_res (*evhtp_hook_single_header)(evhtp_connection_t *, evhtp_header_t *, void *);
|
||||||
|
typedef evhtp_res (*evhtp_hook_on_path)(evhtp_connection_t *, const char *, void *);
|
||||||
|
typedef evhtp_res (*evhtp_hook_on_body_read)(evhtp_connection_t *, const char *, size_t, void *);
|
||||||
|
typedef evhtp_res (*evhtp_hook_complete)(evhtp_connection_t *, evhtp_request_t *, void *);
|
||||||
|
|
||||||
|
typedef int (*evhtp_headers_iter_cb)(evhtp_header_t * header, void * arg);
|
||||||
|
|
||||||
|
struct evhtp_request;
|
||||||
|
struct evhtp_headers;
|
||||||
|
struct evhtp_header;
|
||||||
|
|
||||||
|
struct evhtp_cfg {
|
||||||
|
char * base_uri;
|
||||||
|
char * bind_addr;
|
||||||
|
uint16_t bind_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct evhtp {
|
||||||
|
evhtp_cfg * config;
|
||||||
|
evbase_t * evbase;
|
||||||
|
evserv_t * serv;
|
||||||
|
void * arg;
|
||||||
|
evhtp_pre_accept pre_accept_cb;
|
||||||
|
evhtp_post_accept post_accept_cb;
|
||||||
|
http_parser_settings psets;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct evhtp_connection {
|
||||||
|
evhtp_conn_hooks_t * hooks;
|
||||||
|
evhtp_request_t * request;
|
||||||
|
http_parser * parser;
|
||||||
|
evbev_t * bev;
|
||||||
|
evhtp_t * evhtp;
|
||||||
|
void * arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct evhtp_header {
|
||||||
|
char * key;
|
||||||
|
char * val;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(evhtp_header) next;
|
||||||
|
};
|
||||||
|
|
||||||
|
TAILQ_HEAD(evhtp_headers, evhtp_header);
|
||||||
|
|
||||||
|
struct evhtp_request {
|
||||||
|
evhtp_headers_t headers;
|
||||||
|
evhtp_method method;
|
||||||
|
evhtp_ver_major major;
|
||||||
|
evhtp_ver_minor minor;
|
||||||
|
char * uri;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum evhtp_hook_type {
|
||||||
|
EVHTP_HOOK_POST_HEADERS = 1,
|
||||||
|
EVHTP_HOOK_SINGLE_HEADER,
|
||||||
|
EVHTP_HOOK_ON_PATH,
|
||||||
|
EVHTP_HOOK_ON_BODY_READ,
|
||||||
|
EVHTP_HOOK_COMPLETE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum evhtp_res {
|
||||||
|
EVHTP_RES_OK = 0,
|
||||||
|
EVHTP_RES_DISCONNECT,
|
||||||
|
EVHTP_RES_CORRUPTED,
|
||||||
|
EVHTP_RES_ERROR,
|
||||||
|
EVHTP_RES_CONTINUE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct evhtp_conn_hooks {
|
||||||
|
evhtp_hook_post_headers post_headers_cb;
|
||||||
|
evhtp_hook_single_header single_header_cb;
|
||||||
|
evhtp_hook_on_path path_cb;
|
||||||
|
evhtp_hook_on_body_read body_read_cb;
|
||||||
|
evhtp_hook_complete complete_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
evhtp_t * evhtp_new(evbase_t *, evhtp_cfg *, void *);
|
||||||
|
evhtp_request_t * evhtp_request_new(void);
|
||||||
|
int evhtp_set_post_accept_cb(evhtp_t *, evhtp_post_accept);
|
||||||
|
int evhtp_set_pre_accept_cb(evhtp_t *, evhtp_pre_accept);
|
||||||
|
int evhtp_conn_hook(evhtp_connection_t *, evhtp_hook_type, void * cb);
|
||||||
|
int evhtp_headers_for_each(evhtp_headers_t *, evhtp_headers_iter_cb, void *);
|
||||||
|
void evhtp_connection_free(evhtp_connection_t *);
|
||||||
|
#endif /* __EVHTP_H__ */
|
||||||
|
|
1
http_parser
Submodule
1
http_parser
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 9639c7c21c868cc743f5cce9ec1cffc1cbcafe01
|
76
test.c
Normal file
76
test.c
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <evhtp.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
dump_hdrs_cb(evhtp_header_t * header, void * arg) {
|
||||||
|
printf("key = '%s', val = '%s'\n", header->key, header->val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evhtp_res
|
||||||
|
test_post_headers_cb(evhtp_connection_t * conn, evhtp_headers_t * hdrs, void * arg) {
|
||||||
|
printf("test_post_headers_cb()\n");
|
||||||
|
|
||||||
|
evhtp_headers_for_each(hdrs, dump_hdrs_cb, NULL);
|
||||||
|
return EVHTP_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evhtp_res
|
||||||
|
test_single_header_cb(evhtp_connection_t * conn, evhtp_header_t * hdr, void * arg) {
|
||||||
|
printf("test_single_header_cb()\n");
|
||||||
|
printf("key = '%s', val='%s'\n", hdr->key, hdr->val);
|
||||||
|
return EVHTP_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evhtp_res
|
||||||
|
test_on_path_cb(evhtp_connection_t * conn, const char * uri) {
|
||||||
|
printf("test_on_path_cb()\n");
|
||||||
|
printf("uri = '%s'\n", uri);
|
||||||
|
return EVHTP_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evhtp_res
|
||||||
|
test_complete_cb(evhtp_connection_t * conn, evhtp_request_t * req, void * arg) {
|
||||||
|
printf("test_complete_cb()\n");
|
||||||
|
printf("method: %d\n", req->method);
|
||||||
|
printf("uri: %s\n", req->uri);
|
||||||
|
printf("vmajor: %d\n", req->major);
|
||||||
|
printf("vminor: %d\n", req->minor);
|
||||||
|
|
||||||
|
return EVHTP_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static evhtp_res
|
||||||
|
test_post_accept_cb(evhtp_connection_t * conn, void * arg) {
|
||||||
|
printf("test_post_accept_cb()\n");
|
||||||
|
|
||||||
|
evhtp_conn_hook(conn, EVHTP_HOOK_SINGLE_HEADER, test_single_header_cb);
|
||||||
|
evhtp_conn_hook(conn, EVHTP_HOOK_POST_HEADERS, test_post_headers_cb);
|
||||||
|
evhtp_conn_hook(conn, EVHTP_HOOK_ON_PATH, test_on_path_cb);
|
||||||
|
evhtp_conn_hook(conn, EVHTP_HOOK_COMPLETE, test_complete_cb);
|
||||||
|
return EVHTP_RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char ** argv) {
|
||||||
|
int res = 0;
|
||||||
|
evbase_t * evbase = NULL;
|
||||||
|
evhtp_t * htp = NULL;
|
||||||
|
evhtp_cfg cfg = {
|
||||||
|
.base_uri = "/",
|
||||||
|
.bind_addr = "0.0.0.0",
|
||||||
|
.bind_port = 8080
|
||||||
|
};
|
||||||
|
|
||||||
|
evbase = event_base_new();
|
||||||
|
htp = evhtp_new(evbase, &cfg, NULL);
|
||||||
|
res = evhtp_set_post_accept_cb(htp, test_post_accept_cb);
|
||||||
|
|
||||||
|
event_base_loop(evbase, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue