diff options
| author | 刘文坛 <[email protected]> | 2023-12-14 06:48:44 +0000 |
|---|---|---|
| committer | 刘文坛 <[email protected]> | 2023-12-14 06:48:44 +0000 |
| commit | a4254d7b60b1aee385c1531ab8c6f7f69b074b90 (patch) | |
| tree | 411ce4bb8a0019a9ecac2344be6c1f99d3f0b928 | |
| parent | 37117f9f350c0c7b624b8f74f0b03cb8ee20be72 (diff) | |
[HTTP_DECODER]first simple http unit_test passed
36 files changed, 3029 insertions, 12 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0258f1d..74ecd3f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,8 +3,8 @@ variables: BUILD_PADDING_PREFIX: /tmp/padding_for_CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX_PREFIX_PREFIX_PREFIX_PREFIX_PREFIX/ BUILD_IMAGE_CENTOS7: "git.mesalab.cn:7443/mesa_platform/build-env:centos7-for-sapp" BUILD_IMAGE_CENTOS8: "git.mesalab.cn:7443/mesa_platform/build-env:rocky8-for-sapp" - INSTALL_DEPENDENCY_LIBRARY: - sapp sapp-devel framework_env + INSTALL_DEPENDENCY_LIBRARY: sapp sapp-devel framework_env libMESA_prof_load-devel + libcjson-devel zlib-devel brotli-devel SYMBOL_TARGET: stellar-c TEST_NAME: gtest_stellar-c INSTALL_PREFIX: "/opt/tsg/" diff --git a/CMakeLists.txt b/CMakeLists.txt index 22dc9b8..90bef99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set (CMAKE_INSTALL_PREFIX "/opt/tsg/" CACHE PATH "default install path" FORCE) endif() +LINK_DIRECTORIES(/opt/MESA/lib /usr/lib64) + find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck) if (CMAKE_CXX_CPPCHECK) list( @@ -76,13 +78,13 @@ add_subdirectory(vendor) add_subdirectory(deps/toml) add_subdirectory(src/adapter) add_subdirectory(src/stellar_on_sapp) +add_subdirectory(src/http_decoder) add_subdirectory(examples/sapp_plugin) add_subdirectory(examples/stellar_plugin) enable_testing() add_subdirectory(test) - install(FILES include/stellar/session_exdata.h DESTINATION ${CMAKE_INSTALL_PREFIX}/framework/include/stellar COMPONENT Headers) install(FILES include/stellar/session_mq.h DESTINATION ${CMAKE_INSTALL_PREFIX}/framework/include/stellar COMPONENT Headers) install(FILES include/stellar/session.h DESTINATION ${CMAKE_INSTALL_PREFIX}/framework/include/stellar COMPONENT Headers) diff --git a/examples/stellar_plugin/simple_plugin.toml b/examples/stellar_plugin/simple_plugin.toml index 24019e7..ce08b65 100644 --- a/examples/stellar_plugin/simple_plugin.toml +++ b/examples/stellar_plugin/simple_plugin.toml @@ -7,4 +7,4 @@ exit = "simple_stellar_event_plugin_exit" [[plugin]] path = "./stellar_plugin/simple_stellar_plugin.so" init = "simple_stellar_mq_plugin_init" -exit = "simple_stellar_mq_plugin_exit" +exit = "simple_stellar_mq_plugin_exit"
\ No newline at end of file diff --git a/include/stellar/session.h b/include/stellar/session.h index 6ce5625..e8f51f5 100644 --- a/include/stellar/session.h +++ b/include/stellar/session.h @@ -110,7 +110,7 @@ const struct packet *session_get0_current_packet(struct session *sess); #define PACKET_DIRECTION_C2S 0 #define PACKET_DIRECTION_S2C 1 -int packet_get_direction(const struct packet *pkt); +int packet_get_direction(const struct packet *pkt); const char *packet_get0_data(const struct packet *pkt, size_t *data_len); int packet_arrive_time(const struct packet *pkt, struct timeval *ts); diff --git a/include/stellar/utils.h b/include/stellar/utils.h index 7beafbb..eb5e705 100644 --- a/include/stellar/utils.h +++ b/include/stellar/utils.h @@ -5,7 +5,9 @@ #define CALLOC(type, number) ((type *)calloc(sizeof(type), number)) -#define FREE(p) {free(p);p=NULL;} +#define REALLOC(type, ptr, number) ((type *)realloc(ptr, (number) * sizeof(type))) + +#define FREE(p) {free(p); p = NULL;} #define TRUE 1 #define FALSE 0 diff --git a/src/http_decoder/CMakeLists.txt b/src/http_decoder/CMakeLists.txt new file mode 100644 index 0000000..1655631 --- /dev/null +++ b/src/http_decoder/CMakeLists.txt @@ -0,0 +1,9 @@ +add_definitions(-fPIC) + +set(HTTP_SRC http_decoder.c http_decoder_utils.c http_decoder_half.c + http_decoder_table.c http_decoder_string.c http_content_decompress.c) + +add_library(http_decoder SHARED ${HTTP_SRC}) +#set_target_properties(http_decoder_shared PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_LIST_DIR}/version.map") +target_link_libraries(http_decoder brotlidec llhttp-static) +set_target_properties(http_decoder PROPERTIES PREFIX "")
\ No newline at end of file diff --git a/src/http_decoder/http_content_decompress.c b/src/http_decoder/http_content_decompress.c new file mode 100644 index 0000000..fa99677 --- /dev/null +++ b/src/http_decoder/http_content_decompress.c @@ -0,0 +1,261 @@ +/* +********************************************************************************************** +* File: http_content_decompress.c +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#include <zlib.h> +#include <string.h> +#include <assert.h> +#include <brotli/decode.h> + +#include "stellar/utils.h" +#include "http_decoder_utils.h" +#include "http_content_decompress.h" + +#define BUFFER_SIZE (1024 * 1024 * 4) + +struct http_content_decompress { + enum http_content_encoding encoding; + + z_stream *z_stream_ptr; + BrotliDecoderState *brdec_state; + + char *buffer; + size_t buffer_size; +}; + +enum http_content_encoding http_content_encoding_str2int(const char *content_encoding) +{ + if (strcasestr(content_encoding, "gzip") != NULL) { + return HTTP_CONTENT_ENCODING_GZIP; + } + + if (strcasestr(content_encoding, "deflate") != NULL) { + return HTTP_CONTENT_ENCODING_DEFLATE; + } + + if (strcasestr(content_encoding, "br") != NULL) { + return HTTP_CONTENT_ENCODING_BR; + } + + return HTTP_CONTENT_ENCODING_NONE; +} + +const char *http_content_encoding_int2str(enum http_content_encoding content_encoding) +{ + if (content_encoding == HTTP_CONTENT_ENCODING_GZIP) { + return "gzip"; + } + + if (content_encoding == HTTP_CONTENT_ENCODING_DEFLATE) { + return "deflate"; + } + + if (content_encoding == HTTP_CONTENT_ENCODING_BR) { + return "br"; + } + + return "unknown"; +} + +struct http_content_decompress * +http_content_decompress_create(enum http_content_encoding encoding) +{ + struct http_content_decompress *decompress = CALLOC(struct http_content_decompress, 1); + assert(decompress); + + decompress->encoding = encoding; + decompress->z_stream_ptr = NULL; + decompress->brdec_state = NULL; + + decompress->buffer = CALLOC(char, BUFFER_SIZE); + assert(decompress->buffer); + decompress->buffer_size = BUFFER_SIZE; + + if (encoding == HTTP_CONTENT_ENCODING_GZIP || + encoding == HTTP_CONTENT_ENCODING_DEFLATE) { + decompress->z_stream_ptr = CALLOC(z_stream, 1); + assert(decompress->z_stream_ptr); + + decompress->z_stream_ptr->zalloc = NULL; + decompress->z_stream_ptr->zfree = NULL; + decompress->z_stream_ptr->opaque = NULL; + decompress->z_stream_ptr->avail_in = 0; + decompress->z_stream_ptr->next_in = Z_NULL; + + if (encoding == HTTP_CONTENT_ENCODING_GZIP) { + if (inflateInit2(decompress->z_stream_ptr, MAX_WBITS + 16) != Z_OK) { + goto error; + } + } + + if (encoding == HTTP_CONTENT_ENCODING_DEFLATE) { + if (inflateInit2(decompress->z_stream_ptr, -MAX_WBITS) != Z_OK) { + goto error; + } + } + } + + if (encoding == HTTP_CONTENT_ENCODING_BR) { + decompress->brdec_state = BrotliDecoderCreateInstance(NULL, NULL, NULL); + if (decompress->brdec_state == NULL) { + goto error; + } + } + + return decompress; + +error: + http_content_decompress_destroy(decompress); + return NULL; +} + +void http_content_decompress_destroy(struct http_content_decompress *decompress) +{ + if (NULL == decompress) { + return; + } + + if (decompress->z_stream_ptr != NULL) { + inflateEnd(decompress->z_stream_ptr); + FREE(decompress->z_stream_ptr); + } + + if (decompress->brdec_state) { + BrotliDecoderDestroyInstance(decompress->brdec_state); + decompress->brdec_state = NULL; + } + + FREE(decompress->buffer); + FREE(decompress); +} + +static int http_content_decompress_write_zlib(struct http_content_decompress *decompress, + const char *indata, size_t indata_len, + char **outdata, size_t *outdata_len) +{ + z_stream *z_stream_ptr = decompress->z_stream_ptr; + z_stream_ptr->avail_in = (unsigned int)indata_len; + z_stream_ptr->next_in = (unsigned char *)indata; + + *outdata = NULL; + *outdata_len = 0; + + int ret = 0; + do { + z_stream_ptr->avail_out = (unsigned int)decompress->buffer_size; + z_stream_ptr->next_out = (unsigned char *)decompress->buffer; + + ret = inflate(z_stream_ptr, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || + ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { + (void)inflateEnd(z_stream_ptr); + return -1; + } + + size_t have = decompress->buffer_size - z_stream_ptr->avail_out; + if (have > 0) { + if (NULL == *outdata) { + http_decoder_log(DEBUG, "%s alloc outbuffer %zu bytes", + http_content_encoding_int2str(decompress->encoding), have); + *outdata = safe_dup(decompress->buffer, have); + *outdata_len = have; + } else { + http_decoder_log(DEBUG, "%s realloc outbuffer %zu bytes", + http_content_encoding_int2str(decompress->encoding), + *outdata_len + have + 1); + *outdata = REALLOC(char, *outdata, *outdata_len + have + 1); + memcpy(*outdata + *outdata_len, decompress->buffer, have); + *outdata_len = *outdata_len + have; + memset(*outdata + *outdata_len, 0, 1); + } + } + } while (0 == z_stream_ptr->avail_out); + + return 0; +} + +static int http_content_decompress_write_br(struct http_content_decompress *decompress, + const char *indata, size_t indata_len, + char **outdata, size_t *outdata_len) +{ + size_t available_out; + size_t available_in = indata_len; + const unsigned char *next_in = (const unsigned char *)indata; + unsigned char *next_out; + + *outdata = NULL; + *outdata_len = 0; + + int ret; + for (;;) { + available_out = decompress->buffer_size; + next_out = (unsigned char *)decompress->buffer; + + ret = BrotliDecoderDecompressStream(decompress->brdec_state, &available_in, + &next_in, &available_out, &next_out, 0); + size_t have = decompress->buffer_size - available_out; + if (have > 0) { + if (NULL == *outdata) { + http_decoder_log(DEBUG, "%s alloc outbuffer %zu bytes", + http_content_encoding_int2str(decompress->encoding), have); + *outdata = safe_dup(decompress->buffer, have); + *outdata_len = have; + } else { + http_decoder_log(DEBUG, "%s realloc outbuffer %zu bytes", + http_content_encoding_int2str(decompress->encoding), + *outdata_len + have + 1); + *outdata = REALLOC(char, *outdata, *outdata_len + have + 1); + memcpy(*outdata + *outdata_len, decompress->buffer, have); + *outdata_len = *outdata_len + have; + memset(*outdata + *outdata_len, 0, 1); + } + } + + if (ret == BROTLI_DECODER_RESULT_SUCCESS || + ret == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) { + return 0; + } + + if (ret == BROTLI_DECODER_RESULT_ERROR) { + BrotliDecoderErrorCode errcode = BrotliDecoderGetErrorCode(decompress->brdec_state); + http_decoder_log(ERROR, "BrotliDecoderDecompressStream() failed: errno = %d, %s", + errcode, BrotliDecoderErrorString(errcode)); + return -1; + } + + assert(ret == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT); + } +} + +int http_content_decompress_write(struct http_content_decompress *decompress, const char *indata, + size_t indata_len, char **outdata, size_t *outdata_len) +{ + assert(decompress); + assert(indata); + assert(indata_len > 0); + assert(outdata); + assert(outdata_len); + + *outdata = NULL; + *outdata_len = 0; + + if (decompress->encoding == HTTP_CONTENT_ENCODING_GZIP || + decompress->encoding == HTTP_CONTENT_ENCODING_DEFLATE) { + return http_content_decompress_write_zlib(decompress, indata, indata_len, + outdata, outdata_len); + } + + if (decompress->encoding == HTTP_CONTENT_ENCODING_BR) { + return http_content_decompress_write_br(decompress, indata, indata_len, + outdata, outdata_len); + } + + assert(0); + return -1; +}
\ No newline at end of file diff --git a/src/http_decoder/http_content_decompress.h b/src/http_decoder/http_content_decompress.h new file mode 100644 index 0000000..66ea567 --- /dev/null +++ b/src/http_decoder/http_content_decompress.h @@ -0,0 +1,50 @@ +/* +********************************************************************************************** +* File: http_content_decompress.h +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _HTTP_CONTENT_DECOMPRESS_H_ +#define _HTTP_CONTENT_DECOMPRESS_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stddef.h> + +// yum install -y zlib-devel +// yum install -y brotli-devel + +enum http_content_encoding { + HTTP_CONTENT_ENCODING_NONE = 0, + HTTP_CONTENT_ENCODING_GZIP = 1 << 1, + HTTP_CONTENT_ENCODING_DEFLATE = 1 << 2, + HTTP_CONTENT_ENCODING_BR = 1 << 3, +}; + +struct http_content_decompress; + +enum http_content_encoding http_content_encoding_str2int(const char *content_encoding); + +const char *http_content_encoding_int2str(enum http_content_encoding content_encoding); + +struct http_content_decompress *http_content_decompress_create(enum http_content_encoding encoding); + +void http_content_decompress_destroy(struct http_content_decompress *decompress); + +// return 0 : success +// return -1 : error +int http_content_decompress_write(struct http_content_decompress *decompress, const char *indata, + size_t indata_len, char **outdata, size_t *outdata_len); + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/src/http_decoder/http_decoder.c b/src/http_decoder/http_decoder.c new file mode 100644 index 0000000..ce767fb --- /dev/null +++ b/src/http_decoder/http_decoder.c @@ -0,0 +1,504 @@ +/* +********************************************************************************************** +* File: http_decoder_entry.c +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#include <assert.h> +#include <stdio.h> + +#include "stellar/utils.h" +#include "stellar/session.h" +#include "stellar/session_mq.h" +#include "stellar/session_exdata.h" +#include "http_decoder.h" +#include "http_decoder_half.h" +#include "http_decoder_table.h" +#include "llhttp.h" + +#define HTTP_IDENTIFY_LEN 16 +#define HTTP_DECODER_RESULT_QUEUE_SIZE 16 + +#define HTTP_DECODER_IS_CACHE_LINE 1 +#define HTTP_DECODER_IS_CACHE_BODY 1 +#define HTTP_DECODER_IS_CACHE_HEADER 1 + +const char *http_decoder_topic = "HTTP_DECODER_MESSAGE"; + +struct http_decoder_result { + struct session *ref_session; + struct http_decoder_half_data *req_data; + struct http_decoder_half_data *res_data; +}; + +struct http_decoder_result_queue { + size_t req_index; + size_t res_index; + size_t del_index; + size_t queue_size; + struct http_decoder_result **array; +}; + +/** + * NOTE: http_message don't have the ownership of data +*/ +struct http_message { + enum http_message_type type; + struct http_decoder_half_data *data; +}; + +struct http_decoder { + struct http_decoder_half *c2s_half; + struct http_decoder_half *s2c_half; +}; + +struct http_decoder_context { + int plugin_id; + int topic_id; + int ex_data_idx; + struct stellar *st; + struct http_decoder *decoder; + struct http_decoder_result_queue *ref_queue; +}; + +struct http_decoder_result *http_decoder_result_new() +{ + struct http_decoder_result *result = CALLOC(struct http_decoder_result, 1); + assert(result); + + result->req_data = NULL; + result->res_data = NULL; + + return result; +} + +void http_decoder_result_free(struct http_decoder_result *result) +{ + if (NULL == result) { + return; + } + + if (result->req_data != NULL) { + http_decoder_half_data_free(result->req_data); + result->req_data = NULL; + } + + if (result->res_data != NULL) { + http_decoder_half_data_free(result->res_data); + result->res_data = NULL; + } + + FREE(result); +} + +// Create a new http result and add it to the queue +static void http_decoder_result_queue_push(struct http_decoder_result_queue *queue, size_t index) +{ + assert(queue); + assert(index < queue->queue_size); + + if (queue->array[index] == NULL) { + queue->array[index] = http_decoder_result_new(); + assert(queue->array[index]); + } +} + +// Remove the http result from the queue but not destroy it +static void http_decoder_result_queue_pop(struct http_decoder_result_queue *queue, size_t index) +{ + assert(queue); + assert(index < queue->queue_size); + + if (queue->array[index] != NULL) { + http_decoder_result_free(queue->array[index]); + queue->array[index] = NULL; + } +} + +static void http_decoder_result_queue_inc_req_index(struct http_decoder_result_queue *queue) +{ + assert(queue); + + queue->req_index++; + queue->req_index = queue->req_index % queue->queue_size; +} + +static void http_decoder_result_queue_inc_res_index(struct http_decoder_result_queue *queue) +{ + assert(queue); + + queue->res_index++; + queue->res_index = queue->res_index % queue->queue_size; +} + +static void http_decoder_result_queue_inc_del_index(struct http_decoder_result_queue *queue) +{ + assert(queue); + + queue->del_index++; + queue->del_index = queue->del_index % queue->queue_size; +} + +static void http_decoder_result_queue_gc(struct http_decoder_result_queue *queue, size_t index) +{ + assert(queue); + assert(index < queue->queue_size); + + if (index == queue->del_index) { + http_decoder_result_queue_pop(queue, index); + http_decoder_result_queue_inc_del_index(queue); + } +} + +static void http_event_handler(enum http_event event, + struct http_decoder_half_data **data, + void *cb_args) +{ + struct http_decoder_context *ctx = (struct http_decoder_context *)cb_args; + assert(ctx); + + printf("ctx->topic_id:%d\n", ctx->topic_id); + assert(ctx->ref_queue); + struct http_decoder_result_queue *queue = ctx->ref_queue; + + switch (event) { + case HTTP_EVENT_INIT: + *data = http_decoder_half_data_new(); + break; + case HTTP_EVENT_REQ_LINE: + if (NULL == queue->array[queue->req_index]) { + http_decoder_result_queue_push(queue, queue->req_index); + } + queue->array[queue->req_index]->req_data = *data; + break; + case HTTP_EVENT_REQ_HDR: + break; + case HTTP_EVENT_REQ_HDR_END: + break; + case HTTP_EVENT_REQ_BODY_BEGIN: + break; + case HTTP_EVENT_REQ_BODY_DATA: + break; + case HTTP_EVENT_REQ_BODY_END: + break; + case HTTP_EVENT_REQ_END: + http_decoder_result_queue_inc_req_index(queue); + http_decoder_result_queue_gc(queue, queue->req_index); + break; + case HTTP_EVENT_RES_LINE: + queue->array[queue->res_index]->res_data = *data; + break; + case HTTP_EVENT_RES_HDR: + break; + case HTTP_EVENT_RES_HDR_END: + break; + case HTTP_EVENT_RES_BODY_BEGIN: + break; + case HTTP_EVENT_RES_BODY_DATA: + break; + case HTTP_EVENT_RES_BODY_END: + break; + case HTTP_EVENT_RES_END: + break; + default: + assert(0); + break; + } +} + +static struct http_decoder *http_decoder_new() +{ + struct http_decoder *decoder = CALLOC(struct http_decoder, 1); + assert(decoder); + + decoder->c2s_half = http_decoder_half_new(); + decoder->s2c_half = http_decoder_half_new(); + + return decoder; +} + +void http_decoder_reinit(struct http_decoder *decoder, void *args) +{ + http_decoder_half_init(decoder->c2s_half, http_event_handler, args, + HTTP_DECODER_IS_CACHE_LINE, + HTTP_DECODER_IS_CACHE_BODY, + HTTP_DECODER_IS_CACHE_HEADER); + + http_decoder_half_init(decoder->s2c_half, http_event_handler, args, + HTTP_DECODER_IS_CACHE_LINE, + HTTP_DECODER_IS_CACHE_BODY, + HTTP_DECODER_IS_CACHE_HEADER); +} + +static struct http_decoder_result_queue *http_decoder_result_queue_new(size_t queue_size) +{ + struct http_decoder_result_queue *queue = CALLOC(struct http_decoder_result_queue, 1); + assert(queue); + + queue->del_index = 0; + queue->req_index = 0; + queue->res_index = 0; + queue->queue_size = queue_size; + + queue->array = CALLOC(struct http_decoder_result *, queue->queue_size); + assert(queue->array); + + return queue; +} + +static void http_decoder_result_queue_free(struct http_decoder_result_queue *queue) +{ + if (NULL == queue) { + return; + } + + if (queue->array != NULL) { + for (size_t i = 0; i < queue->queue_size; i++) { + if (queue->array[i] != NULL) { + http_decoder_result_free(queue->array[i]); + queue->array[i] = NULL; + } + } + + FREE(queue->array); + } + + FREE(queue); +} + +static struct http_decoder_context *http_decoder_context_new() +{ + struct http_decoder_context *ctx = CALLOC(struct http_decoder_context, 1); + assert(ctx); + + return ctx; +} + +static void http_decoder_context_free(struct http_decoder_context *ctx) +{ + if (NULL == ctx) { + return; + } +} + +static int http_protocol_identify(const char *data, size_t data_len) +{ + enum llhttp_type type = HTTP_BOTH; + llhttp_t parser; + llhttp_settings_t settings; + enum llhttp_errno error; + + llhttp_settings_init(&settings); + llhttp_init(&parser, type, &settings); + + error = llhttp_execute(&parser, data, data_len); + if (error != HPE_OK) { + return -1; + } + + return 0; +} + +int http_decoder_entry(struct session *s, int events, const struct packet *pkt, void *cb_arg) +{ + int ret = 0; + size_t payload_len = 0; + struct http_decoder_context *ctx = (struct http_decoder_context *)cb_arg; + + const char *payload = session_get0_current_payload(s, &payload_len); + size_t http_identify_len = payload_len > HTTP_IDENTIFY_LEN ? HTTP_IDENTIFY_LEN : payload_len; + + struct http_decoder_result_queue *queue = session_get_ex_data(s, ctx->ex_data_idx); + if (NULL == queue) { + ret = http_protocol_identify(payload, http_identify_len); + printf("http_protocol_identify ret:%d\n", ret); + if (ret < 0) { + //ignore this session's event + struct session_event *s_event = session_get_intrinsic_event(s, ctx->plugin_id); + session_event_assign(s_event, ctx->st, s, 0, http_decoder_entry, ctx); + return 0; + } + + queue = http_decoder_result_queue_new(HTTP_DECODER_RESULT_QUEUE_SIZE); + session_set_ex_data(s, ctx->ex_data_idx, queue); + } + + ctx->ref_queue = queue; + + int dir = packet_get_direction(pkt); + if (dir < 0) { + return -1; + } + + // printf("\n-------------------------------------------\n"); + // for (size_t i = 0; i < payload_len; i++) { + // printf(" %x", payload[i]); + // } + // printf("\n-------------------------------------------\n"); + + if (NULL == ctx->decoder) { + ctx->decoder = http_decoder_new(); + http_decoder_reinit(ctx->decoder, ctx); + } + + struct http_decoder_half *cur_half = NULL; + if (dir == PACKET_DIRECTION_C2S) { + cur_half = ctx->decoder->c2s_half; + } else { + cur_half = ctx->decoder->s2c_half; + } + + ret = http_decoder_half_parse(cur_half, payload, payload_len); + if (ret < 0) { + if (dir == PACKET_DIRECTION_C2S) { + http_decoder_result_queue_pop(queue, queue->req_index); + } else { + http_decoder_result_queue_pop(queue, queue->res_index); + } + } + + // struct http_message *msg = CALLOC(struct http_message, 1); + // msg->type = HTTP_MESSAGE_REQ_LINE; + // session_mq_publish_message(s, ctx->topic_id, msg); + + return 0; +} + +static void http_decoder_ex_data_free(struct session *s, int idx, void *ex_ptr, void *arg) +{ + if (ex_ptr != NULL) { + FREE(ex_ptr); + } +} + +void http_message_free(void *msg, void *cb_arg) +{ + if (NULL == msg) { + return; + } + + struct http_message *message = (struct http_message *)msg; + message->data = NULL; //don't have memory's ownership + + FREE(message); +} + +void *http_decoder_init(struct stellar *st) +{ + struct http_decoder_context *ctx = http_decoder_context_new(); + + ctx->st = st; + ctx->ex_data_idx = stellar_session_get_ex_new_index(st, "HTTP_DECODER", + http_decoder_ex_data_free, NULL); + + int plugin_id = stellar_plugin_register(st, SESS_EV_TCP, http_decoder_entry, ctx); + if (plugin_id >= 0) { + ctx->plugin_id = plugin_id; + } + + int topic_id = session_mq_get_topic_id(st, http_decoder_topic); + if (topic_id < 0) { + topic_id = session_mq_create_topic(st, http_decoder_topic, http_message_free, NULL); + } + ctx->topic_id = topic_id; + + printf("http_decoder_init: ex_data_idx:%d, plugin_id:%d, topic_id:%d\n", + ctx->ex_data_idx, ctx->plugin_id, ctx->topic_id); + return ctx; +} + +void http_decoder_exit(void *ctx) +{ + if (NULL == ctx) { + return; + } + + FREE(ctx); +} + +enum http_message_type http_message_type(struct http_message *msg) +{ + if (NULL == msg) { + return HTTP_MESSAGE_MAX; + } + + return msg->type; +} + +int http_message_get_request_line(struct http_message *msg, struct http_request_line *line) +{ + if (NULL == msg || msg->type != HTTP_MESSAGE_REQ_LINE || + NULL == line) { + return -1; + } + + return http_decoder_half_data_get_request_line(msg->data, line); +} + +int http_message_get_response_line(struct http_message *msg, struct http_response_line *line) +{ + if (NULL == msg || msg->type != HTTP_MESSAGE_RES_LINE || + NULL == line) { + return -1; + } + + return http_decoder_half_data_get_response_line(msg->data, line); +} + +int http_message_get_request_header(struct http_message *msg, struct hstring *key, + struct http_header *header_array, size_t array_size) +{ + if (NULL == msg || + (msg->type != HTTP_MESSAGE_REQ_HEADER && msg->type != HTTP_MESSAGE_REQ_HEADER_END) || + NULL == header_array || 0 == array_size) { + return -1; + } + + return http_decoder_half_data_get_header(msg->data, key, header_array, array_size); +} + +int http_message_get_response_header(struct http_message *msg, struct hstring *key, + struct http_header *header_array, size_t array_size) +{ + if (NULL == msg || + (msg->type != HTTP_MESSAGE_RES_HEADER && msg->type != HTTP_MESSAGE_RES_HEADER_END) || + NULL == header_array || 0 == array_size) { + return -1; + } + + return http_decoder_half_data_get_header(msg->data, key, header_array, array_size); +} + +int http_message_request_header_next(struct http_message *msg, struct http_header *header) +{ + return 0; +} + +int http_message_response_header_next(struct http_message *msg, struct http_header *header) +{ + return 0; +} + +void http_message_get_request_raw_body(struct http_message *msg, struct hstring *body) +{ + +} + +void http_message_get_response_raw_body(struct http_message *msg, struct hstring *body) +{ + +} + +void http_message_get_request_decompress_body(struct http_message *msg, struct hstring *body) +{ + +} + +void http_message_get_response_decompress_body(struct http_message *msg, struct hstring *body) +{ + +}
\ No newline at end of file diff --git a/src/http_decoder/http_decoder.h b/src/http_decoder/http_decoder.h new file mode 100644 index 0000000..ed5724e --- /dev/null +++ b/src/http_decoder/http_decoder.h @@ -0,0 +1,93 @@ +/* +********************************************************************************************** +* File: http_decoder.h +* Description: +* Authors: Liu WenTan <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _HTTP_DECODER_H_ +#define _HTTP_DECODER_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stddef.h> + +enum http_message_type { + HTTP_MESSAGE_REQ_LINE, + HTTP_MESSAGE_REQ_HEADER, + HTTP_MESSAGE_REQ_HEADER_END, + HTTP_MESSAGE_REQ_BODY, + HTTP_MESSAGE_RES_LINE, + HTTP_MESSAGE_RES_HEADER, + HTTP_MESSAGE_RES_HEADER_END, + HTTP_MESSAGE_RES_BODY, + HTTP_MESSAGE_MAX +}; + +//http string +struct hstring { + char *str; + size_t str_len; +}; + +struct http_header { + struct hstring key; + struct hstring val; +}; + +struct http_request_line { + struct hstring method; + struct hstring uri; + struct hstring version; + + int major_version; + int minor_version; +}; + +struct http_response_line { + struct hstring version; + struct hstring status; + + int major_version; + int minor_version; + int status_code; +}; + +struct http_message; + +enum http_message_type http_message_type(struct http_message *msg); + +int http_message_get_request_line(struct http_message *msg, struct http_request_line *line); + +int http_message_get_response_line(struct http_message *msg, struct http_response_line *line); + +/* same key may has multiple kv */ +int http_message_get_request_header(struct http_message *msg, struct hstring *key, + struct http_header *header_array, size_t array_size); + +int http_message_get_response_header(struct http_message *msg, struct hstring *key, + struct http_header *header_array, size_t array_size); + +int http_message_request_header_next(struct http_message *msg, struct http_header *header); + +int http_message_response_header_next(struct http_message *msg, struct http_header *header); + +void http_message_get_request_raw_body(struct http_message *msg, struct hstring *body); + +void http_message_get_response_raw_body(struct http_message *msg, struct hstring *body); + +void http_message_get_request_decompress_body(struct http_message *msg, struct hstring *body); + +void http_message_get_response_decompress_body(struct http_message *msg, struct hstring *body); + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/src/http_decoder/http_decoder.toml b/src/http_decoder/http_decoder.toml new file mode 100644 index 0000000..f7717a7 --- /dev/null +++ b/src/http_decoder/http_decoder.toml @@ -0,0 +1,4 @@ +[[plugin]] +path = "./src/http_decoder/http_decoder.so" +init = "http_decoder_init" +exit = "http_decoder_exit"
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_half.c b/src/http_decoder/http_decoder_half.c new file mode 100644 index 0000000..c0b195b --- /dev/null +++ b/src/http_decoder/http_decoder_half.c @@ -0,0 +1,729 @@ +/* +********************************************************************************************** +* File: http_decoder_half.c +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#include <assert.h> +#include <stdio.h> + +#include "stellar/utils.h" +#include "llhttp.h" +#include "http_decoder_utils.h" +#include "http_decoder_half.h" +#include "http_decoder_table.h" +#include "http_content_decompress.h" + +struct http_decoder_half_data { + struct http_decoder_table *table; + + int major_version; + int minor_version; + int status_code; + + enum http_content_encoding content_encoding; + char *decompress_body; + size_t decompress_body_len; +}; + +struct http_decoder_half { + llhttp_t parser; + llhttp_settings_t settings; + enum llhttp_errno error; + + int is_cache_line; + int is_cache_header; + int is_cache_body; + + struct http_decoder_half_data *data; + enum http_event event; + http_event_cb *event_cb; + void *cb_args; +}; + +struct http_decoder_half *http_decoder_half_new() +{ + struct http_decoder_half *half = CALLOC(struct http_decoder_half, 1); + assert(half); + + return half; +} + +void http_decoder_half_free(struct http_decoder_half *half) +{ + if (NULL == half) { + return; + } + + if (half->data != NULL) { + http_decoder_half_data_free(half->data); + half->data = NULL; + } + + FREE(half); +} + +#ifdef HTTP_DECODER_DEBUG +static void printf_debug_info(const char *desc, const char *at, size_t length) +{ + if (at) + { + char *temp = safe_dup(at, length); + printf("HTTP PARSER STAGE: %s: %s\n", desc, temp); + safe_free(temp); + } + else + { + printf("HTTP PARSER STAGE: %s\n", desc); + } +} +#else +#define printf_debug_info(desc, at, length) +#endif + +static void http_decoder_half_data_decompress(struct http_decoder_half_data *data) +{ + assert(data); + + FREE(data->decompress_body); + data->decompress_body_len = 0; + + if (data->content_encoding == HTTP_CONTENT_ENCODING_NONE) { + return; + } + + struct hstring raw_body = {0}; + http_decoder_table_get_body(data->table, &raw_body); + if (raw_body.str == NULL || raw_body.str_len == 0) { + return; + } + + struct http_content_decompress *decompress = http_content_decompress_create(data->content_encoding); + assert(decompress); + if (http_content_decompress_write(decompress, raw_body.str, raw_body.str_len, + &data->decompress_body, + &data->decompress_body_len) == -1) { + // log error + } + http_content_decompress_destroy(decompress); +} + +/* Possible return values 0, -1, `HPE_PAUSED` */ +static int on_message_begin(llhttp_t *http) +{ + printf_debug_info("on_message_begin", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + assert(half->data == NULL); + + half->event = HTTP_EVENT_INIT; + if (half->event_cb != NULL) { + half->event_cb(half->event, &half->data, half->cb_args); + } + + return 0; +} + +static int on_message_complete(llhttp_t *http) +{ + printf_debug_info("on_message_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + //trigger http_body end + if (half->parser.type == HTTP_REQUEST) { + if (half->event == HTTP_EVENT_REQ_BODY_DATA) { + half->event = HTTP_EVENT_REQ_BODY_END; + if (half->event_cb != NULL) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + } else { + if (half->event == HTTP_EVENT_RES_BODY_DATA) { + half->event = HTTP_EVENT_RES_BODY_END; + if (half->event_cb != NULL) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + } + + //trigger req/res end + if (half->parser.type == HTTP_REQUEST) { + half->event = HTTP_EVENT_REQ_END; + if (half->event_cb != NULL) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } else { + half->event = HTTP_EVENT_RES_END; + if (half->event_cb != NULL) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + + return 0; +} + +static int on_reset(llhttp_t *http) +{ + printf_debug_info("on_reset", NULL, 0); + + return 0; +} + +static int on_method(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_method", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + http_decoder_table_refer(half->data->table, HTTP_ITEM_METHOD, at, length); + } + + return 0; +} + +/* Information-only callbacks, return value is ignored */ +static int on_method_complete(llhttp_t *http) +{ + printf_debug_info("on_method_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + // if (http_decoder_table_state(half->data->table, HTTP_ITEM_METHOD) == STRING_STATE_REFER) { + // http_decoder_table_cache(half->data->table, HTTP_ITEM_METHOD); + // } + http_decoder_table_commit(half->data->table, HTTP_ITEM_METHOD); + } + + return 0; +} + +/* Possible return values 0, -1, HPE_USER */ +static int on_uri(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_uri", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + http_decoder_table_refer(half->data->table, HTTP_ITEM_URI, at, length); + } + + return 0; +} + +/* Information-only callbacks, return value is ignored */ +static int on_uri_complete(llhttp_t *http) +{ + printf_debug_info("on_uri_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + // if (half->is_cache_line && http_decoder_table_state(half->data->table, HTTP_ITEM_URI) == STRING_STATE_REFER) + // { + // http_decoder_table_cache(half->data->table, HTTP_ITEM_URI); + // } + http_decoder_table_commit(half->data->table, HTTP_ITEM_URI); + } + + return 0; +} + +/* Possible return values 0, -1, HPE_USER */ +static int on_version(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_version", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + http_decoder_table_refer(half->data->table, HTTP_ITEM_VERSION, at, length); + } + + return 0; +} + +/* Information-only callbacks, return value is ignored */ +static int on_version_complete(llhttp_t *http) +{ + printf_debug_info("on_version_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data) { + // if (half->is_cache_line && http_decoder_table_state(half->data->table, HTTP_ITERM_VERSION) == STRING_STATE_REFER) + // { + // http_decoder_table_cache(half->data->table, HTTP_ITERM_VERSION); + // } + http_decoder_table_commit(half->data->table, HTTP_ITEM_VERSION); + + half->data->major_version = llhttp_get_http_major(&half->parser); + half->data->minor_version = llhttp_get_http_minor(&half->parser); + } + + if (half->parser.type == HTTP_REQUEST) { + half->event = (enum http_event)HTTP_EVENT_REQ_LINE; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + + return 0; +} + +/* Possible return values 0, -1, HPE_USER */ +static int on_status(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_status", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + http_decoder_table_refer(half->data->table, HTTP_ITEM_STATUS, at, length); + } + + return 0; +} + +/* Information-only callbacks, return value is ignored */ +static int on_status_complete(llhttp_t *http) +{ + printf_debug_info("on_status_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + // if (half->is_cache_line && http_decoder_table_state(half->data->table, HTTP_ITERM_STATUS) == STRING_STATE_REFER) + // { + // http_decoder_table_cache(half->data->table, HTTP_ITERM_STATUS); + // } + http_decoder_table_commit(half->data->table, HTTP_ITEM_STATUS); + half->data->status_code = llhttp_get_status_code(&half->parser); + } + + half->event = (enum http_event)HTTP_EVENT_RES_LINE; + if (half->event_cb != NULL) { + half->event_cb(half->event, &half->data, half->cb_args); + } + + return 0; +} + +/* Possible return values 0, -1, HPE_USER */ +static int on_header_field(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_header_field", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + http_decoder_table_refer(half->data->table, HTTP_ITEM_HDRKEY, at, length); + } + + return 0; +} + +/* Information-only callbacks, return value is ignored */ +static int on_header_field_complete(llhttp_t *http) +{ + printf_debug_info("on_header_field_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + // if (half->is_cache_header && http_decoder_table_state(half->data->table, HTTP_ITERM_HDRKEY) == STRING_STATE_REFER) + // { + // http_decoder_table_cache(half->data->table, HTTP_ITERM_HDRKEY); + // } + http_decoder_table_commit(half->data->table, HTTP_ITEM_HDRKEY); + } + + return 0; +} + +/* Possible return values 0, -1, HPE_USER */ +static int on_header_value(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_header_value", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + http_decoder_table_refer(half->data->table, HTTP_ITEM_HDRVAL, at, length); + } + + return 0; +} + +/* Information-only callbacks, return value is ignored */ +static int on_header_value_complete(llhttp_t *http) +{ + printf_debug_info("on_header_value_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->data != NULL) { + // if (half->is_cache_header && + // http_decoder_table_state(half->data->table, HTTP_ITERM_HDRVAL) == + // STRING_STATE_REFER) { + // http_decoder_table_cache(half->data->table, HTTP_ITERM_HDRVAL); + // } + http_decoder_table_commit(half->data->table, HTTP_ITEM_HDRVAL); + } + + if (half->parser.type == HTTP_REQUEST) { + half->event = HTTP_EVENT_REQ_HDR; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + + if (half->parser.type == HTTP_RESPONSE) { + half->event = HTTP_EVENT_RES_HDR; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + + if (half->data != NULL) { + if (half->data->content_encoding == HTTP_CONTENT_ENCODING_NONE) { + struct http_header http_hdr = {0}; + struct hstring key = {.str = (char *)"Content-Encoding", .str_len = 16}; + if (http_decoder_table_get_header(half->data->table, &key, &http_hdr, 1) == 1) { + char *str = safe_dup(http_hdr.val.str, http_hdr.val.str_len); + half->data->content_encoding = http_content_encoding_str2int(str); + FREE(str); + } + } + } + + return 0; +} + +/* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + * Possible return values 0, -1, `HPE_PAUSED` + */ +static int on_chunk_header(llhttp_t *http) +{ + printf_debug_info("on_chunk_header", NULL, 0); + + return 0; +} + +/* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + * Possible return values 0, -1, `HPE_PAUSED` + */ +static int on_chunk_header_complete(llhttp_t *http) +{ + printf_debug_info("on_chunk_header_complete", NULL, 0); + + return 0; +} + +/* Possible return values: + * 0 - Proceed normally + * 1 - Assume that request/response has no body, and proceed to parsing the next message + * 2 - Assume absence of body (as above) and make `llhttp_execute()` return `HPE_PAUSED_UPGRADE` + * -1 - Error `HPE_PAUSED` + */ +static int on_headers_complete(llhttp_t *http) +{ + printf_debug_info("on_headers_complete", NULL, 0); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + if (half->parser.type == HTTP_REQUEST) { + half->event = HTTP_EVENT_REQ_HDR_END; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + + if (half->parser.type == HTTP_RESPONSE) { + half->event = HTTP_EVENT_RES_HDR_END; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + + return 0; +} + +/* Possible return values 0, -1, HPE_USER */ +static int on_body(llhttp_t *http, const char *at, size_t length) +{ + printf_debug_info("on_body", at, length); + + struct http_decoder_half *half = container_of(http, struct http_decoder_half, parser); + assert(half); + + // trigger body_begin event + if (half->parser.type == HTTP_REQUEST) { + if (half->event == HTTP_EVENT_REQ_HDR_END) { + half->event = HTTP_EVENT_REQ_BODY_BEGIN; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + } else { + if (half->event == HTTP_EVENT_RES_HDR_END) { + half->event = HTTP_EVENT_RES_BODY_BEGIN; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + } + + // if enable cache_body, trigger body_data event on_message_complete + // if disable cache_body, trigger body_data event on_body + // if (half->is_cache_body) { + // if (half->data) { + // http_decoder_table_refer(half->data->table, HTTP_ITERM_BODY, at, + // length); + // http_decoder_table_cache(half->data->table, HTTP_ITERM_BODY); + // } + // } else { + if (half->data != NULL) { + if (http_decoder_table_state(half->data->table, HTTP_ITEM_BODY) == STRING_STATE_COMMIT) { + http_decoder_table_reset(half->data->table, HTTP_ITEM_BODY); + } + + http_decoder_table_refer(half->data->table, HTTP_ITEM_BODY, at, length); + http_decoder_table_commit(half->data->table, HTTP_ITEM_BODY); + + http_decoder_half_data_decompress(half->data); + } + + if (half->parser.type == HTTP_REQUEST) { + half->event = HTTP_EVENT_REQ_BODY_DATA; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } else { + half->event = HTTP_EVENT_RES_BODY_DATA; + if (half->event_cb) { + half->event_cb(half->event, &half->data, half->cb_args); + } + } + // } + + return 0; +} + +void http_decoder_half_init(struct http_decoder_half *half, http_event_cb *event_cb, + void *cb_args, int is_cache_line, int is_cache_header, + int is_cache_body) +{ + if (NULL == half) { + return; + } + + enum llhttp_type type = HTTP_BOTH; // HTTP_BOTH | HTTP_REQUEST | HTTP_RESPONSE + llhttp_settings_init(&half->settings); + llhttp_init(&half->parser, type, &half->settings); + + half->settings.on_message_begin = on_message_begin; + half->settings.on_message_complete = on_message_complete; + half->settings.on_reset = on_reset; + + half->settings.on_url = on_uri; + half->settings.on_url_complete = on_uri_complete; + + half->settings.on_status = on_status; + half->settings.on_status_complete = on_status_complete; + + half->settings.on_method = on_method; + half->settings.on_method_complete = on_method_complete; + + half->settings.on_version = on_version; + half->settings.on_version_complete = on_version_complete; + + half->settings.on_header_field = on_header_field; + half->settings.on_header_field_complete = on_header_field_complete; + + half->settings.on_header_value = on_header_value; + half->settings.on_header_value_complete = on_header_value_complete; + + half->settings.on_chunk_header = on_chunk_header; + half->settings.on_chunk_complete = on_chunk_header_complete; + + half->settings.on_headers_complete = on_headers_complete; + half->settings.on_body = on_body; + + half->error = HPE_OK; + + half->event_cb = event_cb; + half->cb_args = cb_args; //result queue pointer + half->is_cache_line = is_cache_line; + half->is_cache_header = is_cache_header; + half->is_cache_body = is_cache_body; + + half->data = NULL; +} + +int http_decoder_half_parse(struct http_decoder_half *half, const char *data, + size_t data_len) +{ + if (NULL == half || NULL == data || 0 == data_len) { + return -1; + } + + half->error = llhttp_execute(&half->parser, data, data_len); + if (half->error != HPE_OK) { + printf("llhttp_execute parse error: %s %s\n", + llhttp_errno_name(half->error), half->parser.reason); + return -1; + } + + if (half->data != NULL) { + if (http_decoder_table_state(half->data->table, HTTP_ITEM_URI) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_URI); + } + + if (http_decoder_table_state(half->data->table, HTTP_ITEM_STATUS) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_STATUS); + } + + if (http_decoder_table_state(half->data->table, HTTP_ITEM_METHOD) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_METHOD); + } + + if (http_decoder_table_state(half->data->table, HTTP_ITEM_VERSION) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_VERSION); + } + + if (http_decoder_table_state(half->data->table, HTTP_ITEM_HDRKEY) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_HDRKEY); + } + + if (http_decoder_table_state(half->data->table, HTTP_ITEM_HDRVAL) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_HDRVAL); + } + + if (http_decoder_table_state(half->data->table, HTTP_ITEM_BODY) == + STRING_STATE_REFER) { + http_decoder_table_cache(half->data->table, HTTP_ITEM_BODY); + } + } + + return 0; +} + +struct http_decoder_half_data *http_decoder_half_data_new() +{ + struct http_decoder_half_data *data = CALLOC(struct http_decoder_half_data, 1); + assert(data); + + data->table = http_decoder_table_new(); + assert(data->table); + + data->major_version = -1; + data->minor_version = -1; + data->status_code = -1; + + data->content_encoding = HTTP_CONTENT_ENCODING_NONE; + data->decompress_body = NULL; + data->decompress_body_len = 0; + + return data; +} + +void http_decoder_half_data_free(struct http_decoder_half_data *data) +{ + if (NULL == data) { + return; + } + + if (data->table != NULL) { + http_decoder_table_free(data->table); + data->table = NULL; + } + + if (data->decompress_body != NULL) { + FREE(data->decompress_body); + } + + FREE(data); +} + +int http_decoder_half_data_get_request_line(struct http_decoder_half_data *data, + struct http_request_line *line) +{ + if (NULL == data || NULL == line) { + return -1; + } + + http_decoder_table_get_method(data->table, &line->method); + http_decoder_table_get_uri(data->table, &line->uri); + http_decoder_table_get_version(data->table, &line->version); + + line->major_version = data->major_version; + line->minor_version = data->minor_version; + + return 0; +} + +int http_decoder_half_data_get_response_line(struct http_decoder_half_data *data, + struct http_response_line *line) +{ + if (NULL == data || NULL == line) { + return -1; + } + + http_decoder_table_get_version(data->table, &line->version); + http_decoder_table_get_status(data->table, &line->status); + + line->major_version = data->major_version; + line->minor_version = data->minor_version; + line->status_code = data->status_code; + + return 0; +} + +int http_decoder_half_data_get_header(struct http_decoder_half_data *data, + struct hstring *key, + struct http_header *header_array, + size_t array_size) +{ + http_decoder_table_get_header(data->table, key, header_array, array_size); +} + +int http_decoder_half_data_iter_header(struct http_decoder_half_data *data, + struct http_header *header) +{ + if (NULL == data || NULL == data->table) { + return -1; + } + + http_decoder_table_iter_header(data->table, header); +}
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_half.h b/src/http_decoder/http_decoder_half.h new file mode 100644 index 0000000..5eede43 --- /dev/null +++ b/src/http_decoder/http_decoder_half.h @@ -0,0 +1,82 @@ +/* +********************************************************************************************** +* File: http_decoder_half.h +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _HTTP_DECODER_HALF_H_ +#define _HTTP_DECODER_HALF_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stddef.h> + +#include "http_decoder.h" +#include "http_content_decompress.h" + +// only one http event is fired at a time +enum http_event { + HTTP_EVENT_INIT = 0, + + HTTP_EVENT_REQ_LINE = 1 << 1, + HTTP_EVENT_REQ_HDR = 1 << 2, + HTTP_EVENT_REQ_HDR_END = 1 << 3, + HTTP_EVENT_REQ_BODY_BEGIN = 1 << 4, + HTTP_EVENT_REQ_BODY_DATA = 1 << 5, + HTTP_EVENT_REQ_BODY_END = 1 << 6, + HTTP_EVENT_REQ_END = 1 << 7, + + HTTP_EVENT_RES_LINE = 1 << 8, + HTTP_EVENT_RES_HDR = 1 << 9, + HTTP_EVENT_RES_HDR_END = 1 << 10, + HTTP_EVENT_RES_BODY_BEGIN = 1 << 11, + HTTP_EVENT_RES_BODY_DATA = 1 << 12, + HTTP_EVENT_RES_BODY_END = 1 << 13, + HTTP_EVENT_RES_END = 1 << 14, +}; + +struct http_decoder_half; +struct http_decoder_half_data; + +typedef void http_event_cb(enum http_event event, struct http_decoder_half_data **data, void *cb_args); + +struct http_decoder_half *http_decoder_half_new(); + +void http_decoder_half_free(struct http_decoder_half *half); + +void http_decoder_half_init(struct http_decoder_half *half, http_event_cb *event_cb, + void *cb_args, int is_cache_line, int is_cache_header, + int is_cache_body); + +int http_decoder_half_parse(struct http_decoder_half *half, const char *data, size_t len); + +//http decoder half data API +struct http_decoder_half_data *http_decoder_half_data_new(); + +void http_decoder_half_data_free(struct http_decoder_half_data *data); + +int http_decoder_half_data_get_request_line(struct http_decoder_half_data *data, + struct http_request_line *line); + +int http_decoder_half_data_get_response_line(struct http_decoder_half_data *data, + struct http_response_line *line); + +int http_decoder_half_data_get_header(struct http_decoder_half_data *data, + struct hstring *key, + struct http_header *header_array, + size_t array_size); + +int http_decoder_half_data_iter_header(struct http_decoder_half_data *data, + struct http_header *header); +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_string.c b/src/http_decoder/http_decoder_string.c new file mode 100644 index 0000000..15ff290 --- /dev/null +++ b/src/http_decoder/http_decoder_string.c @@ -0,0 +1,176 @@ +/* +********************************************************************************************** +* File: http_decoder_string.h +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#include <stdlib.h> + +#include "http_decoder_string.h" + +static const char *string_state_to_desc(enum string_state state) +{ + switch (state) { + case STRING_STATE_INIT: + return "init"; + break; + case STRING_STATE_REFER: + return "refer"; + break; + case STRING_STATE_CACHE: + return "cache"; + break; + case STRING_STATE_COMMIT: + return "commit"; + break; + default: + return "unknown"; + break; + } +} + +void http_decoder_string_refer(struct http_decoder_string *rstr, + const char *at, size_t length) +{ + if (NULL == rstr) { + return; + } + + switch (rstr->state) { + case STRING_STATE_INIT: + case STRING_STATE_CACHE: + rstr->refer.str = (char *)at; + rstr->refer.str_len = length; + break; + default: + abort(); + break; + } + + rstr->state = STRING_STATE_REFER; +} + +void http_decoder_string_cache(struct http_decoder_string *rstr) +{ + if (NULL == rstr) { + return; + } + + switch (rstr->state) { + case STRING_STATE_REFER: + if (rstr->refer.str_len > 0) { + rstr->cache.str = (char *)realloc(rstr->cache.str, rstr->cache.str_len + rstr->refer.str_len); + memcpy(rstr->cache.str + rstr->cache.str_len, rstr->refer.str, rstr->refer.str_len); + rstr->cache.str_len += rstr->refer.str_len; + + rstr->refer.str = NULL; + rstr->refer.str_len = 0; + } + break; + default: + abort(); + break; + } + + rstr->state = STRING_STATE_CACHE; +} + +void http_decoder_string_commit(struct http_decoder_string *rstr) +{ + if (NULL == rstr) { + return; + } + + switch (rstr->state) { + case STRING_STATE_REFER: + if (rstr->cache.str_len) { + http_decoder_string_cache(rstr); + + rstr->commit.str = rstr->cache.str; + rstr->commit.str_len = rstr->cache.str_len; + // not overwrite rstr->cache.str + } else { + rstr->commit.str = rstr->refer.str; + rstr->commit.str_len = rstr->refer.str_len; + + rstr->refer.str = NULL; + rstr->refer.str_len = 0; + } + break; + case STRING_STATE_CACHE: + rstr->commit.str = rstr->cache.str; + rstr->commit.str_len = rstr->cache.str_len; + // not overwrite rstr->cache.str + break; + default: + abort(); + break; + } + + rstr->state = STRING_STATE_COMMIT; +} + +void http_decoder_string_reset(struct http_decoder_string *rstr) +{ + assert(rstr); + + switch (rstr->state) { + case STRING_STATE_INIT: + case STRING_STATE_REFER: + case STRING_STATE_CACHE: + case STRING_STATE_COMMIT: + safe_free(rstr->cache.str); + memset(rstr, 0, sizeof(struct http_decoder_string)); + break; + default: + abort(); + break; + } + + rstr->state = STRING_STATE_INIT; +} + +enum string_state http_decoder_string_state(struct http_decoder_string *rstr) +{ + return rstr->state; +} + +void http_decoder_string_get(struct http_decoder_string *rstr, struct hstring *out) +{ + if (NULL == rstr || NULL == out) { + return; + } + + if (http_decoder_string_state(rstr) == STRING_STATE_COMMIT) { + out->str = rstr->commit.str; + out->str_len = rstr->commit.str_len; + } else { + out->str = NULL; + out->str_len = 0; + } +} + +void http_decoder_string_dump(struct http_decoder_string *rstr, const char *desc) +{ + if (NULL == rstr) { + return; + } + + char *refer_str = safe_dup(rstr->refer.str, rstr->refer.str_len); + char *cache_str = safe_dup(rstr->cache.str, rstr->cache.str_len); + char *commit_str = safe_dup(rstr->commit.str, rstr->commit.str_len); + + printf("%s: state: %s, refer: {len: %02zu, str: %s}, cache: {len: %02zu, str: %s}, commit: {len: %02zu, str: %s}\n", + desc, string_state_to_desc(rstr->state), + rstr->refer.str_len, refer_str, + rstr->cache.str_len, cache_str, + rstr->commit.str_len, commit_str); + + FREE(refer_str); + FREE(cache_str); + FREE(commit_str); +}
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_string.h b/src/http_decoder/http_decoder_string.h new file mode 100644 index 0000000..82a812b --- /dev/null +++ b/src/http_decoder/http_decoder_string.h @@ -0,0 +1,87 @@ +/* +********************************************************************************************** +* File: http_decoder_string.h +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _HTTP_DECODER_STRING_H_ +#define _HTTP_DECODER_STRING_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "http_decoder.h" + +enum string_state { + STRING_STATE_INIT, + STRING_STATE_REFER, + STRING_STATE_CACHE, + STRING_STATE_COMMIT, +}; + +/* state transition diagram + * +----------+ + * | | + * \|/ | + * +------+ | + * | init | | + * +------+ | + * | | + * +---->| | + * | \|/ | + * | +-------+ | + * | | refer |--+ | + * | +-------+ | | + * | | | | + * | \|/ | | + * | +-------+ | | + * +--| cache | | | + * +-------+ | | + * | | | + * |<------+ | + * \|/ | + * +--------+ | + * | commit | | + * +--------+ | + * | | + * \|/ | + * +--------+ | + * | reset |----+ + * +--------+ + */ + + +//http decoder string +struct http_decoder_string { + struct hstring refer; // shallow copy + struct hstring cache; // deep copy + struct hstring commit; + + enum string_state state; +}; + +void http_decoder_string_refer(struct http_decoder_string *rstr, const char *at, size_t length); + +void http_decoder_string_cache(struct http_decoder_string *rstr); + +void http_decoder_string_commit(struct http_decoder_string *rstr); + +void http_decoder_string_reset(struct http_decoder_string *rstr); + +enum string_state http_decoder_string_state(struct http_decoder_string *rstr); + +void http_decoder_string_get(struct http_decoder_string *rstr, struct hstring *out); + +void http_decoder_string_dump(struct http_decoder_string *rstr, const char *desc); + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_table.c b/src/http_decoder/http_decoder_table.c new file mode 100644 index 0000000..292c80c --- /dev/null +++ b/src/http_decoder/http_decoder_table.c @@ -0,0 +1,464 @@ +/* +********************************************************************************************** +* File: http_decoder_table.c +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "http_decoder_table.h" +#include "http_decoder.h" +#include "http_decoder_string.h" +#include "stellar/utils.h" + +#define MAX_HEADER_SIZE 16 + +struct http_decoder_header { + struct http_decoder_string key; + struct http_decoder_string val; +}; + +struct http_decoder_table { + struct http_decoder_string uri; + struct http_decoder_string status; + struct http_decoder_string method; + struct http_decoder_string version; + struct http_decoder_string body; + + size_t header_size; + size_t header_index; + size_t header_iter; + struct http_decoder_header *headers; +}; + +struct http_decoder_table *http_decoder_table_new() +{ + struct http_decoder_table *table = CALLOC(struct http_decoder_table, 1); + assert(table); + + table->header_index = 0; + table->header_size = MAX_HEADER_SIZE; + table->headers = CALLOC(struct http_decoder_header, table->header_size); + + return table; +} + +void http_decoder_table_free(struct http_decoder_table *table) +{ + if (NULL == table) { + return; + } + + if (table->uri.cache.str != NULL) { + FREE(table->uri.cache.str); + } + + if (table->status.cache.str != NULL) { + FREE(table->status.cache.str); + } + + if (table->method.cache.str != NULL) { + FREE(table->method.cache.str); + } + + if (table->version.cache.str != NULL) { + FREE(table->version.cache.str); + } + + if (table->body.cache.str != NULL) { + FREE(table->body.cache.str); + } + + if (table->headers != NULL) { + FREE(table->headers); + } + + FREE(table); +} + +enum string_state http_decoder_table_state(struct http_decoder_table *table, + enum http_item type) +{ + if (NULL == table) { + return STRING_STATE_INIT; + } + struct http_decoder_header *header = NULL; + enum string_state state = STRING_STATE_INIT; + assert(table); + + switch (type) { + case HTTP_ITEM_URI: + state = http_decoder_string_state(&table->uri); + break; + case HTTP_ITEM_STATUS: + state = http_decoder_string_state(&table->status); + break; + case HTTP_ITEM_METHOD: + state = http_decoder_string_state(&table->method); + break; + case HTTP_ITEM_VERSION: + state = http_decoder_string_state(&table->version); + break; + case HTTP_ITEM_HDRKEY: + header = &table->headers[table->header_index]; + state = http_decoder_string_state(&header->key); + break; + case HTTP_ITEM_HDRVAL: + header = &table->headers[table->header_index]; + state = http_decoder_string_state(&header->val); + break; + case HTTP_ITEM_BODY: + state = http_decoder_string_state(&table->body); + break; + default: + abort(); + break; + } + + return state; +} + +void http_decoder_table_refer(struct http_decoder_table *table, enum http_item type, + const char *at, size_t len) +{ + if (NULL == table) { + return; + } + + struct http_decoder_header *header = NULL; + assert(table); + + switch (type) { + case HTTP_ITEM_URI: + http_decoder_string_refer(&table->uri, at, len); + break; + case HTTP_ITEM_STATUS: + http_decoder_string_refer(&table->status, at, len); + break; + case HTTP_ITEM_METHOD: + http_decoder_string_refer(&table->method, at, len); + break; + case HTTP_ITEM_VERSION: + http_decoder_string_refer(&table->version, at, len); + break; + case HTTP_ITEM_HDRKEY: + if (table->header_index >= table->header_size) { + table->headers = (struct http_decoder_header *)realloc(table->headers, + table->header_size * 2); + assert(table->headers); + + table->header_size *= 2; + for (size_t i = table->header_index; i < table->header_size; i++) { + header = &table->headers[i]; + memset(header, 0, sizeof(struct http_decoder_header)); + } + } + header = &table->headers[table->header_index]; + http_decoder_string_refer(&header->key, at, len); + break; + case HTTP_ITEM_HDRVAL: + header = &table->headers[table->header_index]; + http_decoder_string_refer(&header->val, at, len); + break; + case HTTP_ITEM_BODY: + http_decoder_string_refer(&table->body, at, len); + break; + default: + abort(); + break; + } +} + +void http_decoder_table_cache(struct http_decoder_table *table, enum http_item type) +{ + if (NULL == table) { + return; + } + + struct http_decoder_header *header = NULL; + assert(table); + + switch (type) { + case HTTP_ITEM_URI: + http_decoder_string_cache(&table->uri); + break; + case HTTP_ITEM_STATUS: + http_decoder_string_cache(&table->status); + break; + case HTTP_ITEM_METHOD: + http_decoder_string_cache(&table->method); + break; + case HTTP_ITEM_VERSION: + http_decoder_string_cache(&table->version); + break; + case HTTP_ITEM_HDRKEY: + header = &table->headers[table->header_index]; + http_decoder_string_cache(&header->key); + break; + case HTTP_ITEM_HDRVAL: + header = &table->headers[table->header_index]; + http_decoder_string_cache(&header->val); + break; + case HTTP_ITEM_BODY: + http_decoder_string_cache(&table->body); + break; + default: + abort(); + break; + } +} + +void http_decoder_table_commit(struct http_decoder_table *table, enum http_item type) +{ + if (NULL == table) { + return; + } + + struct http_decoder_header *header = NULL; + assert(table); + + switch (type) { + case HTTP_ITEM_URI: + http_decoder_string_commit(&table->uri); + break; + case HTTP_ITEM_STATUS: + http_decoder_string_commit(&table->status); + break; + case HTTP_ITEM_METHOD: + http_decoder_string_commit(&table->method); + break; + case HTTP_ITEM_VERSION: + http_decoder_string_commit(&table->version); + break; + case HTTP_ITEM_HDRKEY: + header = &table->headers[table->header_index]; + http_decoder_string_commit(&header->key); + break; + case HTTP_ITEM_HDRVAL: + header = &table->headers[table->header_index]; + http_decoder_string_commit(&header->val); + // inc index + table->header_index++; + break; + case HTTP_ITEM_BODY: + http_decoder_string_commit(&table->body); + break; + default: + abort(); + break; + } +} + +void http_decoder_table_reset(struct http_decoder_table *table, enum http_item type) +{ + if (NULL == table) { + return; + } + + struct http_decoder_header *header = NULL; + assert(table); + + switch (type) { + case HTTP_ITEM_URI: + http_decoder_string_reset(&table->uri); + break; + case HTTP_ITEM_STATUS: + http_decoder_string_reset(&table->status); + break; + case HTTP_ITEM_METHOD: + http_decoder_string_reset(&table->method); + break; + case HTTP_ITEM_VERSION: + http_decoder_string_reset(&table->version); + break; + case HTTP_ITEM_HDRKEY: + header = &table->headers[table->header_index]; + http_decoder_string_reset(&header->key); + break; + case HTTP_ITEM_HDRVAL: + header = &table->headers[table->header_index]; + http_decoder_string_reset(&header->val); + break; + case HTTP_ITEM_BODY: + http_decoder_string_reset(&table->body); + break; + default: + abort(); + break; + } +} + +void http_decoder_table_remove(struct http_decoder_table *table) +{ + if (NULL == table) { + return; + } + + if (http_decoder_string_state(&table->uri) == STRING_STATE_COMMIT) { + http_decoder_string_reset(&table->uri); + } + + if (http_decoder_string_state(&table->status) == STRING_STATE_COMMIT) { + http_decoder_string_reset(&table->status); + } + + if (http_decoder_string_state(&table->method) == STRING_STATE_COMMIT) { + http_decoder_string_reset(&table->method); + } + + if (http_decoder_string_state(&table->version) == STRING_STATE_COMMIT) { + http_decoder_string_reset(&table->version); + } + + if (http_decoder_string_state(&table->body) == STRING_STATE_COMMIT) { + http_decoder_string_reset(&table->body); + } + + for (size_t i = 0; i <= table->header_index; i++) { + struct http_decoder_header *header = &table->headers[i]; + if (http_decoder_string_state(&header->key) == STRING_STATE_COMMIT && + http_decoder_string_state(&header->val) == STRING_STATE_COMMIT) { + http_decoder_string_reset(&header->key); + http_decoder_string_reset(&header->val); + } + } + + if (table->header_index != 0) { + struct http_decoder_header *last_header = + &table->headers[table->header_index]; + if (http_decoder_string_state(&last_header->key) == STRING_STATE_CACHE || + http_decoder_string_state(&last_header->val) == STRING_STATE_CACHE) { + memmove(&table->headers[0], last_header, sizeof(struct http_decoder_header)); + memset(last_header, 0, sizeof(struct http_decoder_header)); + } + + table->header_index = 0; + } +} + +void http_decoder_table_dump(struct http_decoder_table *table) +{ + if (NULL == table) { + return; + } + + http_decoder_string_dump(&table->uri, "uri"); + http_decoder_string_dump(&table->status, "status"); + http_decoder_string_dump(&table->method, "method"); + http_decoder_string_dump(&table->version, "version"); + http_decoder_string_dump(&table->body, "body"); + + for (size_t i = 0; i <= table->header_index; i++) { + struct http_decoder_header *header = &table->headers[i]; + http_decoder_string_dump(&header->key, "key"); + http_decoder_string_dump(&header->val, "val"); + } +} + +void http_decoder_table_get_uri(struct http_decoder_table *table, + struct hstring *out) +{ + if (NULL == table || NULL == out) { + return; + } + + http_decoder_string_get(&table->uri, out); +} + +void http_decoder_table_get_method(struct http_decoder_table *table, + struct hstring *out) +{ + if (NULL == table || NULL == out) { + return; + } + + http_decoder_string_get(&table->method, out); +} + +void http_decoder_table_get_status(struct http_decoder_table *table, + struct hstring *out) +{ + if (NULL == table || NULL == out) { + return; + } + + http_decoder_string_get(&table->status, out); +} + +void http_decoder_table_get_version(struct http_decoder_table *table, + struct hstring *out) +{ + if (NULL == table || NULL == out) { + return; + } + + http_decoder_string_get(&table->version, out); +} + +void http_decoder_table_get_body(struct http_decoder_table *table, + struct hstring *out) +{ + if (NULL == table || NULL == out) { + return; + } + + http_decoder_string_get(&table->body, out); +} + +size_t http_decoder_table_get_header(struct http_decoder_table *table, struct hstring *key, + struct http_header *header_array, size_t array_size) +{ + if (NULL == table || NULL == key || NULL == header_array) { + return 0; + } + + size_t header_cnt = 0; + for (size_t i = 0; i < table->header_index && header_cnt < array_size; i++) { + struct http_decoder_header *header = &table->headers[i]; + if (http_decoder_string_state(&header->key) == STRING_STATE_COMMIT && + http_decoder_string_state(&header->val) == STRING_STATE_COMMIT) { + struct hstring tmp_key; + http_decoder_string_get(&header->key, &tmp_key); + + if (tmp_key.str_len == key->str_len && strncasecmp(tmp_key.str, key->str, key->str_len) == 0) { + http_decoder_string_get(&header->val, &header_array[header_cnt++].val); + } + } + } + + return header_cnt; +} + +int http_decoder_table_iter_header(struct http_decoder_table *table, + struct http_header *header) +{ + if (NULL == table) { + return -1; + } + + if (table->header_iter >= table->header_index) { + table->header_iter = 0; + } + + struct http_decoder_header *tmp_decoder_header = &table->headers[table->header_iter++]; + if (http_decoder_string_state(&tmp_decoder_header->key) == STRING_STATE_COMMIT && + http_decoder_string_state(&tmp_decoder_header->val) == STRING_STATE_COMMIT) { + http_decoder_string_get(&tmp_decoder_header->key, &header->key); + http_decoder_string_get(&tmp_decoder_header->val, &header->val); + return 1; + } + + header->key.str = NULL; + header->key.str_len = 0; + + header->val.str = NULL; + header->val.str_len = 0; + + return 0; +}
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_table.h b/src/http_decoder/http_decoder_table.h new file mode 100644 index 0000000..53ff61d --- /dev/null +++ b/src/http_decoder/http_decoder_table.h @@ -0,0 +1,82 @@ +/* +********************************************************************************************** +* File: http_decoder_table.h +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _HTTP_DECODER_TABLE_H_ +#define _HTTP_DECODER_TABLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +#include "http_decoder.h" +#include "http_decoder_string.h" + +enum http_item { + HTTP_ITEM_URI = 0x01, + HTTP_ITEM_STATUS = 0x02, + HTTP_ITEM_METHOD = 0x03, + HTTP_ITEM_VERSION = 0x04, + HTTP_ITEM_HDRKEY = 0x05, + HTTP_ITEM_HDRVAL = 0x06, + HTTP_ITEM_BODY = 0x07, +}; + +struct http_decoder_table; + +struct http_decoder_table *http_decoder_table_new(); + +void http_decoder_table_free(struct http_decoder_table *table); + +enum string_state http_decoder_table_state(struct http_decoder_table *table, + enum http_item type); + +void http_decoder_table_refer(struct http_decoder_table *table, + enum http_item type, const char *at, size_t len); + +void http_decoder_table_cache(struct http_decoder_table *table, + enum http_item type); + +void http_decoder_table_commit(struct http_decoder_table *table, + enum http_item type); + +void http_decoder_table_reset(struct http_decoder_table *table, + enum http_item type); + +void http_decoder_table_remove(struct http_decoder_table *table); + +void http_decoder_table_dump(struct http_decoder_table *table); + +void http_decoder_table_get_uri(struct http_decoder_table *table, + struct hstring *out); + +void http_decoder_table_get_method(struct http_decoder_table *table, + struct hstring *out); + +void http_decoder_table_get_status(struct http_decoder_table *table, + struct hstring *out); + +void http_decoder_table_get_version(struct http_decoder_table *table, + struct hstring *out); + +void http_decoder_table_get_body(struct http_decoder_table *table, + struct hstring *out); + +size_t http_decoder_table_get_header(struct http_decoder_table *table, struct hstring *key, + struct http_header *header_array, size_t array_size); + +int http_decoder_table_iter_header(struct http_decoder_table *table, + struct http_header *header); +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_utils.c b/src/http_decoder/http_decoder_utils.c new file mode 100644 index 0000000..a5dfbe1 --- /dev/null +++ b/src/http_decoder/http_decoder_utils.c @@ -0,0 +1,25 @@ +/* +********************************************************************************************** +* File: http_decoder_utils.c +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#include <string.h> + +#include "stellar/utils.h" + +char *safe_dup(const char *str, size_t len) +{ + if (str == NULL || len == 0) { + return NULL; + } + + char *dup = CALLOC(char, len + 1); + memcpy(dup, str, len); + + return dup; +}
\ No newline at end of file diff --git a/src/http_decoder/http_decoder_utils.h b/src/http_decoder/http_decoder_utils.h new file mode 100644 index 0000000..0d981c5 --- /dev/null +++ b/src/http_decoder/http_decoder_utils.h @@ -0,0 +1,65 @@ +/* +********************************************************************************************** +* File: http_decoder_utils.h +* Description: +* Authors: LuWenPeng <[email protected]> +* Date: 2022-10-31 +* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _HTTP_DECODER_UTILS_H_ +#define _HTTP_DECODER_UTILS_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdio.h> + +char *safe_dup(const char *str, size_t len); + +/****************************************************************************** + * Logger + ******************************************************************************/ + +enum http_decoder_log_level +{ + DEBUG = 0x11, + WARN = 0x12, + INFO = 0x13, + ERROR = 0x14, +}; + +#ifndef http_decoder_log +#define http_decoder_log(level, format, ...) \ + { \ + switch (level) \ + { \ + case DEBUG: \ + fprintf(stdout, "HTTP_DECODER [DEBUG] " format "\n", ##__VA_ARGS__); \ + fflush(stdout); \ + break; \ + case WARN: \ + fprintf(stdout, "HTTP_DECODER [WARN] " format "\n", ##__VA_ARGS__); \ + fflush(stdout); \ + break; \ + case INFO: \ + fprintf(stdout, "HTTP_DECODER [INFO] " format "\n", ##__VA_ARGS__); \ + fflush(stdout); \ + break; \ + case ERROR: \ + fprintf(stderr, "HTTP_DECODER [ERROR] " format "\n", ##__VA_ARGS__); \ + fflush(stderr); \ + break; \ + } \ + } +#endif + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/src/http_decoder/version.map b/src/http_decoder/version.map new file mode 100644 index 0000000..a0ba8a4 --- /dev/null +++ b/src/http_decoder/version.map @@ -0,0 +1,7 @@ +VERS_3.0{ +global: + extern "C" { + http_message_*; + }; +local: *; +};
\ No newline at end of file diff --git a/src/stellar_on_sapp/start_loader.inf b/src/stellar_on_sapp/start_loader.inf index f966457..89b2f94 100644 --- a/src/stellar_on_sapp/start_loader.inf +++ b/src/stellar_on_sapp/start_loader.inf @@ -4,13 +4,13 @@ SO_PATH=./plug/stellar_on_sapp/stellar_on_sapp.so INIT_FUNC=STELLAR_START_LOADER_INIT DESTROY_FUNC=STELLAR_START_LOADER_EXIT -[TCP_ALL] -FUNC_FLAG=ALL -FUNC_NAME=stellar_on_sapp_tcpall_entry - -#[TCP] +#[TCP_ALL] #FUNC_FLAG=ALL -#FUNC_NAME=stellar_on_sapp_tcp_entry +#FUNC_NAME=stellar_on_sapp_tcpall_entry + +[TCP] +FUNC_FLAG=ALL +FUNC_NAME=stellar_on_sapp_tcp_entry [UDP] FUNC_FLAG=ALL diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 56d7b60..b7beeaa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,5 +10,7 @@ target_link_libraries( gtest ) +add_subdirectory(http_decoder) + include(GoogleTest) gtest_discover_tests(gtest_stellar)
\ No newline at end of file diff --git a/test/http_decoder/CMakeLists.txt b/test/http_decoder/CMakeLists.txt new file mode 100644 index 0000000..4ef959c --- /dev/null +++ b/test/http_decoder/CMakeLists.txt @@ -0,0 +1,40 @@ +set(DECODER_NAME http_decoder) + +add_library(${DECODER_NAME}_test_plug SHARED http_decoder_gtest.cpp) +add_dependencies(${DECODER_NAME}_test_plug ${DECODER_NAME}) +target_link_libraries(${DECODER_NAME}_test_plug MESA_prof_load cjson) +set_target_properties(${DECODER_NAME}_test_plug PROPERTIES PREFIX "") + +set(TEST_RUN_DIR ${CMAKE_CURRENT_BINARY_DIR}/sapp) +set(TEST_MAIN ${TEST_RUN_DIR}/plugin_test_main) + +# assemble test env +add_test(NAME INSTALL_TEST_MAIN COMMAND sh -c "rpm -i ${CMAKE_CURRENT_SOURCE_DIR}/test_env/sapp4.el8.x86_64.rpm --prefix=${CMAKE_CURRENT_BINARY_DIR}/sapp --force --nodeps") + +add_test(NAME COPY_TEST_MAIN COMMAND sh -c "cp ${TEST_RUN_DIR}/tools/plugin_test_main ${TEST_RUN_DIR}/plugin_test_main") +add_test(NAME COPY_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/tsgconf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/test_env/tsg_l7_protocol.conf ${TEST_RUN_DIR}/tsgconf/tsg_l7_protocol.conf") +add_test(NAME COPY_SPEC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/stellar_plugin/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/test_env/spec.toml ${TEST_RUN_DIR}/stellar_plugin/spec.toml") +add_test(NAME COPY_CONFLIST COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/plug/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/test_env/conflist.inf ${TEST_RUN_DIR}/plug/conflist.inf") +add_test(NAME COPY_INF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/plug/stellar_on_sapp && cp ${CMAKE_CURRENT_SOURCE_DIR}/test_env/start_loader.inf ${TEST_RUN_DIR}/plug/stellar_on_sapp/start_loader.inf") + +# update config files +add_test(NAME UPDATE_SAPP_LOG COMMAND bash -c "sed -i 's/sapp_log.fatal/sapp_log.info/' ${TEST_RUN_DIR}/etc/sapp_log.conf") +add_test(NAME UPDATE_SAPP_SYN_MODE COMMAND bash -c "sed -i 's/syn_mandatory=1/syn_mandatory=0/' ${TEST_RUN_DIR}/etc/sapp.toml") +add_test(NAME UPDATE_SAPP_REORDER COMMAND bash -c "sed -i 's/reorder_pkt_max=32/reorder_pkt_max=5/' ${TEST_RUN_DIR}/etc/sapp.toml") + + +# update plugin to be tested +add_test(NAME UPDATE_STELLAR_ON_SAPP_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/src/stellar_on_sapp/stellar_on_sapp.so ${TEST_RUN_DIR}/plug/stellar_on_sapp/stellar_on_sapp.so") +add_test(NAME UPDATE_PLUG_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/src/${DECODER_NAME}/${DECODER_NAME}.so ${TEST_RUN_DIR}/stellar_plugin/${DECODER_NAME}.so") +add_test(NAME UPDATE_TEST_SO COMMAND sh -c "cp ${CMAKE_CURRENT_BINARY_DIR}/${DECODER_NAME}_test_plug.so ${TEST_RUN_DIR}/stellar_plugin/${DECODER_NAME}_test_plug.so") + +set_tests_properties(INSTALL_TEST_MAIN COPY_TEST_MAIN COPY_CONF COPY_SPEC COPY_CONFLIST COPY_INF + UPDATE_SAPP_LOG UPDATE_SAPP_SYN_MODE UPDATE_SAPP_REORDER + UPDATE_STELLAR_ON_SAPP_SO UPDATE_PLUG_SO UPDATE_TEST_SO + PROPERTIES FIXTURES_SETUP TestFixture) + +# run tests +# add_test(NAME RUN_HTTP_SIMPLE_TEST COMMAND ${TEST_MAIN} ${CMAKE_CURRENT_SOURCE_DIR}/test_result_json/proto_identify_http.json +# -f "find ${CMAKE_CURRENT_SOURCE_DIR}/http_pcap/ -name *.pcap|sort -V" WORKING_DIRECTORY ${TEST_RUN_DIR}) + +# set_tests_properties(RUN_HTTP_SIMPLE_TEST PROPERTIES FIXTURES_REQUIRED TestFixture)
\ No newline at end of file diff --git a/test/http_decoder/http_decoder_gtest.cpp b/test/http_decoder/http_decoder_gtest.cpp new file mode 100644 index 0000000..9ebaddd --- /dev/null +++ b/test/http_decoder/http_decoder_gtest.cpp @@ -0,0 +1,185 @@ +/* + * author:yangwei + * create time:2021-8-21 + * + */ + + + +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <assert.h> + +#include "../../src/http_decoder/http_decoder.h" + +#ifdef __cplusplus +extern "C" +{ + + +#include "cJSON.h" +#include "MESA_prof_load.h" + +#include "stellar/utils.h" +#include "stellar/stellar.h" +#include "stellar/session_exdata.h" +#include "stellar/session_mq.h" + +int commit_test_result_json(cJSON *node, const char *name); +} +#endif + +#include "MESA/stream.h" + +static int g_result_count = 1; +int g_test_exdata_idx = 0; +int g_l7_exdata_idx = 0; +int g_test_app_plugin_id = 0; +int g_stellar_session_bridge_id = -1; + +#define MAX_PROTO_ID_NUM 10000 +static char *g_proto_id2name[MAX_PROTO_ID_NUM]; + +struct http_decoder_test_context { + int topic_id; + int plugin_id; +}; + +// static int load_l7_protocol_mapper(const char *filename) { +// int ret = 0, proto_id = 0; +// char line[1024] = {0}; +// char type_name[32] = {0}; +// char proto_name[32] = {0}; + +// memset(g_proto_id2name, 0, sizeof(g_proto_id2name)); +// FILE *fp = fopen(filename, "r"); +// if (NULL == fp) { +// printf("Open %s failed ...", filename); +// return -1; +// } + +// memset(line, 0, sizeof(line)); + +// while ((fgets(line, sizeof(line), fp)) != NULL) { +// if (line[0] == '#' || line[0] == '\n' || +// line[0] == '\r' || line[0] == '\0') { +// continue; +// } + +// ret = sscanf(line, "%30s %30s %d", type_name, proto_name, &proto_id); +// assert(ret == 3 && proto_id < MAX_PROTO_ID_NUM); + +// g_proto_id2name[proto_id] = (char *)calloc(strlen(proto_name)+1, 1); +// strcpy(g_proto_id2name[proto_id], proto_name); +// memset(line, 0, sizeof(line)); +// } + +// fclose(fp); +// fp = NULL; + +// return ret; +// } + +static void commit_test_result(cJSON *ctx, struct session *sess) +{ + assert(g_l7_exdata_idx >= 0 && ctx != NULL); + struct http_request_line *label = (struct http_request_line *)session_get_ex_data(sess, g_l7_exdata_idx);; + // if(label != NULL) + // { + // int proto_ids[8]; + // const char* proto_names[8]; + // for(int i = 0; i < label->protocol_id_num; i++) + // { + // proto_ids[i] = (int)(label->protocol_id[i]); + // proto_names[i] = g_proto_id2name[proto_ids[i]]; + + // } + // cJSON *label_ids = cJSON_CreateIntArray(proto_ids, label->protocol_id_num); + // cJSON_AddItemToObject(ctx, "l7_label_id", label_ids); + // cJSON *label_names = cJSON_CreateStringArray(proto_names, label->protocol_id_num); + // cJSON_AddItemToObject(ctx, "l7_label_name", label_names); + // } + // else + // { + // cJSON_AddStringToObject(ctx, "l7_label_id", "UNKNOWN"); + // } + // unsigned char dir_flag; + // int is_symmetric=session_is_symmetric(sess, &dir_flag); + // if(is_symmetric) + // { + // cJSON_AddStringToObject(ctx, "STREAM_DIR", "DOUBLE"); + // } + // else if(dir_flag == SESSION_SEEN_C2S_FLOW) + // { + // cJSON_AddStringToObject(ctx, "STREAM_DIR", "C2S"); + // } + // else if(dir_flag == SESSION_SEEN_S2C_FLOW) + // { + // cJSON_AddStringToObject(ctx, "STREAM_DIR", "S2C"); + // } + // else + // { + // assert(0); + // } + // if (ctx) + // { + // char result_name[128] = ""; + // sprintf(result_name, "APP_PROTO_IDENTIFY_RESULT_%d", g_result_count); + // commit_test_result_json(ctx, result_name); + // g_result_count += 1; + // } + return; +} + +static int http_decoder_test_entry(struct session *sess, int topic_id, const void *data, void *cb_arg) +{ + struct http_message *msg = (struct http_message *)data; + + printf("................http_decoder_test_entry................\n"); + struct http_request_line line; + memset(&line, 0, sizeof(line)); + + enum http_message_type msg_type = http_message_type(msg); + switch (msg_type) { + case HTTP_MESSAGE_REQ_LINE: + http_message_get_request_line(msg, &line); + break; + default: + break; + } + + return 0; +} + +extern "C" void *http_decoder_test_init(struct stellar *st) +{ + char l7_label_name[256] = ""; + char l7_bridge_name[256] = ""; + char l7_proto_name[256] = ""; + + MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "L7_LABEL_NAME", l7_label_name, sizeof(l7_label_name), "L7_PROTOCOL_LABEL"); + MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "APP_BRIDGE_NAME", l7_bridge_name, sizeof(l7_bridge_name), "APP_BRIDGE"); + MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "L7_PROTOCOL_FILE", l7_proto_name, sizeof(l7_proto_name), "./tsgconf/tsg_l7_protocol.conf"); + + int topic_id = session_mq_get_topic_id(st, "HTTP_DECODER_MESSAGE"); + if (topic_id < 0) { + printf("http_decoder_test_init: can't get http_decoder topic id !!!\n"); + exit(-1); + } + + session_mq_subscribe_topic(st, topic_id, http_decoder_test_entry, NULL); + printf("http_decoder_test_init OK!\n"); + + return NULL; +} + +extern "C" void http_decoder_test_exit(void *ctx) +{ + if (NULL == ctx) { + return; + } + + FREE(ctx); + printf("http_decoder_test_exit OK!\n"); +}
\ No newline at end of file diff --git a/test/http_decoder/http_pcap/http_simple.pcap b/test/http_decoder/http_pcap/http_simple.pcap Binary files differnew file mode 100644 index 0000000..a4b6bea --- /dev/null +++ b/test/http_decoder/http_pcap/http_simple.pcap diff --git a/test/http_decoder/http_pcap/simple_http.pcap b/test/http_decoder/http_pcap/simple_http.pcap Binary files differnew file mode 100644 index 0000000..a4b6bea --- /dev/null +++ b/test/http_decoder/http_pcap/simple_http.pcap diff --git a/test/http_decoder/test_env/conflist.inf b/test/http_decoder/test_env/conflist.inf new file mode 100644 index 0000000..2e8144d --- /dev/null +++ b/test/http_decoder/test_env/conflist.inf @@ -0,0 +1,9 @@ +[platform] +./plug/stellar_on_sapp/start_loader.inf + + +[protocol] + + +[business] +#./plug/stellar_on_sapp/defer_loader.inf diff --git a/test/http_decoder/test_env/sapp4.el8.x86_64.rpm b/test/http_decoder/test_env/sapp4.el8.x86_64.rpm Binary files differnew file mode 100644 index 0000000..e43fe2f --- /dev/null +++ b/test/http_decoder/test_env/sapp4.el8.x86_64.rpm diff --git a/test/http_decoder/test_env/spec.toml b/test/http_decoder/test_env/spec.toml new file mode 100644 index 0000000..0bfa214 --- /dev/null +++ b/test/http_decoder/test_env/spec.toml @@ -0,0 +1,11 @@ +# stellar_plugin.toml +# +[[plugin]] +path = "./stellar_plugin/http_decoder.so" +init = "http_decoder_init" +exit = "http_decoder_exit" + +[[plugin]] +path = "./stellar_plugin/http_decoder_test_plug.so" +init = "http_decoder_test_init" +exit = "http_decoder_test_exit" diff --git a/test/http_decoder/test_env/start_loader.inf b/test/http_decoder/test_env/start_loader.inf new file mode 100644 index 0000000..89b2f94 --- /dev/null +++ b/test/http_decoder/test_env/start_loader.inf @@ -0,0 +1,17 @@ +[PLUGINFO] +PLUGNAME=stellar_start_loader +SO_PATH=./plug/stellar_on_sapp/stellar_on_sapp.so +INIT_FUNC=STELLAR_START_LOADER_INIT +DESTROY_FUNC=STELLAR_START_LOADER_EXIT + +#[TCP_ALL] +#FUNC_FLAG=ALL +#FUNC_NAME=stellar_on_sapp_tcpall_entry + +[TCP] +FUNC_FLAG=ALL +FUNC_NAME=stellar_on_sapp_tcp_entry + +[UDP] +FUNC_FLAG=ALL +FUNC_NAME=stellar_on_sapp_udp_entry
\ No newline at end of file diff --git a/test/http_decoder/test_env/tsg_l7_protocol.conf b/test/http_decoder/test_env/tsg_l7_protocol.conf new file mode 100644 index 0000000..1075a8f --- /dev/null +++ b/test/http_decoder/test_env/tsg_l7_protocol.conf @@ -0,0 +1,57 @@ +#TYPE:1:UCHAR,2:USHORT,3:USTRING,4:ULOG,5:USTRING,6:FILE,7:UBASE64,8:PACKET +#TYPE FIELD VALUE +STRING UNCATEGORIZED 8000 +#STRING UNCATEGORIZED 8001 +#STRING UNKNOWN_OTHER 8002 +STRING DNS 32 +STRING FTP 45 +STRING FTPS 751 +STRING HTTP 67 +STRING HTTPS 68 +STRING ICMP 70 +STRING IKE 8003 +STRING MAIL 8004 +STRING IMAP 75 +STRING IMAPS 76 +STRING IPSEC 85 +STRING XMPP 94 +STRING L2TP 98 +STRING NTP 137 +STRING POP3 147 +STRING POP3S 148 +STRING PPTP 153 +STRING QUIC 2521 +STRING SIP 182 +STRING SMB 185 +STRING SMTP 186 +STRING SMTPS 187 +STRING SPDY 1469 +STRING SSH 198 +STRING SSL 199 +STRING SOCKS 8005 +STRING TELNET 209 +STRING DHCP 29 +STRING RADIUS 158 +STRING OPENVPN 336 +STRING STUN 201 +STRING TEREDO 555 +STRING DTLS 1291 +STRING DoH 8006 +STRING ISAKMP 92 +STRING MDNS 3835 +STRING NETBIOS 129 +STRING NETFLOW 130 +STRING RDP 150 +STRING RTCP 174 +STRING RTP 175 +STRING SLP 8007 +STRING SNMP 190 +STRING SSDP 197 +STRING TFTP 211 +STRING BJNP 2481 +STRING LDAP 100 +STRING RTMP 337 +STRING RTSP 176 +STRING ESNI 8008 +STRING QQ 156 +STRING WeChat 1296 diff --git a/test/http_decoder/test_result_json/empty_array.json b/test/http_decoder/test_result_json/empty_array.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/test/http_decoder/test_result_json/empty_array.json @@ -0,0 +1 @@ +[]
\ No newline at end of file diff --git a/test/http_decoder/test_result_json/http_simple_result.json b/test/http_decoder/test_result_json/http_simple_result.json new file mode 100644 index 0000000..988f0b7 --- /dev/null +++ b/test/http_decoder/test_result_json/http_simple_result.json @@ -0,0 +1,28 @@ +[ + { + "Tuple4": "192.168.38.73.50806>192.168.40.137.80", + "method": "GET", + "uri": "/index.html", + "req_version": "1.1", + "major_version": 1, + "minor_version": 1, + "Host": "192.168.40.137", + "User-Agent": "curl/7.79.1", + "Accept": "*/*", + "name": "HTTP_DECODER_RESULT_1" + }, + { + "Tuple4": "192.168.38.73.50806>192.168.40.137.80", + "res_version": "1.0", + "res_status": "OK", + "major_version": 1, + "minor_version": 0, + "status_code": 200, + "Server": "SimpleHTTP/0.6 Python/2.7.5", + "Date": "Thu, 30 Nov 2023 08:42:24 GMT", + "Content-type": "text/html", + "Content-Length": "144", + "Last-Modified": "Thu, 30 Nov 2023 08:38:54 GMT", + "name": "HTTP_DECODER_RESULT_2" + } +] diff --git a/test/http_decoder/test_result_json/proto_identify_http.json b/test/http_decoder/test_result_json/proto_identify_http.json new file mode 100644 index 0000000..757d9e2 --- /dev/null +++ b/test/http_decoder/test_result_json/proto_identify_http.json @@ -0,0 +1,10 @@ +[ + { + "Tuple4": "192.168.38.73.50806>192.168.40.137.80", + "STREAM_TYPE": "TCP", + "l7_label_id": [32], + "l7_label_name": ["HTTP"], + "STREAM_DIR": "C2S", + "name": "APP_PROTO_IDENTIFY_RESULT_1" + } +] diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index e373899..045e36f 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -1,5 +1,7 @@ include(ExternalProject) +set(VENDOR_BUILD ${CMAKE_BINARY_DIR}/vendor/vbuild) + # GoogleTest ExternalProject_Add(googletest PREFIX googletest URL ${CMAKE_CURRENT_SOURCE_DIR}/googletest-release-1.8.0.tar.gz @@ -19,3 +21,16 @@ add_library(gmock STATIC IMPORTED GLOBAL) add_dependencies(gmock googletest) set_property(TARGET gmock PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgmock.a) set_property(TARGET gmock PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + +#llhttp-9.1.2 +ExternalProject_Add(llhttp PREFIX llhttp + URL ${CMAKE_CURRENT_SOURCE_DIR}/llhttp-release-v9.1.3.tar.gz + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${VENDOR_BUILD} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS="-fPIC") + +file(MAKE_DIRECTORY ${VENDOR_BUILD}/include) + +add_library(llhttp-static STATIC IMPORTED GLOBAL) +add_dependencies(llhttp-static llhttp) + +set_property(TARGET llhttp-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${VENDOR_BUILD}/include) +set_property(TARGET llhttp-static PROPERTY IMPORTED_LOCATION ${VENDOR_BUILD}/lib64/libllhttp.a)
\ No newline at end of file diff --git a/vendor/llhttp-release-v9.1.3.tar.gz b/vendor/llhttp-release-v9.1.3.tar.gz Binary files differnew file mode 100644 index 0000000..c83dbd0 --- /dev/null +++ b/vendor/llhttp-release-v9.1.3.tar.gz |
