Merge branch 'feature-pangu-http-test' of git.mesalab.cn:tango/tfe into feature-pangu-http-test

# Conflicts:
#	plugin/business/pangu-http/pangu_http.cpp
This commit is contained in:
zhengchao
2018-09-19 14:27:37 +08:00
12 changed files with 303 additions and 64 deletions

View File

@@ -6,6 +6,7 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall) set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall)
enable_testing()
add_subdirectory(vendor) add_subdirectory(vendor)
add_subdirectory(common) add_subdirectory(common)
add_subdirectory(plugin) add_subdirectory(plugin)

View File

@@ -201,42 +201,10 @@ typedef void (http_session_data_cb)(const struct tfe_stream * stream,
typedef void (http_session_end_cb)(const struct tfe_stream * stream, typedef void (http_session_end_cb)(const struct tfe_stream * stream,
const struct tfe_http_session * session, unsigned int thread_id, void ** pme); const struct tfe_http_session * session, unsigned int thread_id, void ** pme);
static inline struct http_field_name * http_field_name_duplicate(const struct http_field_name * orig) struct http_field_name * http_field_name_duplicate(const struct http_field_name * orig);
{ int http_field_name_compare(const struct http_field_name * lvalue, const struct http_field_name * rvalue);
struct http_field_name * __duplicated = ALLOC(struct http_field_name, 1); const char * http_field_to_string(const struct http_field_name * field);
assert(__duplicated != NULL); void http_field_destory(struct http_field_name *);
if (orig->field_id == TFE_HTTP_UNKNOWN_FIELD)
{
__duplicated->field_id = TFE_HTTP_UNKNOWN_FIELD;
__duplicated->field_name = tfe_strdup(orig->field_name);
}
else
{
__duplicated->field_id = orig->field_id;
__duplicated->field_name = NULL;
}
return __duplicated;
}
static inline int http_field_name_compare(const struct http_field_name * lvalue,
const struct http_field_name * rvalue)
{
if (lvalue->field_id != rvalue->field_id)
{
return (lvalue->field_id - rvalue->field_id);
}
/* unknown field, compare field_name in string */
if (lvalue->field_id == TFE_HTTP_UNKNOWN_FIELD)
{
return strcasecmp(lvalue->field_name, rvalue->field_name);
}
/* field_id is equal, but not unknown, hit */
return 0;
}
static inline const char * tfe_http_field_read(const struct tfe_http_half * half, static inline const char * tfe_http_field_read(const struct tfe_http_half * half,
const struct http_field_name * name) const struct http_field_name * name)

View File

@@ -14,6 +14,87 @@ struct tfe_http_half * tfe_http_response_create(int major_version, int resp_code
return NULL; return NULL;
} }
static const char * __str_std_header_field_map[] =
{
[TFE_HTTP_UNKNOWN_FIELD] = NULL,
[TFE_HTTP_HOST] = "Host",
[TFE_HTTP_REFERER] = "Referer",
[TFE_HTTP_USER_AGENT] = "User-Agent",
[TFE_HTTP_COOKIE] = "Cookie",
[TFE_HTTP_PROXY_AUTHORIZATION] = "Proxy-Authorization",
[TFE_HTTP_AUTHORIZATION] = "Authorization",
[TFE_HTTP_LOCATION] = "Location",
[TFE_HTTP_SERVER] = "Server",
[TFE_HTTP_ETAG] = "Etag",
[TFE_HTTP_DATE] = "Date",
[TFE_HTTP_TRAILER] = "Trailer",
[TFE_HTTP_TRANSFER_ENCODING] = "Transfer-Encoding",
[TFE_HTTP_VIA] = "Via",
[TFE_HTTP_PRAGMA] = "Pragma",
[TFE_HTTP_CONNECTION] = "Connection",
[TFE_HTTP_CONT_ENCODING] = "Content-Encoding",
[TFE_HTTP_CONT_LANGUAGE] = "Content-Language",
[TFE_HTTP_CONT_LOCATION] = "Content-Location",
[TFE_HTTP_CONT_RANGE] = "Content-Range",
[TFE_HTTP_CONT_LENGTH] = "Content-Length",
[TFE_HTTP_CONT_TYPE] = "Content-Type",
[TFE_HTTP_CONT_DISPOSITION] = "Content-Disposition",
[TFE_HTTP_EXPIRES] = "Expires",
[TFE_HTTP_ACCEPT_ENCODING] = "Accept-Encoding"
};
struct http_field_name * http_field_name_duplicate(const struct http_field_name * orig)
{
struct http_field_name * __duplicated = ALLOC(struct http_field_name, 1);
assert(__duplicated != NULL);
if (orig->field_id == TFE_HTTP_UNKNOWN_FIELD)
{
__duplicated->field_id = TFE_HTTP_UNKNOWN_FIELD;
__duplicated->field_name = tfe_strdup(orig->field_name);
}
else
{
__duplicated->field_id = orig->field_id;
__duplicated->field_name = NULL;
}
return __duplicated;
}
int http_field_name_compare(const struct http_field_name * lvalue, const struct http_field_name * rvalue)
{
if (lvalue->field_id != rvalue->field_id)
{
return (lvalue->field_id - rvalue->field_id);
}
/* unknown field, compare field_name in string */
if (lvalue->field_id == TFE_HTTP_UNKNOWN_FIELD)
{
return strcasecmp(lvalue->field_name, rvalue->field_name);
}
/* field_id is equal, but not unknown, hit */
return 0;
}
struct http_field_name * http_field_construct_from_string(const char * str_field)
{
return NULL;
}
const char * http_field_to_string(const struct http_field_name * field)
{
if (field->field_id != TFE_HTTP_UNKNOWN_FIELD) return __str_std_header_field_map[field->field_id];
return field->field_name;
}
void http_field_destory(struct http_field_name * field)
{
free(field);
}
struct http_frame_session_ctx struct http_frame_session_ctx
{ {
struct http_frame_plugin_status * plugin_status; struct http_frame_plugin_status * plugin_status;

View File

@@ -1032,7 +1032,8 @@ static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt)
SSL_CTX_set_session_cache_mode(sslctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_set_session_cache_mode(sslctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL);
SSL_CTX_set_session_id_context(sslctx, (const unsigned char *) mgr->ssl_session_context, SSL_CTX_set_session_id_context(sslctx, (const unsigned char *) mgr->ssl_session_context,
sizeof(mgr->ssl_session_context)); sizeof(mgr->ssl_session_context));
ret = SSL_CTX_set_ex_data(sslctx, SSL_EX_DATA_IDX_SSLMGR, mgr);
assert(ret == 1);
if (mgr->dh) if (mgr->dh)
{ {
SSL_CTX_set_tmp_dh(sslctx, mgr->dh); SSL_CTX_set_tmp_dh(sslctx, mgr->dh);

View File

@@ -1,5 +1,6 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -337,10 +338,15 @@ static void __stream_bev_readcb(struct bufferevent * bev, void * arg)
if (_stream->is_plugin_opened == 0) if (_stream->is_plugin_opened == 0)
{ {
p_info_iter->on_open(&_stream->head, _stream->thread_ref->thread_id, dir, &(plug_ctx->pme)); if (p_info_iter->on_open != NULL)
{
p_info_iter->on_open(&_stream->head, _stream->thread_ref->thread_id, dir, &(plug_ctx->pme));
}
_stream->is_plugin_opened = 1; _stream->is_plugin_opened = 1;
} }
else
if (p_info_iter->on_data != NULL)
{ {
action_tmp = p_info_iter->on_data(&_stream->head, _stream->thread_ref->thread_id, action_tmp = p_info_iter->on_data(&_stream->head, _stream->thread_ref->thread_id,
dir, contiguous_data, contigous_len, &(plug_ctx->pme)); dir, contiguous_data, contigous_len, &(plug_ctx->pme));
@@ -634,6 +640,67 @@ void tfe_stream_destory(struct tfe_stream_private * stream)
thread->load--; thread->load--;
} }
static struct tfe_stream_addr * __stream_addr_create_by_fds(struct tfe_stream * stream, evutil_socket_t fd_downstream)
{
struct tfe_stream_addr * __stream_addr = NULL;
struct sockaddr_storage sk_src_storage{};
struct sockaddr * sk_src_ptr = (struct sockaddr *) &sk_src_storage;
socklen_t sk_src_len = sizeof(sk_src_storage);
struct sockaddr_storage sk_dst_storage{};
struct sockaddr * sk_dst_ptr = (struct sockaddr *) &sk_dst_storage;
socklen_t sk_dst_len = sizeof(sk_dst_storage);
int ret = getsockname(fd_downstream, sk_src_ptr, &sk_src_len);
if (unlikely(ret < 0))
{
TFE_STREAM_LOG_ERROR(stream, "Failed at calling getsockaddr() for fd %d : %s", fd_downstream, strerror(errno));
goto __errout;
}
ret = getpeername(fd_downstream, sk_dst_ptr, &sk_dst_len);
if (unlikely(ret < 0))
{
TFE_STREAM_LOG_ERROR(stream, "Failed at calling getpeername() for fd %d : %s", fd_downstream, strerror(errno));
goto __errout;
}
assert(sk_src_ptr->sa_family == sk_dst_ptr->sa_family);
if (sk_src_ptr->sa_family == AF_INET)
{
__stream_addr = (struct tfe_stream_addr *) malloc(
sizeof(struct tfe_stream_addr) + sizeof(struct tfe_stream_addr_tuple4_v4));
struct tfe_stream_addr_ipv4 * st_addr_v4 = __stream_addr->ipv4;
struct sockaddr_in * sk_v4_src_ptr = (struct sockaddr_in *)sk_src_ptr;
struct sockaddr_in * sk_v4_dst_ptr = (struct sockaddr_in *)sk_dst_ptr;
__stream_addr->addrtype = TFE_ADDR_STREAM_TUPLE4_V4;
__stream_addr->addrlen = sizeof(struct tfe_stream_addr_tuple4_v4);
st_addr_v4->saddr.s_addr = sk_v4_src_ptr->sin_addr.s_addr;
st_addr_v4->source = sk_v4_src_ptr->sin_port;
st_addr_v4->daddr.s_addr = sk_v4_dst_ptr->sin_addr.s_addr;
st_addr_v4->dest = sk_v4_dst_ptr->sin_port;
}
else if (sk_src_ptr->sa_family == AF_INET6)
{
assert(0);
}
else
{
TFE_STREAM_LOG_ERROR(stream, "Invalid sockaddr family for fd %d: sa_family is %d.",
fd_downstream, sk_src_ptr->sa_family); goto __errout;
}
return __stream_addr;
__errout:
if (__stream_addr != NULL) free(__stream_addr);
return NULL;
}
void tfe_stream_init_by_fds(struct tfe_stream * stream, evutil_socket_t fd_downstream, evutil_socket_t fd_upstream) void tfe_stream_init_by_fds(struct tfe_stream * stream, evutil_socket_t fd_downstream, evutil_socket_t fd_upstream)
{ {
struct tfe_stream_private * _stream = container_of(stream, struct tfe_stream_private, head); struct tfe_stream_private * _stream = container_of(stream, struct tfe_stream_private, head);
@@ -645,6 +712,12 @@ void tfe_stream_init_by_fds(struct tfe_stream * stream, evutil_socket_t fd_downs
evutil_make_socket_nonblocking(fd_downstream); evutil_make_socket_nonblocking(fd_downstream);
evutil_make_socket_nonblocking(fd_upstream); evutil_make_socket_nonblocking(fd_upstream);
_stream->head.addr = __stream_addr_create_by_fds(stream, fd_downstream);
if(unlikely(_stream->head.addr == NULL))
{
assert(0);
}
if (_stream->session_type == STREAM_PROTO_PLAIN) if (_stream->session_type == STREAM_PROTO_PLAIN)
{ {
_stream->conn_downstream = __conn_private_create_by_fd(_stream, fd_downstream); _stream->conn_downstream = __conn_private_create_by_fd(_stream, fd_downstream);

View File

@@ -808,8 +808,11 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht
{ {
break; break;
} }
scan_ret=Maat_set_scan_status(g_pangu_rt->maat, &(ctx->mid), MAAT_SET_SCAN_DISTRICT,
field_name.field_name,strlen(field_name.field_name)); const char * str_field_name = http_field_to_string(&field_name);
scan_ret=Maat_set_scan_status(g_pangu_rt->maat, &(ctx->mid), MAAT_SET_SCAN_DISTRICT,
str_field_name,strlen(str_field_name));
assert(scan_ret==0); assert(scan_ret==0);
scan_ret=Maat_full_scan_string(g_pangu_rt->maat, table_id, scan_ret=Maat_full_scan_string(g_pangu_rt->maat, table_id,
CHARSET_UTF8, field_val, strlen(field_val), CHARSET_UTF8, field_val, strlen(field_val),
@@ -886,6 +889,8 @@ void pangu_on_http_begin(const struct tfe_stream * stream,
{ {
tfe_http_session_detach(session); tfe_http_session_detach(session);
} }
*pme=ctx;
return; return;
} }

View File

@@ -1,3 +1,4 @@
### PLUGIN
add_library(http src/http_entry.cpp src/http_half.cpp) add_library(http src/http_entry.cpp src/http_half.cpp)
target_include_directories(http PRIVATE include/internal) target_include_directories(http PRIVATE include/internal)
@@ -6,3 +7,12 @@ target_include_directories(http PUBLIC incluce/external)
target_link_libraries(http common) target_link_libraries(http common)
target_link_libraries(http http-parser-static) target_link_libraries(http http-parser-static)
target_link_libraries(http libevent-static) target_link_libraries(http libevent-static)
### UNITTEST CASE
add_executable(test-http-half test/test_http_half.cpp)
target_include_directories(test-http-half PRIVATE include/internal)
target_link_libraries(test-http-half gtest common http)
include(GoogleTest)
gtest_discover_tests(test-http-half)

View File

@@ -51,8 +51,12 @@ struct http_half_private
short minor; short minor;
struct evbuffer * evbuf_uri; struct evbuffer * evbuf_uri;
struct evbuffer * evbuf_header_field; struct evbuffer * evbuf_header_field;
struct evbuffer * evbuf_header_value; struct evbuffer * evbuf_header_value;
bool is_evbuf_header_field_set;
bool is_evbuf_header_value_set;
struct evbuffer * evbuf_body; struct evbuffer * evbuf_body;
enum hf_private_status body_status; enum hf_private_status body_status;
@@ -64,6 +68,7 @@ struct http_half_private
}; };
struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor); struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor);
void hf_private_destory(struct http_half_private * hf_private); void hf_private_destory(struct http_half_private * hf_private);
/** Parse the raw tcp input for HTTP half structure /** Parse the raw tcp input for HTTP half structure
@@ -83,5 +88,7 @@ int hf_private_parse(struct http_half_private * hf_private, const unsigned char
void hf_private_set_callback(struct http_half_private * hf_private, hf_private_cb * cb, void hf_private_set_callback(struct http_half_private * hf_private, hf_private_cb * cb,
void * user, void (* fn_user_deleter)(void *)); void * user, void (* fn_user_deleter)(void *));
void hf_private_set_session(struct http_half_private * hf_private, struct http_session_private * hs_private);
struct http_session_private * hs_private_create(struct http_connection_private * hc_private, struct http_session_private * hs_private_create(struct http_connection_private * hc_private,
struct http_half_private * hf_private_req, struct http_half_private * hf_private_resp); struct http_half_private * hf_private_req, struct http_half_private * hf_private_resp);

View File

@@ -67,6 +67,7 @@ enum tfe_stream_action __http_connection_entry_on_request(const struct tfe_strea
/* HTTP Request and Session */ /* HTTP Request and Session */
hf_private_request = hf_private_create(TFE_HTTP_REQUEST, 1, 0); hf_private_request = hf_private_create(TFE_HTTP_REQUEST, 1, 0);
hs_private = hs_private_create(hc_private, hf_private_request, NULL); hs_private = hs_private_create(hc_private, hf_private_request, NULL);
hf_private_set_session(hf_private_request, hs_private);
/* Closure, catch stream, session and thread_id */ /* Closure, catch stream, session and thread_id */
struct user_event_dispatch_closure * __closure = ALLOC(struct user_event_dispatch_closure, 1); struct user_event_dispatch_closure * __closure = ALLOC(struct user_event_dispatch_closure, 1);
@@ -139,13 +140,13 @@ enum tfe_stream_action __http_connection_entry_on_response(const struct tfe_stre
int __http_connection_identify(const struct tfe_stream * stream, int __http_connection_identify(const struct tfe_stream * stream,
struct http_connection_private * ht_conn, const unsigned char * data, size_t len) struct http_connection_private * ht_conn, const unsigned char * data, size_t len)
{ {
struct http_half_private * hf_private = hf_private_create(TFE_HTTP_RESPONSE, 1, 0); struct http_half_private * hf_private = hf_private_create(TFE_HTTP_REQUEST, 1, 0);
int ret = hf_private_parse(hf_private, data, len); int ret = hf_private_parse(hf_private, data, len);
hf_private_destory(hf_private); hf_private_destory(hf_private);
return ret; return ret;
} }
#define HTTP_INDENTIFY_LENGTH 8 #define HTTP_INDENTIFY_LENGTH 4
enum tfe_stream_action http_connection_entry_data(const struct tfe_stream * stream, unsigned int thread_id, enum tfe_stream_action http_connection_entry_data(const struct tfe_stream * stream, unsigned int thread_id,
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme) enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme)
@@ -159,12 +160,7 @@ enum tfe_stream_action http_connection_entry_data(const struct tfe_stream * stre
goto __detach; goto __detach;
/* Protocol Identification, we need 8 bytes at least to tell it is HTTP or not */ /* Protocol Identification, we need 8 bytes at least to tell it is HTTP or not */
if (len < HTTP_INDENTIFY_LENGTH) if (len < HTTP_INDENTIFY_LENGTH) goto __detach;
{
static const unsigned int __defer_bytes = HTTP_INDENTIFY_LENGTH;
tfe_stream_action_set_opt(stream, ACTION_OPT_DEFER_BYTES, (void *) &__defer_bytes, sizeof(__defer_bytes));
return ACTION_DEFER_DATA;
}
/* Now, we want to identify this stream */ /* Now, we want to identify this stream */
int ret = __http_connection_identify(stream, ht_conn, data, len); int ret = __http_connection_identify(stream, ht_conn, data, len);

View File

@@ -84,6 +84,8 @@ static void __http_half_header_kv_complete(struct http_half_private * hf_private
/* Write a '\0' for evbuffers */ /* Write a '\0' for evbuffers */
evbuffer_add(hf_private->evbuf_header_field, &__zero, sizeof(__zero)); evbuffer_add(hf_private->evbuf_header_field, &__zero, sizeof(__zero));
evbuffer_add(hf_private->evbuf_header_value, &__zero, sizeof(__zero)); evbuffer_add(hf_private->evbuf_header_value, &__zero, sizeof(__zero));
sz_evbuf_field = evbuffer_get_length(hf_private->evbuf_header_field);
sz_evbuf_value = evbuffer_get_length(hf_private->evbuf_header_value);
/* Convert evbuffer to const char * pair */ /* Convert evbuffer to const char * pair */
str_field = (const char *) evbuffer_pullup(hf_private->evbuf_header_field, sz_evbuf_field); str_field = (const char *) evbuffer_pullup(hf_private->evbuf_header_field, sz_evbuf_field);
@@ -107,6 +109,8 @@ static void __http_half_header_kv_complete(struct http_half_private * hf_private
__clear_buffer: __clear_buffer:
evbuffer_drain(hf_private->evbuf_header_field, sz_evbuf_field); evbuffer_drain(hf_private->evbuf_header_field, sz_evbuf_field);
evbuffer_drain(hf_private->evbuf_header_value, sz_evbuf_value); evbuffer_drain(hf_private->evbuf_header_value, sz_evbuf_value);
hf_private->is_evbuf_header_value_set = false;
hf_private->is_evbuf_header_field_set = false;
} }
void __hf_public_req_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser) void __hf_public_req_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser)
@@ -117,10 +121,10 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st
/* accept-encoding, host is located in header's K-V structure */ /* accept-encoding, host is located in header's K-V structure */
hf_req_spec->method = (enum tfe_http_std_method) parser->method; hf_req_spec->method = (enum tfe_http_std_method) parser->method;
const static struct http_field_name __host_field_name = const static struct http_field_name __host_field_name =
{ {
.field_id = TFE_HTTP_HOST, .field_id = TFE_HTTP_HOST,
.field_name = NULL .field_name = NULL
}; };
hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name); hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name);
@@ -131,7 +135,7 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st
/* TODO: URL /* TODO: URL
* url is more complex. need to review RFC */ * url is more complex. need to review RFC */
hf_req_spec->url = NULL; hf_req_spec->url = hf_req_spec->uri;
} }
void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser) void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser)
@@ -142,10 +146,10 @@ void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, s
/* Status Code */ /* Status Code */
hf_resp_spec->resp_code = parser->status_code; hf_resp_spec->resp_code = parser->status_code;
const static struct http_field_name __cont_encoding_field_name = const static struct http_field_name __cont_encoding_field_name =
{ {
.field_id = TFE_HTTP_CONT_ENCODING, .field_id = TFE_HTTP_CONT_ENCODING,
.field_name = NULL .field_name = NULL
}; };
/* Content Encoding */ /* Content Encoding */
hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name); hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name);
@@ -164,11 +168,13 @@ static int __parser_callback_on_message_begin(struct http_parser * parser)
assert(hf_private->evbuf_uri == NULL && hf_private->evbuf_body == NULL); assert(hf_private->evbuf_uri == NULL && hf_private->evbuf_body == NULL);
assert(hf_private->evbuf_header_field == NULL && hf_private->evbuf_header_value == NULL); assert(hf_private->evbuf_header_field == NULL && hf_private->evbuf_header_value == NULL);
hf_private->evbuf_uri = evbuffer_new();
hf_private->evbuf_header_field = evbuffer_new(); hf_private->evbuf_header_field = evbuffer_new();
hf_private->evbuf_header_value = evbuffer_new(); hf_private->evbuf_header_value = evbuffer_new();
hf_private->evbuf_body = evbuffer_new(); hf_private->is_evbuf_header_field_set = false;
hf_private->is_evbuf_header_value_set = false;
hf_private->evbuf_uri = evbuffer_new();
hf_private->evbuf_body = evbuffer_new();
hf_private->body_status = STATUS_INIT; hf_private->body_status = STATUS_INIT;
hf_private->message_status = STATUS_READING; hf_private->message_status = STATUS_READING;
@@ -186,19 +192,19 @@ static int __parser_callback_on_uri_field(struct http_parser * parser, const cha
static int __parser_callback_on_header_field(struct http_parser * parser, const char * at, size_t length) static int __parser_callback_on_header_field(struct http_parser * parser, const char * at, size_t length)
{ {
struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser);
if (hf_private->is_evbuf_header_field_set && hf_private->is_evbuf_header_value_set)
/* Last field-value tuple doesn't push into hf_private, flush these */
if (evbuffer_get_length(hf_private->evbuf_header_field) != 0)
{ {
__http_half_header_kv_complete(hf_private); __http_half_header_kv_complete(hf_private);
} }
hf_private->is_evbuf_header_field_set = true;
return evbuffer_add(hf_private->evbuf_header_field, at, length); return evbuffer_add(hf_private->evbuf_header_field, at, length);
} }
static int __parser_callback_on_header_value(struct http_parser * parser, const char * at, size_t length) static int __parser_callback_on_header_value(struct http_parser * parser, const char * at, size_t length)
{ {
struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser);
hf_private->is_evbuf_header_value_set = true;
return evbuffer_add(hf_private->evbuf_header_value, at, length); return evbuffer_add(hf_private->evbuf_header_value, at, length);
} }
@@ -429,6 +435,8 @@ struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short ma
hf_private->parse_settings = &__http_half_parse_setting; hf_private->parse_settings = &__http_half_parse_setting;
hf_private->parse_object->data = hf_private; hf_private->parse_object->data = hf_private;
TAILQ_INIT(&hf_private->header_list);
return hf_private; return hf_private;
} }
@@ -440,6 +448,11 @@ void hf_private_set_callback(struct http_half_private * hf_private, hf_private_c
hf_private->event_cb_user_deleter = user_deleter; hf_private->event_cb_user_deleter = user_deleter;
} }
void hf_private_set_session(struct http_half_private * hf_private, struct http_session_private * hs_private)
{
hf_private->session = hs_private;
}
int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len) int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len)
{ {
assert(hf_private->parse_cursor <= len); assert(hf_private->parse_cursor <= len);

View File

@@ -0,0 +1,83 @@
#include <gtest/gtest.h>
#include <http_half.h>
static const char * __identify_http_request =
"POST /gen_204 HTTP/1.1\r\n"
"Host: www.google.com\r\n"
"Connection: close\r\n"
"Content-Length: 0\r\n"
"Origin: https://www.google.com\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n"
"Content-Type: text/plain;charset=UTF-8\r\n"
"Accept: */*\r\n"
"X-Client-Data: CJG2yQEIorbJAQjEtskBCKmdygEI2J3KAQjZncoBCKijygEY+aXKAQ==\r\n"
"Referer: https://www.google.com/\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7\r\n";
static const char * __identify_not_http_request = "MZMZ";
TEST(HttpHalfConstruct, ProtoIdentifyIsHTTP)
{
auto * hf_request = hf_private_create(TFE_HTTP_REQUEST, 1, 1);
ASSERT_TRUE(hf_request != NULL);
int ret = hf_private_parse(hf_request, (const unsigned char *) __identify_http_request,
strlen(__identify_http_request));
EXPECT_EQ(ret, 0);
}
TEST(HttpHalfConstruct, ProtoIdentifyNotHTTP)
{
auto * hf_request = hf_private_create(TFE_HTTP_REQUEST, 1, 1);
ASSERT_TRUE(hf_request != NULL);
int ret = hf_private_parse(hf_request, (const unsigned char *) __identify_not_http_request,
strlen(__identify_not_http_request));
EXPECT_EQ(ret, -1);
}
static const char * __get_http_request_01 =
"GET /gfwlist/gfwlist/master/gfwlist.txt HTTP/1.1\r\n"
"Host: raw.githubusercontent.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n"
"Accept: */*\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7\r\n"
"If-None-Match: \"023aeae5eafc12082067c36031888adb3bafa797\"\r\n"
"\r\n";
void __get_http_request_01_verify_helper(struct http_half_private * hf_private)
{
auto * hf_public = &hf_private->hf_public;
EXPECT_EQ(hf_public->major_version, 1);
EXPECT_EQ(hf_public->minor_version, 1);
auto * hf_public_request = &hf_public->req_spec;
EXPECT_STREQ(hf_public_request->uri, "/gfwlist/gfwlist/master/gfwlist.txt");
EXPECT_STREQ(hf_public_request->url, "/gfwlist/gfwlist/master/gfwlist.txt");
EXPECT_STREQ(hf_public_request->host, "raw.githubusercontent.com");
EXPECT_EQ(hf_public_request->method, TFE_HTTP_GET);
}
TEST(HttpHalfConstruct, GetWithNoBody)
{
auto * hf_request = hf_private_create(TFE_HTTP_REQUEST, 0, 0);
ASSERT_TRUE(hf_request != NULL);
int ret =
hf_private_parse(hf_request, (const unsigned char *) __get_http_request_01, strlen(__get_http_request_01));
ASSERT_EQ(ret, 0);
__get_http_request_01_verify_helper(hf_request);
}
int main(int argc, char ** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -112,9 +112,10 @@ file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
add_library(gtest STATIC IMPORTED GLOBAL) add_library(gtest STATIC IMPORTED GLOBAL)
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgtest.a) set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgtest.a)
set_property(TARGET gtest PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) set_property(TARGET gtest PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
set_property(TARGET gtest PROPERTY INTERFACE_LINK_LIBRARIES pthread)
add_library(gmock STATIC IMPORTED GLOBAL) add_library(gmock STATIC IMPORTED GLOBAL)
set_property(TARGET gmock PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgtest.a) set_property(TARGET gmock PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgmock.a)
set_property(TARGET gmock PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) set_property(TARGET gmock PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)