diff --git a/plugin/protocol/http/CMakeLists.txt b/plugin/protocol/http/CMakeLists.txt index c16e36d..1422057 100644 --- a/plugin/protocol/http/CMakeLists.txt +++ b/plugin/protocol/http/CMakeLists.txt @@ -1,18 +1,23 @@ ### PLUGIN -add_library(http src/http_entry.cpp src/http_half.cpp) +add_library(http src/http_entry.cpp src/http_half.cpp src/http_convert.cpp) target_include_directories(http PRIVATE include/internal) 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) - +target_link_libraries(http z) ### 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) +add_executable(test-http-convert test/test_http_convert.cpp) +target_include_directories(test-http-convert PRIVATE include/internal) +target_link_libraries(test-http-convert gtest common http) + include(GoogleTest) gtest_discover_tests(test-http-half) +gtest_discover_tests(test-http-convert) diff --git a/plugin/protocol/http/include/internal/http_convert.h b/plugin/protocol/http/include/internal/http_convert.h new file mode 100644 index 0000000..a0b58af --- /dev/null +++ b/plugin/protocol/http/include/internal/http_convert.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +struct hf_content_converter; + +enum hf_content_conv_work_mode +{ + HF_CONTENT_CONV_COMPRASS, + HF_CONTENT_CONV_UNCOMPRASS +}; + +int hf_content_converter_write(struct hf_content_converter * cv_object, + struct http_half_private * hf_private, tfe_http_event http_ev, const unsigned char * data, size_t datalen); + +void hf_content_converter_destroy(struct hf_content_converter * cv_object); + +struct hf_content_converter * hf_content_converter_create(enum hf_content_conv_work_mode mode, + unsigned int content_encode, hf_private_cb * data_cb, void * data_cb_user); diff --git a/plugin/protocol/http/include/internal/http_half.h b/plugin/protocol/http/include/internal/http_half.h index 2d7d470..c2b5728 100644 --- a/plugin/protocol/http/include/internal/http_half.h +++ b/plugin/protocol/http/include/internal/http_half.h @@ -21,6 +21,15 @@ struct http_header_private char * value; }; +#define BV(x) (1 << x) +#define HTTP_ACCEPT_ENCODING_IDENTITY BV(0) +#define HTTP_ACCEPT_ENCODING_GZIP BV(1) +#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2) +#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3) +#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4) +#define HTTP_ACCEPT_ENCODING_X_GZIP BV(5) +#define HTTP_ACCEPT_ENCODING_X_BZIP2 BV(6) + TAILQ_HEAD(http_header_private_list, http_header_private); struct http_half_private { @@ -54,6 +63,9 @@ struct http_half_private struct evbuffer * evbuf_uri; char * url_storage; + /* Content-Encoding */ + uint16_t content_encoding; + /* Header Parser */ struct evbuffer * evbuf_header_field; struct evbuffer * evbuf_header_value; @@ -104,8 +116,6 @@ struct http_session_private * hs_private_create(struct http_connection_private * void hs_private_destory(struct http_session_private * hs_private); - - void hs_private_hf_private_set(struct http_session_private * hs_private, struct http_half_private * hf, enum tfe_http_direction); diff --git a/plugin/protocol/http/src/http_convert.cpp b/plugin/protocol/http/src/http_convert.cpp new file mode 100644 index 0000000..0f2a221 --- /dev/null +++ b/plugin/protocol/http/src/http_convert.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +struct hf_content_converter +{ + /* MODE AND CALLBACKS */ + enum hf_content_conv_work_mode mode; + unsigned int content_encode; + hf_private_cb * data_cb; + void * data_cb_user; + + /* ZLIB STREAM */ + z_stream * z_stream_ptr; + unsigned char * chunk; + size_t sz_chunk; +}; + +void hf_content_converter_destroy(struct hf_content_converter * cv_object) +{ + if (cv_object->z_stream_ptr && cv_object->mode == HF_CONTENT_CONV_COMPRASS) + { + (void)deflateEnd(cv_object->z_stream_ptr); + free(cv_object->z_stream_ptr); + } + + if (cv_object->z_stream_ptr && cv_object->mode == HF_CONTENT_CONV_UNCOMPRASS) + { + (void)inflateEnd(cv_object->z_stream_ptr); + free(cv_object->z_stream_ptr); + } + + cv_object->z_stream_ptr = NULL; + free(cv_object); +} + +struct hf_content_converter * hf_content_converter_create(enum hf_content_conv_work_mode mode, + unsigned int content_encode, hf_private_cb * data_cb, void * data_cb_user) +{ + struct hf_content_converter * cv_object = ALLOC(struct hf_content_converter, 1); + assert(data_cb != NULL); + + cv_object->mode = mode; + cv_object->content_encode = content_encode; + cv_object->data_cb = data_cb; + cv_object->data_cb_user = data_cb_user; + + /* ZSTREAM */ + cv_object->z_stream_ptr = ALLOC(z_stream, 1); + cv_object->z_stream_ptr->zalloc = NULL; + cv_object->z_stream_ptr->zfree = NULL; + cv_object->z_stream_ptr->opaque = NULL; + cv_object->z_stream_ptr->avail_in = 0; + cv_object->z_stream_ptr->next_in = Z_NULL; + + /* CHUNK, 4K */ +#define CHUNK_SIZE (1024 * 1024 * 4) + cv_object->chunk = (unsigned char *)malloc(CHUNK_SIZE); + cv_object->sz_chunk = CHUNK_SIZE; + + int ret = 0; + if (content_encode == HTTP_ACCEPT_ENCODING_GZIP) + { + ret = inflateInit2(cv_object->z_stream_ptr, MAX_WBITS + 16); + } + else if (content_encode == HTTP_ACCEPT_ENCODING_DEFLATE) + { + ret = inflateInit(cv_object->z_stream_ptr); + } + + if (ret != Z_OK) goto __errout; + return cv_object; + +__errout: + free(cv_object->z_stream_ptr); + free(cv_object->chunk); + free(cv_object); + return NULL; +} + +int hf_content_converter_write(struct hf_content_converter * cv_object, + struct http_half_private * hf_private, tfe_http_event http_ev, const unsigned char * data, size_t datalen) +{ + z_stream * z_stream_ptr = cv_object->z_stream_ptr; + z_stream_ptr->avail_in = (unsigned int)datalen; + z_stream_ptr->next_in = (unsigned char *)data; + + if (z_stream_ptr->avail_in == 0) + { + (void)inflateEnd(z_stream_ptr); + return Z_ERRNO; + } + + int ret = 0; + do + { + z_stream_ptr->avail_out = (unsigned int) cv_object->sz_chunk; + z_stream_ptr->next_out = cv_object->chunk; + + ret = inflate(z_stream_ptr, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + + if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) + { + goto __error; + } + + unsigned int have = (unsigned int) cv_object->sz_chunk - z_stream_ptr->avail_out; + if (have > 0 && cv_object->data_cb != NULL) + { + cv_object->data_cb(hf_private, http_ev, cv_object->chunk, (size_t) have, cv_object->data_cb_user); + } + + } while (z_stream_ptr->avail_out == 0); + return ret; + +__error: + (void)inflateEnd(z_stream_ptr); + return ret; +} diff --git a/plugin/protocol/http/src/http_half.cpp b/plugin/protocol/http/src/http_half.cpp index 6820d8d..5316574 100644 --- a/plugin/protocol/http/src/http_half.cpp +++ b/plugin/protocol/http/src/http_half.cpp @@ -61,6 +61,36 @@ static enum tfe_http_std_field __str_header_field_to_std_field_id(const char * s return TFE_HTTP_UNKNOWN_FIELD; } +uint16_t __hf_content_encoding_parse(const char * str_content_encoding) +{ + if (strcasestr(str_content_encoding, "gzip") != NULL) + { + return HTTP_ACCEPT_ENCODING_GZIP; + } + + if (strcasestr(str_content_encoding, "x-gzip") != NULL) + { + return HTTP_ACCEPT_ENCODING_X_GZIP; + } + + if (strcasestr(str_content_encoding, "deflate") != NULL) + { + return HTTP_ACCEPT_ENCODING_DEFLATE; + } + + if (strcasestr(str_content_encoding, "bzip2") != NULL) + { + return HTTP_ACCEPT_ENCODING_BZIP2; + } + + if (strcasestr(str_content_encoding, "x-bzip2") != NULL) + { + return HTTP_ACCEPT_ENCODING_X_BZIP2; + } + + return HTTP_ACCEPT_ENCODING_IDENTITY; +} + /* To flush header field and value which stash in evbuffer */ static void __http_half_header_kv_complete(struct http_half_private * hf_private) { @@ -120,12 +150,7 @@ 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 - }; - + const static struct http_field_name __host_field_name = {TFE_HTTP_HOST, NULL}; hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name); /* uri is stored in underlay evbuffer, we need to append a terminal zero */ @@ -157,31 +182,25 @@ void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, s hf_resp_spec->resp_code = parser->status_code; /* Content Type */ - const static struct http_field_name __cont_encoding_type_name = - { - .field_id = TFE_HTTP_CONT_TYPE, - .field_name = NULL - }; - + const static struct http_field_name __cont_encoding_type_name = {TFE_HTTP_CONT_TYPE, NULL}; hf_resp_spec->content_type = (char *) tfe_http_field_read(hf_public, &__cont_encoding_type_name); /* Content Length */ - const static struct http_field_name __cont_encoding_length_name = - { - .field_id = TFE_HTTP_CONT_LENGTH, - .field_name = NULL - }; - + const static struct http_field_name __cont_encoding_length_name = {TFE_HTTP_CONT_LENGTH, NULL}; hf_resp_spec->content_length = (char *) tfe_http_field_read(hf_public, &__cont_encoding_length_name); /* Content Encoding */ - const static struct http_field_name __cont_encoding_field_name = - { - .field_id = TFE_HTTP_CONT_ENCODING, - .field_name = NULL - }; - + const static struct http_field_name __cont_encoding_field_name = {TFE_HTTP_CONT_ENCODING, NULL}; hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name); + + if (hf_resp_spec->content_encoding != NULL) + { + hf_private->content_encoding = __hf_content_encoding_parse(hf_resp_spec->content_encoding); + } + else + { + hf_private->content_encoding = HTTP_ACCEPT_ENCODING_IDENTITY; + } } /* ================================================================================================================== @@ -656,7 +675,7 @@ struct tfe_http_session_ops __http_session_ops = void __construct_request_line(struct http_half_private * hf_private) { - enum tfe_http_std_method __std_method = (enum tfe_http_std_method ) hf_private->method_or_status; + enum tfe_http_std_method __std_method = (enum tfe_http_std_method) hf_private->method_or_status; const char * __str_method = http_std_method_to_string(__std_method); if (__str_method == NULL) { diff --git a/plugin/protocol/http/test/test_http_convert.cpp b/plugin/protocol/http/test/test_http_convert.cpp new file mode 100644 index 0000000..3e7eb6c --- /dev/null +++ b/plugin/protocol/http/test/test_http_convert.cpp @@ -0,0 +1,224 @@ + +#include +#include + +unsigned char __64x[] = { + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58 +}; + +unsigned char __64x_gz[] = { + 0x1f, 0x8b, 0x08, 0x08, 0x56, 0x77, 0xab, 0x5b, 0x00, 0x03, 0x36, 0x34, + 0x78, 0x00, 0x8b, 0x88, 0xa0, 0x0c, 0x00, 0x00, 0x7b, 0xab, 0x2a, 0xf2, + 0x40, 0x00, 0x00, 0x00 +}; + +unsigned char monkey[] = { + 0x7a, 0x6e, 0x78, 0x63, 0x76, 0x6e, 0x6d, 0x7a, 0x2c, 0x78, 0x76, 0x6e, + 0x6d, 0x2e, 0x2c, 0x7a, 0x78, 0x63, 0x6e, 0x76, 0x2e, 0x2c, 0x78, 0x63, + 0x6e, 0x2e, 0x7a, 0x2c, 0x76, 0x6e, 0x2e, 0x7a, 0x76, 0x6e, 0x2e, 0x7a, + 0x78, 0x63, 0x76, 0x6e, 0x2e, 0x2c, 0x7a, 0x78, 0x63, 0x6e, 0x2e, 0x76, + 0x6e, 0x2e, 0x76, 0x2c, 0x7a, 0x6e, 0x6d, 0x2e, 0x2c, 0x76, 0x6e, 0x7a, + 0x78, 0x2e, 0x2c, 0x76, 0x6e, 0x7a, 0x78, 0x63, 0x2e, 0x76, 0x6e, 0x2e, + 0x7a, 0x2c, 0x76, 0x6e, 0x7a, 0x2e, 0x2c, 0x6e, 0x76, 0x2e, 0x7a, 0x2c, + 0x6e, 0x76, 0x6d, 0x7a, 0x78, 0x63, 0x2c, 0x6e, 0x76, 0x7a, 0x78, 0x63, + 0x76, 0x63, 0x6e, 0x6d, 0x2e, 0x2c, 0x76, 0x63, 0x7a, 0x78, 0x76, 0x6e, + 0x7a, 0x78, 0x63, 0x6e, 0x76, 0x6d, 0x78, 0x63, 0x2e, 0x7a, 0x6d, 0x63, + 0x6e, 0x76, 0x7a, 0x6d, 0x2e, 0x2c, 0x6e, 0x76, 0x6d, 0x63, 0x2c, 0x6e, + 0x7a, 0x78, 0x6d, 0x63, 0x2c, 0x76, 0x6e, 0x2e, 0x6d, 0x6e, 0x6e, 0x6d, + 0x7a, 0x78, 0x63, 0x2c, 0x76, 0x6e, 0x78, 0x63, 0x6e, 0x6d, 0x76, 0x2c, + 0x7a, 0x6e, 0x76, 0x7a, 0x78, 0x63, 0x6e, 0x6d, 0x76, 0x2c, 0x2e, 0x78, + 0x63, 0x6e, 0x76, 0x6d, 0x2c, 0x7a, 0x78, 0x63, 0x6e, 0x7a, 0x78, 0x76, + 0x2e, 0x7a, 0x78, 0x2c, 0x71, 0x77, 0x65, 0x72, 0x79, 0x77, 0x65, 0x75, + 0x72, 0x71, 0x69, 0x6f, 0x77, 0x65, 0x75, 0x70, 0x72, 0x6f, 0x70, 0x71, + 0x77, 0x75, 0x74, 0x69, 0x6f, 0x77, 0x65, 0x75, 0x70, 0x71, 0x72, 0x69, + 0x6f, 0x77, 0x65, 0x75, 0x74, 0x69, 0x6f, 0x70, 0x77, 0x65, 0x75, 0x72, + 0x69, 0x6f, 0x70, 0x77, 0x65, 0x75, 0x72, 0x69, 0x6f, 0x70, 0x71, 0x77, + 0x75, 0x72, 0x69, 0x6f, 0x70, 0x75, 0x74, 0x69, 0x6f, 0x70, 0x71, 0x77, + 0x75, 0x72, 0x69, 0x6f, 0x77, 0x75, 0x71, 0x65, 0x72, 0x69, 0x6f, 0x75, + 0x70, 0x71, 0x77, 0x65, 0x72, 0x6f, 0x70, 0x75, 0x77, 0x65, 0x72, 0x6f, + 0x70, 0x71, 0x77, 0x75, 0x72, 0x77, 0x65, 0x75, 0x71, 0x72, 0x69, 0x6f, + 0x70, 0x75, 0x72, 0x6f, 0x70, 0x71, 0x77, 0x75, 0x72, 0x69, 0x6f, 0x70, + 0x75, 0x71, 0x77, 0x72, 0x69, 0x6f, 0x70, 0x75, 0x71, 0x77, 0x65, 0x6f, + 0x70, 0x72, 0x75, 0x69, 0x6f, 0x71, 0x77, 0x65, 0x75, 0x72, 0x71, 0x77, + 0x65, 0x75, 0x72, 0x69, 0x6f, 0x75, 0x71, 0x77, 0x65, 0x6f, 0x70, 0x72, + 0x75, 0x69, 0x6f, 0x75, 0x70, 0x71, 0x69, 0x79, 0x74, 0x69, 0x6f, 0x71, + 0x74, 0x79, 0x69, 0x6f, 0x77, 0x74, 0x79, 0x71, 0x70, 0x74, 0x79, 0x70, + 0x72, 0x79, 0x6f, 0x71, 0x77, 0x65, 0x75, 0x74, 0x69, 0x6f, 0x69, 0x6f, + 0x71, 0x74, 0x77, 0x65, 0x71, 0x72, 0x75, 0x6f, 0x77, 0x71, 0x65, 0x79, + 0x74, 0x69, 0x6f, 0x77, 0x71, 0x75, 0x69, 0x6f, 0x75, 0x72, 0x6f, 0x77, + 0x65, 0x74, 0x79, 0x6f, 0x71, 0x77, 0x75, 0x70, 0x69, 0x6f, 0x74, 0x77, + 0x65, 0x75, 0x71, 0x69, 0x6f, 0x72, 0x77, 0x65, 0x75, 0x71, 0x72, 0x6f, + 0x69, 0x70, 0x69, 0x74, 0x75, 0x71, 0x77, 0x69, 0x6f, 0x72, 0x71, 0x77, + 0x74, 0x69, 0x6f, 0x77, 0x65, 0x75, 0x72, 0x69, 0x6f, 0x75, 0x79, 0x74, + 0x75, 0x69, 0x6f, 0x65, 0x72, 0x79, 0x74, 0x75, 0x69, 0x6f, 0x77, 0x65, + 0x72, 0x79, 0x75, 0x69, 0x74, 0x6f, 0x77, 0x65, 0x79, 0x74, 0x75, 0x69, + 0x77, 0x65, 0x79, 0x75, 0x69, 0x74, 0x79, 0x65, 0x72, 0x75, 0x69, 0x72, + 0x74, 0x79, 0x75, 0x71, 0x72, 0x69, 0x71, 0x77, 0x65, 0x75, 0x72, 0x6f, + 0x70, 0x71, 0x77, 0x65, 0x69, 0x72, 0x75, 0x69, 0x6f, 0x71, 0x77, 0x65, + 0x75, 0x72, 0x69, 0x6f, 0x71, 0x77, 0x75, 0x65, 0x72, 0x69, 0x6f, 0x71, + 0x77, 0x79, 0x75, 0x69, 0x74, 0x75, 0x69, 0x65, 0x72, 0x77, 0x6f, 0x74, + 0x75, 0x65, 0x72, 0x79, 0x75, 0x69, 0x6f, 0x74, 0x77, 0x65, 0x79, 0x72, + 0x74, 0x75, 0x69, 0x77, 0x65, 0x72, 0x74, 0x79, 0x69, 0x6f, 0x77, 0x65, + 0x72, 0x79, 0x72, 0x75, 0x65, 0x69, 0x6f, 0x71, 0x70, 0x74, 0x79, 0x69, + 0x6f, 0x72, 0x75, 0x79, 0x69, 0x6f, 0x70, 0x71, 0x77, 0x74, 0x6a, 0x6b, + 0x61, 0x73, 0x64, 0x66, 0x68, 0x6c, 0x61, 0x66, 0x68, 0x6c, 0x61, 0x73, + 0x64, 0x68, 0x66, 0x6a, 0x6b, 0x6c, 0x61, 0x73, 0x68, 0x6a, 0x6b, 0x66, + 0x68, 0x61, 0x73, 0x6a, 0x6b, 0x6c, 0x66, 0x68, 0x6b, 0x6c, 0x61, 0x73, + 0x6a, 0x64, 0x66, 0x68, 0x6b, 0x6c, 0x61, 0x73, 0x64, 0x68, 0x66, 0x6a, + 0x6b, 0x61, 0x6c, 0x73, 0x64, 0x68, 0x66, 0x6b, 0x6c, 0x61, 0x73, 0x64, + 0x68, 0x6a, 0x6b, 0x66, 0x6c, 0x61, 0x68, 0x73, 0x6a, 0x64, 0x6b, 0x66, + 0x68, 0x6b, 0x6c, 0x61, 0x73, 0x66, 0x68, 0x6a, 0x6b, 0x61, 0x73, 0x64, + 0x66, 0x68, 0x61, 0x73, 0x66, 0x6a, 0x6b, 0x61, 0x73, 0x64, 0x68, 0x66, + 0x6b, 0x6c, 0x73, 0x64, 0x68, 0x61, 0x6c, 0x67, 0x68, 0x68, 0x61, 0x66, + 0x3b, 0x68, 0x64, 0x6b, 0x6c, 0x61, 0x73, 0x66, 0x68, 0x6a, 0x6b, 0x6c, + 0x61, 0x73, 0x68, 0x6a, 0x6b, 0x6c, 0x66, 0x61, 0x73, 0x64, 0x68, 0x66, + 0x61, 0x73, 0x64, 0x6a, 0x6b, 0x6c, 0x66, 0x68, 0x73, 0x64, 0x6a, 0x6b, + 0x6c, 0x61, 0x66, 0x73, 0x64, 0x3b, 0x68, 0x6b, 0x6c, 0x64, 0x61, 0x64, + 0x66, 0x6a, 0x6a, 0x6b, 0x6c, 0x61, 0x73, 0x64, 0x68, 0x66, 0x6a, 0x61, + 0x73, 0x64, 0x64, 0x66, 0x6a, 0x6b, 0x6c, 0x66, 0x68, 0x61, 0x6b, 0x6a, + 0x6b, 0x6c, 0x61, 0x73, 0x64, 0x6a, 0x66, 0x6b, 0x6c, 0x3b, 0x61, 0x73, + 0x64, 0x6a, 0x66, 0x61, 0x73, 0x66, 0x6c, 0x6a, 0x61, 0x73, 0x64, 0x66, + 0x68, 0x6a, 0x6b, 0x6c, 0x61, 0x73, 0x64, 0x66, 0x68, 0x6a, 0x6b, 0x61, + 0x67, 0x68, 0x6a, 0x6b, 0x61, 0x73, 0x68, 0x66, 0x3b, 0x64, 0x6a, 0x66, + 0x6b, 0x6c, 0x61, 0x73, 0x64, 0x6a, 0x66, 0x6b, 0x6c, 0x6a, 0x61, 0x73, + 0x64, 0x6b, 0x6c, 0x66, 0x6a, 0x6b, 0x6c, 0x61, 0x73, 0x64, 0x6a, 0x66, + 0x6b, 0x6c, 0x6a, 0x61, 0x73, 0x64, 0x66, 0x6b, 0x6c, 0x6a, 0x61, 0x6b, + 0x6c, 0x66, 0x6a +}; + +unsigned char monkey_gz[] = { + 0x1f, 0x8b, 0x08, 0x08, 0x56, 0x77, 0xab, 0x5b, 0x00, 0x03, 0x6d, 0x6f, + 0x6e, 0x6b, 0x65, 0x79, 0x00, 0x55, 0x50, 0x59, 0x92, 0xec, 0x20, 0x0c, + 0xbb, 0x50, 0x2a, 0x17, 0xe8, 0xd3, 0x50, 0x09, 0x0c, 0x64, 0x63, 0x69, + 0x08, 0x81, 0xd3, 0x3f, 0xc9, 0xf4, 0x4c, 0xd7, 0xfb, 0x88, 0xe5, 0x45, + 0x96, 0x45, 0xfa, 0xf5, 0x2c, 0xf7, 0x75, 0xf6, 0xe9, 0x41, 0x9c, 0xa7, + 0xfe, 0x2c, 0xd7, 0x3d, 0x4f, 0x88, 0x73, 0x9f, 0x6e, 0x04, 0x7e, 0x64, + 0x8c, 0xd1, 0x8c, 0xe4, 0x9e, 0x3a, 0x99, 0xf7, 0xd5, 0x9f, 0x11, 0x17, + 0x76, 0xc9, 0xee, 0xf3, 0x84, 0xe5, 0x8e, 0x70, 0xa2, 0x0b, 0xe0, 0xe6, + 0x22, 0xe4, 0xa5, 0x3f, 0x42, 0xc5, 0x08, 0xfc, 0x7e, 0x22, 0xe9, 0x27, + 0xe9, 0x27, 0x78, 0xfd, 0x41, 0x84, 0xc6, 0x79, 0x5d, 0xb2, 0x78, 0xc3, + 0xd3, 0x75, 0xf2, 0x0e, 0x15, 0x98, 0xcd, 0xb2, 0x29, 0x16, 0x20, 0x04, + 0x47, 0x53, 0xac, 0x3a, 0xb5, 0xaa, 0x4b, 0x8a, 0xce, 0x03, 0x42, 0xf2, + 0x21, 0xd6, 0x92, 0x47, 0x11, 0x93, 0x20, 0xaa, 0x40, 0xca, 0x17, 0x40, + 0x21, 0xc8, 0x64, 0xe4, 0xb5, 0x44, 0x0d, 0xc0, 0x0e, 0x04, 0x31, 0x91, + 0xc8, 0x11, 0x36, 0xa2, 0x70, 0xd3, 0x77, 0x2d, 0xd6, 0x0f, 0x68, 0x1f, + 0x52, 0x71, 0x3e, 0x8a, 0x81, 0xa1, 0xfd, 0xed, 0x42, 0xcb, 0x35, 0x5c, + 0x88, 0xb9, 0x41, 0x3f, 0xb7, 0x18, 0x72, 0x0b, 0xa9, 0x09, 0x1b, 0x6d, + 0x0e, 0xaa, 0x8e, 0xa9, 0xf8, 0x1a, 0x35, 0x79, 0x35, 0x72, 0x29, 0xc1, + 0x71, 0x26, 0xa9, 0x04, 0xe7, 0x33, 0xaf, 0x3b, 0x3f, 0x4c, 0x78, 0x17, + 0x5c, 0x86, 0x3c, 0xea, 0x58, 0xc7, 0x0b, 0x79, 0xaf, 0x65, 0xac, 0xe1, + 0x27, 0x10, 0xf8, 0x33, 0x8a, 0xcb, 0x40, 0x96, 0x88, 0x28, 0x9a, 0x86, + 0x99, 0x94, 0x1b, 0x9f, 0x21, 0x1e, 0xf9, 0x0e, 0xed, 0xfe, 0x7c, 0x13, + 0x8a, 0x16, 0x20, 0xbd, 0x38, 0x9d, 0xaa, 0xcf, 0x45, 0x94, 0x68, 0xa0, + 0x25, 0x91, 0x4a, 0xf2, 0x0a, 0x74, 0x53, 0xd1, 0xe0, 0x06, 0x96, 0xa9, + 0x34, 0xf9, 0x81, 0x79, 0xdb, 0xd5, 0x7b, 0x35, 0xf6, 0x50, 0xfc, 0xde, + 0xab, 0x35, 0xdb, 0x0e, 0xb4, 0xdb, 0x6e, 0xac, 0x7a, 0x23, 0x37, 0x96, + 0xf5, 0xb6, 0x0e, 0x94, 0xb9, 0x3a, 0x88, 0xa3, 0x04, 0xef, 0x50, 0x16, + 0xf3, 0x7d, 0x10, 0x8c, 0xfd, 0x08, 0x22, 0x95, 0x8c, 0x44, 0x44, 0x75, + 0xfc, 0x58, 0xab, 0xcc, 0xcb, 0xae, 0xbf, 0xac, 0x71, 0xe5, 0x30, 0xc2, + 0x41, 0x90, 0x5b, 0x02, 0xca, 0xbc, 0xd7, 0x17, 0xd4, 0x56, 0xb5, 0x9a, + 0x6d, 0xfb, 0x3d, 0x8b, 0xb8, 0x1a, 0x21, 0xa9, 0x7d, 0x34, 0x37, 0x48, + 0xbf, 0x04, 0xa1, 0x78, 0x6c, 0x72, 0x76, 0x4c, 0xc4, 0xc5, 0x8f, 0x58, + 0xb1, 0xe6, 0x25, 0xc4, 0x0f, 0x9f, 0x2c, 0x68, 0x6c, 0xff, 0x35, 0x04, + 0xd8, 0xfd, 0x07, 0xec, 0x10, 0x9d, 0x29, 0x4b, 0x03, 0x00, 0x00 +}; + +unsigned int monkey_gz_len = 407; +unsigned int monkey_len = 843; +unsigned int __64x_len = 64; +unsigned int __64x_gz_len = 28; + +struct callback_ctx +{ + unsigned char * data; + unsigned int sz_data; +}; + +int __gzip_64x_data_callback(struct http_half_private * hf_private, + tfe_http_event ev, const unsigned char * data, size_t len, void * user) +{ + auto * __ctx = (struct callback_ctx *)user; + memcpy(__ctx->data + __ctx->sz_data, data, len); + __ctx->sz_data += len; + return 0; +} + +class HttpConvertUncompress : public ::testing::Test +{ +protected: + void SetUp() override + { + __ctx = new struct callback_ctx; + __ctx->data = new unsigned char[2048]; + __ctx->sz_data = 0; + + cv_object = hf_content_converter_create(HF_CONTENT_CONV_UNCOMPRASS, + HTTP_ACCEPT_ENCODING_GZIP, __gzip_64x_data_callback, __ctx); + + ASSERT_TRUE(cv_object != NULL); + } + + void TearDown() override + { + delete[] __ctx->data; + delete __ctx; + hf_content_converter_destroy(cv_object); + } + +protected: + struct callback_ctx * __ctx{}; + struct hf_content_converter * cv_object{}; +}; + +TEST_F(HttpConvertUncompress, Gzip64x) +{ + int ret = hf_content_converter_write(cv_object, NULL, EV_HTTP_REQ_BODY_CONT, + (const unsigned char *)__64x_gz, (size_t)__64x_gz_len); + + EXPECT_EQ(ret, 1); + EXPECT_EQ(__ctx->sz_data, __64x_len); + EXPECT_EQ(memcmp(__ctx->data, __64x, __64x_len), 0); +} + +TEST_F(HttpConvertUncompress, GzipMonkey) +{ + int ret = hf_content_converter_write(cv_object, NULL, EV_HTTP_REQ_BODY_CONT, + (const unsigned char *)monkey_gz, (size_t)monkey_gz_len); + + EXPECT_EQ(ret, 1); + EXPECT_EQ(__ctx->sz_data, monkey_len); + EXPECT_EQ(memcmp(__ctx->data, monkey, monkey_len), 0); +} + +TEST_F(HttpConvertUncompress, GzipMonkeyFrag) +{ + unsigned frag_length = monkey_gz_len / 2; + + int ret = 0; + ret = hf_content_converter_write(cv_object, NULL, EV_HTTP_REQ_BODY_CONT, + (const unsigned char *)monkey_gz, frag_length); + + EXPECT_EQ(ret, 0); + ret = hf_content_converter_write(cv_object, NULL, EV_HTTP_REQ_BODY_CONT, + (const unsigned char *)monkey_gz + frag_length, monkey_gz_len - frag_length); + + EXPECT_EQ(ret, 1); + EXPECT_EQ(__ctx->sz_data, monkey_len); + EXPECT_EQ(memcmp(__ctx->data, monkey, monkey_len), 0); +} + +void tfe_stream_write_access_log(const struct tfe_stream * stream, int level, const char * fmt, ...) +{ + return; +} + +int main(int argc, char ** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}