diff --git a/CMakeLists.txt b/CMakeLists.txt index a3f6663..0dfc2f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_C_STANDARD 11) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall) +enable_testing() add_subdirectory(vendor) add_subdirectory(common) add_subdirectory(plugin) diff --git a/common/include/tfe_http.h b/common/include/tfe_http.h index f0ba194..14f8342 100644 --- a/common/include/tfe_http.h +++ b/common/include/tfe_http.h @@ -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, 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 * __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; -} - -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; -} +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); +const char * http_field_to_string(const struct http_field_name * field); +void http_field_destory(struct http_field_name *); static inline const char * tfe_http_field_read(const struct tfe_http_half * half, const struct http_field_name * name) diff --git a/common/src/tfe_http.cpp b/common/src/tfe_http.cpp index 42b0a89..5916121 100644 --- a/common/src/tfe_http.cpp +++ b/common/src/tfe_http.cpp @@ -14,6 +14,87 @@ struct tfe_http_half * tfe_http_response_create(int major_version, int resp_code 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_plugin_status * plugin_status; diff --git a/platform/src/ssl_stream.cpp b/platform/src/ssl_stream.cpp index b93a64e..17bef3a 100644 --- a/platform/src/ssl_stream.cpp +++ b/platform/src/ssl_stream.cpp @@ -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_id_context(sslctx, (const unsigned char *) 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) { SSL_CTX_set_tmp_dh(sslctx, mgr->dh); diff --git a/platform/src/tcp_stream.cpp b/platform/src/tcp_stream.cpp index dc6606d..0b64a2d 100644 --- a/platform/src/tcp_stream.cpp +++ b/platform/src/tcp_stream.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -337,10 +338,15 @@ static void __stream_bev_readcb(struct bufferevent * bev, void * arg) 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; } - else + + if (p_info_iter->on_data != NULL) { action_tmp = p_info_iter->on_data(&_stream->head, _stream->thread_ref->thread_id, dir, contiguous_data, contigous_len, &(plug_ctx->pme)); @@ -634,6 +640,67 @@ void tfe_stream_destory(struct tfe_stream_private * stream) 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) { 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_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) { _stream->conn_downstream = __conn_private_create_by_fd(_stream, fd_downstream); diff --git a/plugin/business/pangu-http/pangu_http.cpp b/plugin/business/pangu-http/pangu_http.cpp index b07f3a4..650520a 100644 --- a/plugin/business/pangu-http/pangu_http.cpp +++ b/plugin/business/pangu-http/pangu_http.cpp @@ -808,8 +808,11 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht { 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); scan_ret=Maat_full_scan_string(g_pangu_rt->maat, table_id, 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); } + + *pme=ctx; return; } diff --git a/plugin/protocol/http/CMakeLists.txt b/plugin/protocol/http/CMakeLists.txt index 80b268b..c16e36d 100644 --- a/plugin/protocol/http/CMakeLists.txt +++ b/plugin/protocol/http/CMakeLists.txt @@ -1,3 +1,4 @@ +### PLUGIN add_library(http src/http_entry.cpp src/http_half.cpp) 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 http-parser-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) diff --git a/plugin/protocol/http/include/internal/http_half.h b/plugin/protocol/http/include/internal/http_half.h index cbe6f61..ac88810 100644 --- a/plugin/protocol/http/include/internal/http_half.h +++ b/plugin/protocol/http/include/internal/http_half.h @@ -51,8 +51,12 @@ struct http_half_private short minor; struct evbuffer * evbuf_uri; + struct evbuffer * evbuf_header_field; struct evbuffer * evbuf_header_value; + bool is_evbuf_header_field_set; + bool is_evbuf_header_value_set; + struct evbuffer * evbuf_body; 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); + void hf_private_destory(struct http_half_private * hf_private); /** 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 * 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_half_private * hf_private_req, struct http_half_private * hf_private_resp); diff --git a/plugin/protocol/http/src/http_entry.cpp b/plugin/protocol/http/src/http_entry.cpp index bbca1f3..c0ca9f4 100644 --- a/plugin/protocol/http/src/http_entry.cpp +++ b/plugin/protocol/http/src/http_entry.cpp @@ -67,6 +67,7 @@ enum tfe_stream_action __http_connection_entry_on_request(const struct tfe_strea /* HTTP Request and Session */ hf_private_request = hf_private_create(TFE_HTTP_REQUEST, 1, 0); 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 */ 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, 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); hf_private_destory(hf_private); 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_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; /* Protocol Identification, we need 8 bytes at least to tell it is HTTP or not */ - if (len < HTTP_INDENTIFY_LENGTH) - { - 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; - } + if (len < HTTP_INDENTIFY_LENGTH) goto __detach; /* Now, we want to identify this stream */ int ret = __http_connection_identify(stream, ht_conn, data, len); diff --git a/plugin/protocol/http/src/http_half.cpp b/plugin/protocol/http/src/http_half.cpp index 87a6eb3..836ff18 100644 --- a/plugin/protocol/http/src/http_half.cpp +++ b/plugin/protocol/http/src/http_half.cpp @@ -84,6 +84,8 @@ static void __http_half_header_kv_complete(struct http_half_private * hf_private /* Write a '\0' for evbuffers */ evbuffer_add(hf_private->evbuf_header_field, &__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 */ 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: evbuffer_drain(hf_private->evbuf_header_field, sz_evbuf_field); 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) @@ -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 */ hf_req_spec->method = (enum tfe_http_std_method) parser->method; const static struct http_field_name __host_field_name = - { - .field_id = TFE_HTTP_HOST, - .field_name = NULL - }; + { + .field_id = TFE_HTTP_HOST, + .field_name = NULL + }; 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 * 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) @@ -142,10 +146,10 @@ void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, s /* Status Code */ hf_resp_spec->resp_code = parser->status_code; const static struct http_field_name __cont_encoding_field_name = - { - .field_id = TFE_HTTP_CONT_ENCODING, - .field_name = NULL - }; + { + .field_id = TFE_HTTP_CONT_ENCODING, + .field_name = NULL + }; /* Content Encoding */ 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_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_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->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) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); - - /* Last field-value tuple doesn't push into hf_private, flush these */ - if (evbuffer_get_length(hf_private->evbuf_header_field) != 0) + if (hf_private->is_evbuf_header_field_set && hf_private->is_evbuf_header_value_set) { __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); } 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); + hf_private->is_evbuf_header_value_set = true; 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_object->data = hf_private; + + TAILQ_INIT(&hf_private->header_list); 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; } +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) { assert(hf_private->parse_cursor <= len); diff --git a/plugin/protocol/http/test/test_http_half.cpp b/plugin/protocol/http/test/test_http_half.cpp new file mode 100644 index 0000000..a0cb1e7 --- /dev/null +++ b/plugin/protocol/http/test/test_http_half.cpp @@ -0,0 +1,83 @@ + +#include +#include + +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(); +} diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index 19dce43..edb79d9 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -112,9 +112,10 @@ file(MAKE_DIRECTORY ${INSTALL_DIR}/include) add_library(gtest STATIC IMPORTED GLOBAL) 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_LINK_LIBRARIES pthread) 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)