diff --git a/ci/travis.sh b/ci/travis.sh index 972e605..f48a0e4 100644 --- a/ci/travis.sh +++ b/ci/travis.sh @@ -34,7 +34,7 @@ env | sort # Install dependency from YUM yum install -y mrzcpd numactl-devel zlib-devel librdkafka-devel systemd-devel -yum install -y libcjson-devel libmaatframe-devel libMESA_field_stat2-devel libMESA_handle_logger-devel +yum install -y libcjson-devel libmaatframe-devel libMESA_field_stat2-devel libMESA_handle_logger-devel libtsglua-devel yum install -y libMESA_htable-devel libMESA_prof_load-devel librulescan-devel libwiredcfg-devel libWiredLB-devel sapp-devel libbreakpad_mini-devel yum install -y libasan diff --git a/plugin/business/pangu-http/CMakeLists.txt b/plugin/business/pangu-http/CMakeLists.txt index ea99523..f7a2d59 100644 --- a/plugin/business/pangu-http/CMakeLists.txt +++ b/plugin/business/pangu-http/CMakeLists.txt @@ -1,7 +1,7 @@ -add_library(pangu-http src/pangu_logger.cpp src/pangu_http.cpp src/pattern_replace.cpp src/pangu_web_cache.cpp src/edit_element.cpp) +add_library(pangu-http src/pangu_logger.cpp src/pangu_http.cpp src/pattern_replace.cpp src/pangu_web_cache.cpp src/edit_element.cpp src/http_lua.cpp) target_link_libraries(pangu-http PUBLIC common http tango-cache-client) target_link_libraries(pangu-http PUBLIC rdkafka ctemplate-static cjson pcre2-static ratelimiter-static libdablooms pthread) -target_link_libraries(pangu-http PUBLIC maatframe) +target_link_libraries(pangu-http PUBLIC maatframe tsglua) target_link_libraries(pangu-http PUBLIC libxml2-static z) add_executable(test_pattern_replace src/test_pattern_replace.cpp src/pattern_replace.cpp) @@ -11,5 +11,8 @@ file(COPY test_data DESTINATION ./) add_executable(test_edit_element src/test_edit_element.cpp src/edit_element.cpp) target_link_libraries(test_edit_element common gtest pcre2-static libxml2-static z) +add_executable(test_http_lua src/test_http_lua.cpp src/http_lua.cpp) +target_link_libraries(test_http_lua common gtest tsglua z) + add_executable(replace_tool src/replace_tool.cpp src/pattern_replace.cpp) target_link_libraries(replace_tool common pcre2-static) diff --git a/plugin/business/pangu-http/src/http_lua.cpp b/plugin/business/pangu-http/src/http_lua.cpp new file mode 100644 index 0000000..6b87d57 --- /dev/null +++ b/plugin/business/pangu-http/src/http_lua.cpp @@ -0,0 +1,713 @@ +#include "pattern_replace.h" +#include "http_lua.h" + +#include +#include + +#include +#include +#include +#include +#include + +static const char __attribute__((__unused__))*http_lua_log_get_url(struct tsg_script_ctx *tsg_ctx) +{ + enum tfe_http_event events = tsg_ctx->events; + if(events < EV_HTTP_REQ_HDR) + { + return NULL; + } + + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return NULL; + } + struct tfe_http_half * in_req_half = session->req; + if(in_req_half == NULL) + return NULL; + struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; + if(in_req_spec == NULL) + return NULL; + + if (in_req_spec->url != NULL) + { + return in_req_spec->url; + } + return NULL; +} + +static int http_lua_log_debug(lua_State *L) +{ + int out_lua_argc=0, i=0; + lua_arg_t *out_lua_argv=NULL; + + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc < 1 || out_lua_argv == NULL) + { + return 0; + } + + char buff[TFE_STRING_MAX]={0}, *p = NULL; + p = buff; + for(i=0; ilocal_logger, "policy_id:%d, profile_id:%d, message:%20s", tsg_ctx->config_id, tsg_ctx->profile_id, buff); + + free_param_form_lua(out_lua_argc, out_lua_argv); + return 1; +} + +static int http_lua_log_info(lua_State *L) +{ + int out_lua_argc=0, i=0; + lua_arg_t *out_lua_argv=NULL; + + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc < 1 || out_lua_argv == NULL) + { + return 0; + } + + char buff[TFE_STRING_MAX]={0}, *p = NULL; + p = buff; + for(i=0; ilocal_logger, "policy_id:%d, profile_id:%d, message:%s", tsg_ctx->config_id, tsg_ctx->profile_id, buff); + + free_param_form_lua(out_lua_argc, out_lua_argv); + return 1; +} + +static int http_lua_log_error(lua_State *L) +{ + int out_lua_argc=0, i=0; + lua_arg_t *out_lua_argv=NULL; + + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc < 1 || out_lua_argv == NULL) + { + return 0; + } + + char buff[TFE_STRING_MAX]={0}, *p = NULL; + p = buff; + for(i=0; ilocal_logger, "policy_id:%d, profile_id:%d, message:%s", tsg_ctx->config_id, tsg_ctx->profile_id, buff); + + free_param_form_lua(out_lua_argc, out_lua_argv); + return 1; +} + +static int http_lua_get_method(lua_State *L) +{ + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + if(tfe_http_in_response(events)) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + + struct tfe_http_half * in_req_half = session->req; + struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; + + const char *method_str = http_std_method_to_string(in_req_spec->method); + if(method_str != NULL) + { + c_push_string_into_lua(L, method_str, strlen(method_str)); + } + + return 1; +} + +static int http_lua_get_uri(lua_State *L) +{ + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + if(tfe_http_in_response(events) || !tsg_ctx->http_req_uri) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + + struct tfe_http_half * in_req_half = session->req; + struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; + if (in_req_spec->uri != NULL) + { + c_push_string_into_lua(L, in_req_spec->uri, strlen(in_req_spec->uri)); + } + + return 1; +} + +static int http_lua_set_uri(lua_State *L) +{ + int out_lua_argc = 0; + lua_arg_t *out_lua_argv = NULL; + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc != 1 || out_lua_argv == NULL) + { + return 0; + } + + char * rewrite_uri = out_lua_argv[0].str; + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + if(tfe_http_in_response(events) || !tsg_ctx->http_req_uri) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + + struct tfe_http_half * in_req_half = session->req; + struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; + if (in_req_spec->uri != NULL) + { + tsg_ctx->execut_lua_sucess=1; + in_req_spec->uri = tfe_strdup(rewrite_uri); + } + free_param_form_lua(out_lua_argc, out_lua_argv); + + return 1; +} + +static int http_lua_get_status_code(lua_State *L) +{ + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + if(tfe_http_in_request(events)) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + struct tfe_http_half * in_resp_half = session->resp; + struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; + + if (in_resp_spec != NULL) + { + c_push_num_into_lua(L, in_resp_spec->resp_code); + } + + return 1; +} + +static int http_lua_set_status_code(lua_State *L) +{ + int out_lua_argc = 0; + lua_arg_t *out_lua_argv = NULL; + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc != 1 || out_lua_argv == NULL) + { + return 0; + } + + int lua_resp_code = out_lua_argv[0].num; + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + if(tfe_http_in_request(events)) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + + struct tfe_http_half * in_resp_half = session->resp; + struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; + + if(lua_resp_code != 0) + { + in_resp_spec->resp_code = lua_resp_code; + } + free_param_form_lua(out_lua_argc, out_lua_argv); + + return 1; +} + +static int http_lua_exit(lua_State *L) +{ + int out_lua_argc = 0; + lua_arg_t *out_lua_argv = NULL; + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc != 1 || out_lua_argv == NULL) + { + return 0; + } + + int exit_code = out_lua_argv[0].num; + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + if(exit_code == 0) + { + tsg_ctx->events = (enum tfe_http_event )0; + return 0; + } + + return 1; +} + +static int http_lua_get_current_stage(lua_State *L) +{ + const char * stage_name[] = {"http_req_uri", "http_req_header","http_req_body","http_resp_header","http_resp_body","http_stage_test"}; + + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + + //For test_http_lua + if(tsg_ctx->http_req_uri==2) + { + c_push_string_into_lua(L, stage_name[5], strlen(stage_name[5])); + return 1; + } + + if(events & EV_HTTP_REQ_HDR) + { + if(tsg_ctx->http_req_uri) + { + c_push_string_into_lua(L, stage_name[0], strlen(stage_name[0])); + } + else + { + c_push_string_into_lua(L, stage_name[1], strlen(stage_name[1])); + } + } + + if((events & EV_HTTP_REQ_BODY_BEGIN) | (events & EV_HTTP_REQ_BODY_END) | (events & EV_HTTP_REQ_BODY_CONT)) + { + c_push_string_into_lua(L, stage_name[2], strlen(stage_name[2])); + } + + if(events & EV_HTTP_RESP_HDR) + { + c_push_string_into_lua(L, stage_name[3], strlen(stage_name[3])); + } + + if((events & EV_HTTP_RESP_BODY_BEGIN) | (events & EV_HTTP_RESP_BODY_CONT) | (events & EV_HTTP_RESP_BODY_END)) + { + c_push_string_into_lua(L, stage_name[4], strlen(stage_name[4])); + } + + return 1; +} + +static int http_lua_get_headers(lua_State *L) +{ + int i=0; + + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + + struct tfe_http_half * in_req_half = session->req; + struct tfe_http_half * in_resp_half = session->resp; + + struct tfe_http_half * in_half = tfe_http_in_request(events) ? in_req_half : in_resp_half; + if(in_half == NULL) + { + return 0; + } + + struct http_field_name in_header_field{}; + const char * in_header_value = NULL; + void * iterator = NULL; + + const char *in_field_name[256], *in_field_value[256]; + + while (true) + { + if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) + { + break; + } + + in_field_name[i] = http_field_name_to_string(&in_header_field); + in_field_value[i] = in_header_value; + i++; + } + + c_push_table_into_lua(L, in_field_name, in_field_value, i); + + return 1; +} + +static int http_lua_set_headers(lua_State *L) +{ + int actually_write=0; + + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + const struct tfe_http_session * session = tsg_ctx->session; + if(session == NULL) + { + return 0; + } + enum tfe_http_event events = tsg_ctx->events; + + struct tfe_http_half * in_req_half = session->req; + struct tfe_http_half * in_resp_half = session->resp; + + struct tfe_http_half * in_half = tfe_http_in_request(events) ? in_req_half : in_resp_half; + if(in_half == NULL) + { + return 0; + } + + struct http_field_name in_header_field{}; + const char * in_header_value = NULL; + void * iterator = NULL; + + int out_lua_argc = 0; + lua_arg_t *out_lua_argv = NULL; + + const char *in_field_name; + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + if(out_lua_argc != 2 || out_lua_argv == NULL) + { + return 0; + } + + char *field_name=out_lua_argv[0].str, *field_value=out_lua_argv[1].str; + + if(field_name == NULL || field_value == NULL) + { + return 0; + } + + while (true) + { + if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) + { + break; + } + in_field_name = http_field_name_to_string(&in_header_field); + if(strcasecmp(in_field_name, field_name)==0 && strcasecmp(field_value, "nil")!=0) + { + if(in_header_field.field_id == TFE_HTTP_UNKNOWN_FIELD) + { + continue; + } + tfe_http_std_field_write(in_half, in_header_field.field_id, NULL); + tfe_http_std_field_write(in_half, in_header_field.field_id, field_value); + actually_write=1; + break; + } + + if(strcasecmp(http_field_name_to_string(&in_header_field), field_name)==0 && strcasecmp(field_value, "nil")==0) + { + if(in_header_field.field_id == TFE_HTTP_UNKNOWN_FIELD) + { + continue; + } + tfe_http_std_field_write(in_half, in_header_field.field_id, NULL); + actually_write=1; + break; + } + } + + if(actually_write ==1) + { + tsg_ctx->execut_lua_sucess=1; + } + + if(actually_write!=1 && strcasecmp(field_value, "nil")!=0) + { + tfe_http_nonstd_field_write(in_half, field_name, field_value); + tsg_ctx->execut_lua_sucess=1; + } + + free_param_form_lua(out_lua_argc, out_lua_argv); + return 0; +} + +static int http_lua_get_body(lua_State *L) +{ + struct tsg_script_ctx *tsg_ctx = (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + + if(tsg_ctx->http_body == NULL) + { + TFE_LOG_ERROR(tsg_ctx->local_logger, "policy_id:%d, profile_id:%d, message:%s", tsg_ctx->config_id, tsg_ctx->profile_id, "Can't to get req/resp body data"); + return 0; + } + + char * __http_body = (char *) evbuffer_pullup(tsg_ctx->http_body, -1); + size_t __http_body_len = evbuffer_get_length(tsg_ctx->http_body); + + c_push_string_into_lua(L, __http_body, __http_body_len); + + return 1; +} + +static int http_lua_set_body(lua_State *L) +{ + int i=0; + struct tsg_script_ctx *tsg_ctx= (struct tsg_script_ctx *)lua_get_userdata(L); + if(tsg_ctx == NULL) + { + return 0; + } + + int out_lua_argc = 0; + lua_arg_t *out_lua_argv = NULL; + + c_pull_param_from_lua(L, &out_lua_argc, &out_lua_argv); + + if(out_lua_argc < 1 || out_lua_argv == NULL) + { + return 0; + } + + tsg_ctx->http_lua_body = evbuffer_new(); + for(i=0; ihttp_lua_body, in, in_sz); + } + free_param_form_lua(out_lua_argc, out_lua_argv); + + return 0; +} + +lua_script_context http_lua_ctx_new(struct tsg_lua_script *lua_script, unsigned int thread_id) +{ + return lua_script_context_malloc(lua_script->http_lua_handle[thread_id]); +} + +void http_lua_ctx_free(struct tsg_lua_script *lua_script, unsigned int thread_id, lua_script_context lua_ctx) +{ + if(lua_ctx) + lua_script_context_free(lua_script->http_lua_handle[thread_id], lua_ctx); +} + +int http_lua_map_cache_script(tsg_lua_handle lua_handle, const char *profile_msg, size_t msg_len) +{ + return tsg_lua_cache_script(lua_handle, profile_msg, msg_len); +} + +void http_lua_inject_http_consts(tsg_lua_handle L) +{ + lua_register_function(L, NULL, "get_current_stage", http_lua_get_current_stage); + lua_register_function(L, NULL, "log_debug", http_lua_log_debug); + lua_register_function(L, NULL, "log_info", http_lua_log_info); + lua_register_function(L, NULL, "log_error", http_lua_log_error); + lua_register_function(L, NULL, "exit", http_lua_exit); +} + +void http_lua_inject_req_header_api(tsg_lua_handle L) +{ + lua_register_function(L, "req", "get_method", http_lua_get_method); + lua_register_function(L, "req", "get_uri", http_lua_get_uri); + lua_register_function(L, "req", "set_uri", http_lua_set_uri); + lua_register_function(L, "req", "get_headers", http_lua_get_headers); + lua_register_function(L, "req", "set_header", http_lua_set_headers); +} + +void http_lua_inject_req_body_api(tsg_lua_handle L) +{ + lua_register_function(L, "req", "get_body_data", http_lua_get_body); + lua_register_function(L, "req", "set_body_data", http_lua_set_body); +} + +void http_lua_inject_resp_header_api(tsg_lua_handle L) +{ + lua_register_function(L, "resp", "get_status_code", http_lua_get_status_code); + lua_register_function(L, "resp", "set_status_code", http_lua_set_status_code); + + lua_register_function(L, "resp", "get_headers", http_lua_get_headers); + lua_register_function(L, "resp", "set_header", http_lua_set_headers); +} + +void http_lua_inject_resp_body_api(tsg_lua_handle L) +{ + lua_register_function(L, "resp", "get_body_data", http_lua_get_body); + lua_register_function(L, "resp", "set_body_data", http_lua_set_body); +} + +void http_lua_inject_api(tsg_lua_handle L) +{ + http_lua_inject_http_consts(L); + http_lua_inject_req_header_api(L); + http_lua_inject_req_body_api(L); + http_lua_inject_resp_header_api(L); + http_lua_inject_resp_body_api(L); +} + +tsg_lua_handle *http_lua_handle_create(int thread_num, const char *name_space) +{ + int id=0; + tsg_lua_handle *http_lua_handle = NULL; + + http_lua_handle = (tsg_lua_handle *)ALLOC(tsg_lua_handle, thread_num); + if(http_lua_handle == NULL) + { + return NULL; + } + + for(id=0; id < thread_num; id++) + { + http_lua_handle[id] = tsg_lua_vm_create_with_name(name_space); + if(http_lua_handle[id] == NULL) + { + return NULL; + } + http_lua_inject_api(http_lua_handle[id]); + } + + return http_lua_handle; +} + +size_t execute_lua_script_rule(struct tsg_lua_script *lua_script, int profile_id, lua_script_context lua_ctx, unsigned int thread_id, void *user_data) +{ + int ret=0, timeout=0; + int *lua_script_id=NULL; + char *profile_msg; size_t msg_len; + + ret=lua_script->http_lua_profile(profile_id, &profile_msg, &msg_len, &lua_script_id, &timeout); + if(ret<0) + { + return ret; + } + + lua_data_t in; in.data = (char *)"tfe"; in.len = strlen(in.data); + lua_arg_t out; out.type = STRING; out.len = 1024; out.str = (char *)malloc(10); + + lua_data_t tsg_script_data; + tsg_script_data.data=profile_msg; + tsg_script_data.len=msg_len; + + if(lua_script->lua_is_cache==1) + { + ret=lua_cache_exec(lua_script->http_lua_handle[thread_id], lua_script_id[thread_id], in, user_data, lua_ctx, timeout, &out); + } + else + { + + ret=lua_exec(lua_script->http_lua_handle[thread_id], tsg_script_data, in, user_data, lua_ctx, timeout, &out); + } + + FREE(&out.str); + FREE(&profile_msg); + + return ret; +} + diff --git a/plugin/business/pangu-http/src/http_lua.h b/plugin/business/pangu-http/src/http_lua.h new file mode 100644 index 0000000..b00e600 --- /dev/null +++ b/plugin/business/pangu-http/src/http_lua.h @@ -0,0 +1,39 @@ +#pragma once +#include + +#include + +#include "pattern_replace.h" +#include +#include + +struct tsg_lua_script +{ + int lua_is_cache; + tsg_lua_handle *http_lua_handle; + int (*http_lua_profile)(int profile_id, char **profile_msg, size_t *msg_len, int **script_id, int *timeout); +}; + +struct tsg_script_ctx +{ + int config_id; + int profile_id; + int http_req_uri; + int execut_lua_sucess; + lua_script_context lua_ctx; + enum tfe_http_event events; + void * local_logger; + const struct tfe_http_session *session; + struct tfe_http_half *replacing; + struct evbuffer *http_body; + struct evbuffer *http_lua_body; + int actually_executed; +}; + +lua_script_context http_lua_ctx_new(struct tsg_lua_script *lua_script, unsigned int thread_id); +void http_lua_ctx_free(struct tsg_lua_script *lua_script, unsigned int thread_id, lua_script_context lua_ctx); + +size_t execute_lua_script_rule(struct tsg_lua_script *lua_script, int profile_id, lua_script_context lua_ctx, unsigned int thread_id, void *user_data); +int http_lua_map_cache_script(tsg_lua_handle lua_handle, const char *profile_msg, size_t msg_len); +tsg_lua_handle *http_lua_handle_create(int thread_num, const char *name_space); + diff --git a/plugin/business/pangu-http/src/pangu_http.cpp b/plugin/business/pangu-http/src/pangu_http.cpp index e472f69..8fac17a 100644 --- a/plugin/business/pangu-http/src/pangu_http.cpp +++ b/plugin/business/pangu-http/src/pangu_http.cpp @@ -1,6 +1,7 @@ #include "pangu_logger.h" #include "edit_element.h" #include "pattern_replace.h" +#include "http_lua.h" #include "pangu_web_cache.h" #include @@ -55,6 +56,7 @@ enum manipulate_action MA_ACTION_HIJACK, MA_ACTION_INSERT, MA_ACTION_ELEMENT, + MA_ACTION_LUA_SCRIPT, __MA_ACTION_MAX }; @@ -84,6 +86,7 @@ enum pangu_http_stat STAT_ACTION_INSERT, STAT_ACTION_INSERT_SZ, STAT_ACTION_EDIT_ELEMENT, + STAT_ACTION_RUN_SCRIPT, STAT_ACTION_WHITELSIT, STAT_SUSPENDING, __PG_STAT_MAX @@ -94,6 +97,7 @@ enum manipulate_profile_table POLICY_PROFLIE_TABLE_REJECT, POLICY_PROFILE_TABLE_INSERT, POLICY_PROFILE_TABLE_HIJACK, + POLICY_PROFILE_TABLE_LUA, POLICY_PROFILE_TABLE_MAX }; @@ -106,6 +110,8 @@ struct manipulate_profile char *profile_msg; char *profile_type; char *profile_position; + int *script_id; + int timeout; ctemplate::Template * tpl; pthread_mutex_t lock; }; @@ -153,6 +159,7 @@ struct pangu_rt struct event_base* gc_evbase; struct event* gcev; + struct tsg_lua_script lua_script; Ratelimiter_handle_t ratelimiter; int enable_rate; @@ -189,6 +196,7 @@ static void pangu_http_stat_init(struct pangu_rt * pangu_runtime) spec[STAT_ACTION_INSERT]="intcp_ins_num"; spec[STAT_ACTION_INSERT_SZ]="ins_bytes"; spec[STAT_ACTION_EDIT_ELEMENT]="intcp_edit_elem_num"; + spec[STAT_ACTION_RUN_SCRIPT]="intcp_rus_num"; spec[STAT_ACTION_WHITELSIT]="intcp_allow_num"; spec[STAT_SUSPENDING]="suspending"; @@ -317,6 +325,7 @@ static enum manipulate_action manipulate_action_str2idx(const char *action_str) clue_action_map[MA_ACTION_HIJACK]= "hijack"; clue_action_map[MA_ACTION_INSERT]= "insert"; clue_action_map[MA_ACTION_ELEMENT] = "edit_element"; + clue_action_map[MA_ACTION_LUA_SCRIPT] = "run_script"; size_t i = 0; @@ -517,6 +526,21 @@ void policy_action_param_new(int idx, const struct Maat_rule_t* rule, const char } param->e_rule = rule_id; break; + case MA_ACTION_LUA_SCRIPT: + item=cJSON_GetObjectItem(json,"run_script_profile"); + if(item && item->type==cJSON_Number){ + param->profile_id = item->valueint; + } + item=cJSON_GetObjectItem(json,"enforcement_ratio"); + if(item && item->type==cJSON_Number) + { + param->enforcement_ratio = item->valuedouble; + } + else + { + param->enforcement_ratio = 1; + } + break; default: assert(0); break; } @@ -699,6 +723,52 @@ void ma_hijack_profile_table_new_cb(int table_id, const char* key, const char* t return; } +void ma_lua_profile_table_new_cb(int table_id, const char* key, const char* table_line, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp) +{ + int timeout=0; + int ret=0, profile_id=0, is_valid=0; + char profile_name[128]={0}, profile_path[TFE_PATH_MAX]={0}; + + ret=sscanf(table_line, "%d\t%s\t%d\t%d", &profile_id, profile_path, &timeout, &is_valid); + if(ret!=4) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Policy table parse config failed: %s", table_line); + return; + } + struct manipulate_profile* ply_profile=ALLOC(struct manipulate_profile, 1); + ply_profile->ref_cnt=1; + pthread_mutex_init(&(ply_profile->lock), NULL); + + ply_profile->profile_id=profile_id; + ply_profile->profile_name=tfe_strdup(profile_path); + ply_profile->profile_msg = tfe_read_file(profile_path, &ply_profile->msg_len); + ply_profile->timeout=timeout; + if (ply_profile->profile_msg == NULL) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Read file failed %d:%s:%s", profile_id, profile_name, profile_path); + *ad = ply_profile; + return; + } + + int i=0, thread_num = g_pangu_rt->thread_num; + struct tsg_lua_script *lua_script = &(g_pangu_rt->lua_script); + + if(lua_script->lua_is_cache==1) + { + ply_profile->script_id = ALLOC(int, thread_num); + + for(i=0; iscript_id[i]=http_lua_map_cache_script(lua_script->http_lua_handle[i], ply_profile->profile_msg, ply_profile->msg_len); + } + } + + TFE_LOG_INFO(g_pangu_rt->local_logger, "Policy table add success %d", profile_id); + + *ad = ply_profile; + return; +} + void ma_profile_table_free_cb(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void *argp) { if(*ad==NULL) @@ -716,8 +786,15 @@ void ma_profile_table_free_cb(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, pthread_mutex_unlock(&(ply_obj->lock)); pthread_mutex_destroy(&(ply_obj->lock)); - FREE(&ply_obj->profile_type); - FREE(&ply_obj->profile_msg); + if(ply_obj->profile_type) + FREE(&ply_obj->profile_type); + + if(ply_obj->profile_msg) + FREE(&ply_obj->profile_msg); + + if(ply_obj->script_id) + FREE(&ply_obj->script_id); + FREE(&ply_obj->profile_name); if (ply_obj->profile_position) FREE(&ply_obj->profile_position); @@ -759,7 +836,8 @@ const char* table_name_idx2str(int profile_idx) { const char *table_name_map[] = {"TSG_PROFILE_RESPONSE_PAGES", "PXY_PROFILE_INSERT_SCRIPTS", - "PXY_PROFILE_HIJACK_FILES"}; + "PXY_PROFILE_HIJACK_FILES", + "PXY_PROFILE_RUN_SCRIPTS"}; return table_name_map[profile_idx]; } @@ -775,6 +853,7 @@ int maat_table_ex_init(int profile_idx, [POLICY_PROFLIE_TABLE_REJECT] = ma_profile_table_new_cb, [POLICY_PROFILE_TABLE_INSERT] = ma_insert_profile_table_new_cb, [POLICY_PROFILE_TABLE_HIJACK] = ma_hijack_profile_table_new_cb, + [POLICY_PROFILE_TABLE_LUA] = ma_lua_profile_table_new_cb, }; table_id=g_pangu_rt->plolicy_table_id[profile_idx]=Maat_table_register(g_pangu_rt->maat, table_name); @@ -843,7 +922,7 @@ int pangu_policy_init(const char* profile_path, const char* static_section, cons goto error_out; } - for(int i = 0; i <= POLICY_PROFILE_TABLE_HIJACK; i++) + for(int i = 0; i <= POLICY_PROFILE_TABLE_LUA; i++) { ret = maat_table_ex_init(i, ma_profile_table_free_cb, ma_profile_table_dup_cb); if(ret<0) @@ -934,6 +1013,13 @@ int pangu_http_init(struct tfe_proxy * proxy) g_pangu_rt->ratelimiter=ratelimit_handle_create(profile_path, "ratelimit"); pangu_http_stat_init(g_pangu_rt); + + g_pangu_rt->lua_script.http_lua_handle=http_lua_handle_create(g_pangu_rt->thread_num, "tfe"); + if(g_pangu_rt->lua_script.http_lua_handle==NULL) + { + goto error_out; + } + if(pangu_policy_init(profile_path, "MAAT", "DYNAMIC_MAAT")<0) { goto error_out; @@ -1030,6 +1116,7 @@ struct pangu_http_ctx struct replace_ctx * rep_ctx; struct insert_ctx * ins_ctx; struct edit_element_ctx * edit_ctx; + struct tsg_script_ctx *tsg_ctx; struct ip_data_ctx ip_ctx; int (* resumed_cb)(const struct tfe_stream * stream, @@ -1048,7 +1135,6 @@ struct pangu_http_ctx int thread_id; }; - void http_repl_ctx_free(struct replace_ctx* rep_ctx) { if (rep_ctx->http_body) @@ -1088,6 +1174,23 @@ void http_element_ctx_free(struct edit_element_ctx *edit_ctx) return; } +void http_tsg_ctx_free(struct tsg_script_ctx *tsg_ctx, int thread_id) +{ + if (tsg_ctx->http_body) + { + evbuffer_free(tsg_ctx->http_body); + tsg_ctx->http_body = NULL; + } + if (tsg_ctx->http_lua_body) + { + evbuffer_free(tsg_ctx->http_lua_body); + tsg_ctx->http_lua_body = NULL; + } + http_lua_ctx_free(&g_pangu_rt->lua_script, thread_id, tsg_ctx->lua_ctx); + FREE(&tsg_ctx); + return; +} + void http_ip_ctx_free(struct ip_data_ctx *ip_ctx) { if(ip_ctx->asn_client) @@ -1128,6 +1231,11 @@ static void pangu_http_ctx_free(struct pangu_http_ctx * ctx) http_element_ctx_free(ctx->edit_ctx); ctx->edit_ctx = NULL; } + if(ctx->tsg_ctx) + { + http_tsg_ctx_free(ctx->tsg_ctx, ctx->thread_id); + ctx->tsg_ctx = NULL; + } http_ip_ctx_free(&ctx->ip_ctx); ctx->manipulate_replaced=0; @@ -1403,6 +1511,172 @@ static int http_enforcement_ratio(float enforcement_ratio) return 0; } +int http_lua_profile(int profile_id, char **profile_msg, size_t *msg_len, int **script_id, int *timeout) +{ + int ret = 0; + + struct manipulate_profile* lua_profile=get_profile_by_id(POLICY_PROFILE_TABLE_LUA, profile_id); + if(lua_profile==NULL) + { + ret=-1; + return ret; + } + + *profile_msg = tfe_strdup(lua_profile->profile_msg); + *msg_len = lua_profile->msg_len; + *script_id = lua_profile->script_id; + *timeout=lua_profile->timeout; + + ma_profile_table_free(lua_profile); + lua_profile = NULL; + return ret; +} + +void http_lua(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, + const unsigned char * body_frag, size_t frag_size, struct pangu_http_ctx * ctx) +{ + int ret = 0; + struct tfe_http_session * to_write_sess = NULL; + + struct tsg_lua_script *lua_script=&g_pangu_rt->lua_script; + lua_script->http_lua_profile=http_lua_profile; + + to_write_sess = tfe_http_session_allow_write(session); + if (to_write_sess == NULL) //fail to wirte, abandon. + { + TFE_STREAM_LOG_INFO(stream, "tfe_http_session_allow_write() %s failed.", session->req->req_spec.uri); + ctx->action = PG_ACTION_NONE; + tfe_http_session_detach(session); return; + } + + struct tsg_script_ctx *tsg_ctx = ctx->tsg_ctx; + if (ctx->tsg_ctx == NULL) + { + if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) + { + struct policy_action_param *param = ctx->param; + ctx->tsg_ctx = tsg_ctx = ALLOC(struct tsg_script_ctx, 1); + tsg_ctx->profile_id = param->profile_id; + tsg_ctx->lua_ctx = http_lua_ctx_new(lua_script, ctx->thread_id); + } + else + { + TFE_STREAM_LOG_INFO(stream, "Can only setup replace on REQ/RESP headers, detached."); + ctx->action = PG_ACTION_NONE; + tfe_http_session_detach(session); return; + } + } + tsg_ctx->events = events; + tsg_ctx->session = session; + tsg_ctx->local_logger = g_pangu_rt->local_logger; + tsg_ctx->config_id = ctx->enforce_rules[0].config_id; + + struct tfe_http_half * in_req_half = session->req; + struct tfe_http_half * in_resp_half = session->resp; + struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; + struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; + + if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) + { + if (tfe_http_in_request(events)) + { + tsg_ctx->http_req_uri=1; tsg_ctx->execut_lua_sucess=0; + ret=execute_lua_script_rule(lua_script, tsg_ctx->profile_id, tsg_ctx->lua_ctx, ctx->thread_id, (void *)tsg_ctx); + if(ret>0 && tsg_ctx->execut_lua_sucess==1) + { + tsg_ctx->actually_executed =1; + } + tsg_ctx->http_req_uri=0; + tsg_ctx->replacing = tfe_http_session_request_create(to_write_sess, in_req_spec->method, in_req_spec->uri); + tfe_http_session_request_set(to_write_sess, tsg_ctx->replacing); + } + else + { + tsg_ctx->replacing = tfe_http_session_response_create(to_write_sess, in_resp_spec->resp_code); + tfe_http_session_response_set(to_write_sess, tsg_ctx->replacing); + } + + tsg_ctx->execut_lua_sucess=0; + ret=execute_lua_script_rule(lua_script, tsg_ctx->profile_id, tsg_ctx->lua_ctx, ctx->thread_id, (void *)tsg_ctx); + if(ret>0 && tsg_ctx->actually_executed==1) + { + tsg_ctx->actually_executed =1; + } + + struct tfe_http_half * in_half = tfe_http_in_request(events) ? in_req_half : in_resp_half; + + struct http_field_name in_header_field{}; + const char * in_header_value = NULL; + void * iterator = NULL; + + while (true) + { + if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) + { + break; + } + tfe_http_field_write(tsg_ctx->replacing, &in_header_field, in_header_value); + } + } + + if ((events & EV_HTTP_REQ_BODY_BEGIN) || (events & EV_HTTP_RESP_BODY_BEGIN)) + { + assert(tsg_ctx->http_body == NULL); + tsg_ctx->http_body = evbuffer_new(); + } + + if ((events & EV_HTTP_REQ_BODY_CONT) || (events & EV_HTTP_RESP_BODY_CONT)) + { + evbuffer_add(tsg_ctx->http_body, body_frag, frag_size); + } + + if ((events & EV_HTTP_REQ_BODY_END) || (events & EV_HTTP_RESP_BODY_END)) + { + char * __http_body = (char *) evbuffer_pullup(tsg_ctx->http_body, -1); + size_t __http_body_len = evbuffer_get_length(tsg_ctx->http_body); + + ret=execute_lua_script_rule(lua_script, tsg_ctx->profile_id, tsg_ctx->lua_ctx, ctx->thread_id, (void *)tsg_ctx); + + char * __http_lua_body = NULL; size_t __http_body_lua_len = 0; + if(ret > 0 && tsg_ctx->http_lua_body != NULL) + { + tsg_ctx->actually_executed =1; + __http_lua_body = (char *) evbuffer_pullup(tsg_ctx->http_lua_body, -1); + __http_body_lua_len = evbuffer_get_length(tsg_ctx->http_lua_body); + } + + if (__http_body_lua_len >0) + { + tfe_http_half_append_body(tsg_ctx->replacing, __http_lua_body, __http_body_lua_len, 0); + tsg_ctx->actually_executed=1; + } + else + { + tfe_http_half_append_body(tsg_ctx->replacing, __http_body, __http_body_len, 0); + } + + if (tsg_ctx->http_lua_body != NULL) + { + evbuffer_free(tsg_ctx->http_lua_body); + tsg_ctx->http_lua_body = NULL; + } + + if (tsg_ctx->http_body != NULL) + { + evbuffer_free(tsg_ctx->http_body); + tsg_ctx->http_body = NULL; + } + } + + if ((events & EV_HTTP_REQ_END) || (events & EV_HTTP_RESP_END)) + { + tfe_http_half_append_body(tsg_ctx->replacing, NULL, 0, 0); + tsg_ctx->replacing = NULL; + } + + return; +} + void http_replace(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct pangu_http_ctx * ctx) { @@ -2185,6 +2459,9 @@ static void http_manipulate(const struct tfe_stream * stream, const struct tfe_h case MA_ACTION_ELEMENT: http_element(stream, session, events, body_frag, frag_size, ctx); break; + case MA_ACTION_LUA_SCRIPT: + http_lua(stream, session, events, body_frag, frag_size, ctx); + break; default: assert(0); break; } @@ -2702,6 +2979,21 @@ static inline int ctx_actually_replaced(struct pangu_http_ctx * ctx) } } +static inline int ctx_actually_ran_script(struct pangu_http_ctx * ctx) +{ + + if(ctx->action == PG_ACTION_MANIPULATE && + ctx->param->action == MA_ACTION_LUA_SCRIPT && + ctx->tsg_ctx->actually_executed==1) + { + return 1; + } + else + { + return 0; + } +} + static inline int ctx_actually_inserted(struct pangu_http_ctx * ctx) { @@ -2791,7 +3083,7 @@ void pangu_on_http_end(const struct tfe_stream * stream, if(ctx->action != PG_ACTION_NONE && (((ctx_actually_replaced(ctx)) || (ctx_actually_inserted(ctx)) || (ctx_actually_edited(ctx)) || - (ctx_actually_manipulate(ctx))) || (ctx->action == PG_ACTION_MONIT || + (ctx_actually_manipulate(ctx)) || ctx_actually_ran_script(ctx)) || (ctx->action == PG_ACTION_MONIT || ctx->action == PG_ACTION_REJECT || ctx->action == PG_ACTION_WHITELIST))) { ret=pangu_send_log(g_pangu_rt->send_logger, &log_msg); @@ -2811,6 +3103,11 @@ void pangu_on_http_end(const struct tfe_stream * stream, ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_REPLACE])); } + if(ctx->tsg_ctx && ctx->tsg_ctx->actually_executed==1) + { + ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_RUN_SCRIPT])); + } + TFE_LOG_DEBUG(g_pangu_rt->local_logger, "cache %s %s upload=%d", session->req->req_spec.url, cache_pending_result_string(ctx->pending_result), diff --git a/plugin/business/pangu-http/src/test_http_lua.cpp b/plugin/business/pangu-http/src/test_http_lua.cpp new file mode 100644 index 0000000..56c1d33 --- /dev/null +++ b/plugin/business/pangu-http/src/test_http_lua.cpp @@ -0,0 +1,481 @@ +#include +#include +#include "http_lua.h" + +#include +#include +#include +#include +#include +#include + +bool g_print_to_stderr = true; + +struct lua_http_head_field +{ + TAILQ_ENTRY(lua_http_head_field) next; + char * value; + struct http_field_name *field; +}; + +struct lua_http_headers +{ + TAILQ_HEAD(http_field_list_head, lua_http_head_field) lua_http_field_list; + int nvlen; + uint8_t flag; +}; + +struct def_lua_http_headers +{ + const char *filed_name; + const char *value; + enum tfe_http_std_field field_id; +}; + +struct def_lua_http_headers def_lua_http_head_value[]={{"accept", "text/html", TFE_HTTP_UNKNOWN_FIELD}, + {"accept-encoding", "gzip, deflate, br", TFE_HTTP_UNKNOWN_FIELD}, + {"accept-language", "zh-CN,zh;q=0.9", TFE_HTTP_UNKNOWN_FIELD}, + {"pragma", "no-cache", TFE_HTTP_PRAGMA}, + {"user-agent", "Mozilla/5.0", TFE_HTTP_USER_AGENT}, + {"cache-control", "max-age=3600", TFE_HTTP_CACHE_CONTROL}, + {"content-encoding", "gzip", TFE_HTTP_CONT_ENCODING}, + {"content-type", "text/html", TFE_HTTP_CONT_TYPE}, + {"server", "nginx", TFE_HTTP_SERVER}, + {"expires", "Tue, 12 Jul 2022 07:11:56 GMT", TFE_HTTP_EXPIRES}}; + + +struct tsg_lua_pattern +{ + int *script_id; + int thread_num; + struct tsg_lua_script *lua_script; + struct lua_http_headers lua_http_head_list; +}; +struct tsg_lua_pattern *g_tsg_lua_pattern=NULL; + +struct lua_http_headers *lua_get_http_head_list() +{ + return &g_tsg_lua_pattern->lua_http_head_list; +} + +struct http_field_name *lua_http_field_name_dup(const struct http_field_name * orig) +{ + struct http_field_name * field_name_item = ALLOC(struct http_field_name, 1); + assert(field_name_item != NULL); + + if (orig->field_id == TFE_HTTP_UNKNOWN_FIELD) + { + field_name_item->field_id = TFE_HTTP_UNKNOWN_FIELD; + field_name_item->field_name = tfe_strdup(orig->field_name); + } + else + { + field_name_item->field_id = orig->field_id; + field_name_item->field_name = NULL; + } + return field_name_item; +} + +const char *lua_http_field_iterate(const struct tfe_http_half * half, void ** iter, struct http_field_name * field) +{ + struct lua_http_head_field **http_head_field = (struct lua_http_head_field **) iter; + + if (*http_head_field == NULL) + *http_head_field = TAILQ_FIRST(&(lua_get_http_head_list()->lua_http_field_list)); + else + *http_head_field = TAILQ_NEXT(*http_head_field, next); + + if (*http_head_field == NULL) return NULL; + + field->field_id = (*http_head_field)->field->field_id; + field->field_name = (*http_head_field)->field->field_name; + return (*http_head_field)->value; +} + +int lua_http_field_write(struct tfe_http_half * half, const struct http_field_name * field, const char * value) +{ + if (value != NULL) + { + struct lua_http_head_field * http_head_field = ALLOC(struct lua_http_head_field, 1); + http_head_field->field = lua_http_field_name_dup(field); + http_head_field->value = tfe_strdup(value); + TAILQ_INSERT_TAIL(&g_tsg_lua_pattern->lua_http_head_list.lua_http_field_list, http_head_field, next); + } + else + { + struct lua_http_head_field * http_head_field = NULL; struct lua_http_head_field * http_head_field_peer = NULL; + TAILQ_FOREACH_SAFE(http_head_field, &g_tsg_lua_pattern->lua_http_head_list.lua_http_field_list, next, http_head_field_peer) + { + if (http_field_name_compare(http_head_field->field, field) != 0) + continue; + + TAILQ_REMOVE(&g_tsg_lua_pattern->lua_http_head_list.lua_http_field_list, http_head_field, next); + http_field_name_destory(http_head_field->field); + free(http_head_field->value); + free(http_head_field); + } + } + + return 0; +} + +const char *lua_http_field_read(const struct tfe_http_half * half, const struct http_field_name * field) +{ + struct lua_http_head_field * http_head_field = NULL; + struct lua_http_head_field * http_head_field_node = NULL; + + TAILQ_FOREACH(http_head_field, &g_tsg_lua_pattern->lua_http_head_list.lua_http_field_list, next) + { + if (http_field_name_compare(http_head_field->field, field) != 0) continue; + http_head_field_node = http_head_field; + break; + } + + return http_head_field_node != NULL ? http_head_field->value : NULL; +} + +static int lua_http_default_headers_init(struct def_lua_http_headers *lua_http_head_value) +{ + for(size_t i=0; i < sizeof(def_lua_http_head_value)/sizeof(struct def_lua_http_headers); i++) + { + struct http_field_name field; + field.field_id = lua_http_head_value[i].field_id; + field.field_name = lua_http_head_value[i].filed_name; + + struct lua_http_head_field * http_head_field = ALLOC(struct lua_http_head_field, 1); + http_head_field->field = lua_http_field_name_dup(&field); + http_head_field->value = tfe_strdup(lua_http_head_value[i].value); + TAILQ_INSERT_TAIL(&g_tsg_lua_pattern->lua_http_head_list.lua_http_field_list, http_head_field, next); + } + + return 0; +} + +struct tsg_lua_script *tsg_lua_script_new(int lua_is_cache, const char *input_lua_data, size_t input_lua_data_len, int thread_num) +{ + int i=0; + struct tsg_lua_script *lua_script=ALLOC(struct tsg_lua_script, 1); + + lua_script->lua_is_cache=lua_is_cache; + lua_script->http_lua_handle = http_lua_handle_create(thread_num, "tfe"); + + if(lua_is_cache) + { + for(i=0; iscript_id[i]=http_lua_map_cache_script(lua_script->http_lua_handle[i], input_lua_data, input_lua_data_len); + } + } + + return lua_script; +} + +void lua_script_handle_destory(struct tsg_lua_script *lua_script) +{ + int i=0; + + for(i=0; i< g_tsg_lua_pattern->thread_num; i++) + { + tsg_destory_lua(lua_script->http_lua_handle[i]); + } + + FREE(&lua_script); +} + +int tsg_lua_pattern_profile_from_path(int profile_id, char **profile_msg, size_t *msg_len, int **script_id, int *timeout) +{ + int ret=0; + size_t input_sz=0; + const char* filename="./test_data/http_session.lua"; + + char *input= tfe_read_file(filename, &input_sz); + + *profile_msg=input; + *msg_len = input_sz; + *script_id = g_tsg_lua_pattern->script_id; + *timeout=1000; + + return ret; +} + +void lua_http_session_destory(struct tfe_http_session *session) +{ + if(session != NULL) + { + char *uri=(char *)session->req->req_spec.uri; + if(uri) + FREE(&uri); + struct tfe_http_half_ops *ops=(struct tfe_http_half_ops *)session->resp->ops; + if(ops) + FREE(&ops); + if(session->resp) + FREE(&session->resp); + if(session->req) + FREE(&session->req); + FREE(&session); + } + + return; +} + +const struct tfe_http_session *lua_http_session_init() +{ + struct tfe_http_session *session =ALLOC(struct tfe_http_session, 1); + + struct tfe_http_half * in_req_half=ALLOC(struct tfe_http_half, 1); + session->req = in_req_half; + + struct tfe_http_half * in_resp_half=ALLOC(struct tfe_http_half, 1); + session->resp = in_resp_half; + + struct tfe_http_half_ops *ops = ALLOC(struct tfe_http_half_ops, 1); + in_resp_half->ops = ops; + in_req_half->ops = ops; + + ops->ops_http_field_iterate = lua_http_field_iterate; + ops->ops_http_field_write = lua_http_field_write; + ops->ops_http_field_read = lua_http_field_read; + + return session; +} + +#if 0 +TEST(TSG_LUA_SCRIPT, Lua_TimeOut) +{ + int ret=0; + int profile_id=0,thread_id=0; + struct tsg_script_ctx tsg_ctx; + + struct timespec start_time, end_time; + + memset(&tsg_ctx, 0, sizeof(tsg_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.http_req_uri=2; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + + clock_gettime(CLOCK_REALTIME, &(start_time)); + ret = execute_lua_script_rule(lua_script, profile_id, NULL, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret==ERR_SCRIPT_TIMEOUT); + + clock_gettime(CLOCK_REALTIME, &(end_time)); + printf("take time %lu(s)\n", end_time.tv_sec - start_time.tv_sec); + + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} +#endif + +TEST(TSG_LUA_SCRIPT, Req_Uri) +{ + int ret=0; + int profile_id=0,thread_id=0; + struct tsg_script_ctx tsg_ctx; + memset(&tsg_ctx, 0, sizeof(tsg_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.events = EV_HTTP_REQ_HDR; + tsg_ctx.http_req_uri=1; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + tsg_ctx.session->req->req_spec.uri = tfe_strdup("forecast"); + + ret = execute_lua_script_rule(lua_script, profile_id, NULL, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + + EXPECT_STREQ(tsg_ctx.session->req->req_spec.uri, "team"); + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} + +TEST(TSG_LUA_SCRIPT, Req_Header) +{ + int ret=0; + int profile_id=0,thread_id=0; + struct tsg_script_ctx tsg_ctx; + memset(&tsg_ctx, 0, sizeof(tsg_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.events = EV_HTTP_REQ_HDR; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + tsg_ctx.session->req->req_spec.method = TFE_HTTP_METHOD_GET; + + ret = execute_lua_script_rule(lua_script, profile_id, NULL, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + + const char* user_agent_val=tfe_http_std_field_read(tsg_ctx.session->resp, TFE_HTTP_USER_AGENT); + EXPECT_TRUE(user_agent_val!=NULL); + EXPECT_STREQ(user_agent_val, "curl-v1.1"); + + const char* x_tg_val=tfe_http_nonstd_field_read(tsg_ctx.session->resp, "x-tg-construct-by"); + EXPECT_TRUE(x_tg_val!=NULL); + EXPECT_STREQ(x_tg_val, "tfe"); + + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} + +TEST(TSG_LUA_SCRIPT, Resp_Header) +{ + int ret=0; + int profile_id=0,thread_id=0; + struct tsg_script_ctx tsg_ctx; + memset(&tsg_ctx,0,sizeof(struct tsg_script_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.events = EV_HTTP_RESP_HDR; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + tsg_ctx.session->resp->resp_spec.resp_code = 200; + + ret = execute_lua_script_rule(lua_script, profile_id, NULL, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + + const char* content_type_val=tfe_http_std_field_read(tsg_ctx.session->resp, TFE_HTTP_CONT_TYPE); + EXPECT_TRUE(content_type_val!=NULL); + EXPECT_STREQ(content_type_val, "utf8"); + + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} + +TEST(TSG_LUA_SCRIPT, Req_Data) +{ + int ret=0; + int profile_id=0,thread_id=0; + struct tsg_script_ctx tsg_ctx; + memset(&tsg_ctx,0,sizeof(struct tsg_script_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.events = EV_HTTP_REQ_BODY_END; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + + const char *input="This is request data"; + tsg_ctx.http_body = evbuffer_new(); + evbuffer_add(tsg_ctx.http_body, input, strlen(input)); + + ret = execute_lua_script_rule(lua_script, profile_id, NULL, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + ASSERT_TRUE(tsg_ctx.http_lua_body!=NULL); + + char *__http_body=(char *) evbuffer_pullup(tsg_ctx.http_lua_body, -1); + EXPECT_STREQ(__http_body, "This is request data set req body"); + printf("__http_body: %s\n",__http_body); + + evbuffer_free(tsg_ctx.http_body); + evbuffer_free(tsg_ctx.http_lua_body); + + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} + +TEST(TSG_LUA_SCRIPT, Resq_Data) +{ + int ret=0; + int profile_id=3,thread_id=0; + struct tsg_script_ctx tsg_ctx; + memset(&tsg_ctx,0,sizeof(struct tsg_script_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.events = EV_HTTP_RESP_BODY_END; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + + const char *input="This is response data"; + tsg_ctx.http_body = evbuffer_new(); + evbuffer_add(tsg_ctx.http_body, input, strlen(input)); + + ret = execute_lua_script_rule(lua_script, profile_id, NULL, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + ASSERT_TRUE(tsg_ctx.http_lua_body!=NULL); + + char *__http_body=(char *) evbuffer_pullup(tsg_ctx.http_lua_body, -1); + EXPECT_STREQ(__http_body, "This is response data set resp body"); + printf("__http_body: %s\n",__http_body); + + evbuffer_free(tsg_ctx.http_body); + evbuffer_free(tsg_ctx.http_lua_body); + + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} + +TEST(TSG_LUA_SCRIPT, Lua_Http_Session) +{ + int ret=0; + int profile_id=0,thread_id=0; + struct tsg_script_ctx tsg_ctx; + memset(&tsg_ctx,0,sizeof(struct tsg_script_ctx)); + + tsg_ctx.session=lua_http_session_init(); + tsg_ctx.events = EV_HTTP_RESP_HDR; + + struct tsg_lua_script * lua_script=g_tsg_lua_pattern->lua_script; + lua_script->http_lua_profile = tsg_lua_pattern_profile_from_path; + tsg_ctx.lua_ctx=http_lua_ctx_new(lua_script, thread_id); + + ret = execute_lua_script_rule(lua_script, profile_id, tsg_ctx.lua_ctx, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + + const char* content_type_val=tfe_http_std_field_read(tsg_ctx.session->resp, TFE_HTTP_CONT_TYPE); + EXPECT_TRUE(content_type_val!=NULL); + EXPECT_STREQ(content_type_val, "utf8"); + + tsg_ctx.events = EV_HTTP_RESP_BODY_END; + tsg_ctx.http_body = evbuffer_new(); + const char *user_input="This is response data"; + evbuffer_add(tsg_ctx.http_body, user_input, strlen(user_input)); + + ret = execute_lua_script_rule(lua_script, profile_id, tsg_ctx.lua_ctx, thread_id, (void *)&tsg_ctx); + EXPECT_TRUE(ret>0); + EXPECT_TRUE(tsg_ctx.http_lua_body!=NULL); + + char *__http_body=(char *) evbuffer_pullup(tsg_ctx.http_lua_body, -1); + EXPECT_STREQ(__http_body, "This is response data set resp body"); + printf("__http_body: %s\n",__http_body); + + evbuffer_free(tsg_ctx.http_body); + evbuffer_free(tsg_ctx.http_lua_body); + + http_lua_ctx_free(lua_script, thread_id, tsg_ctx.lua_ctx); + lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); +} + +int main(int argc, char ** argv) +{ + struct tsg_lua_pattern *tsg_lua_pattern = ALLOC(struct tsg_lua_pattern, 1); + TAILQ_INIT(&tsg_lua_pattern->lua_http_head_list.lua_http_field_list); + + int i=0, thread_num=1; + struct tsg_lua_script *lua_script=ALLOC(struct tsg_lua_script, 1); + + lua_script->lua_is_cache=0; + lua_script->http_lua_handle = http_lua_handle_create(thread_num, "tfe"); + + if(lua_script->lua_is_cache) + { + size_t input_sz; + const char* filename="./test_data/http_session.lua"; + char *input= tfe_read_file(filename, &input_sz); + + tsg_lua_pattern->script_id = ALLOC(int, thread_num); + + for(i=0; iscript_id[i]=http_lua_map_cache_script(lua_script->http_lua_handle[i], input, input_sz); + } + } + + tsg_lua_pattern->lua_script=lua_script; + tsg_lua_pattern->thread_num=thread_num; + g_tsg_lua_pattern = tsg_lua_pattern; + + lua_http_default_headers_init(def_lua_http_head_value); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/plugin/business/pangu-http/test_data/http_session.lua b/plugin/business/pangu-http/test_data/http_session.lua new file mode 100644 index 0000000..4c0aa2a --- /dev/null +++ b/plugin/business/pangu-http/test_data/http_session.lua @@ -0,0 +1,73 @@ + +local ctx=tfe.context + +function Sleep2(n) + local t0 = os.clock() + while os.clock() - t0 <= n do end +end + +if(tfe.get_current_stage() == "http_stage_test") +then + Sleep2(1000) +end + +if(tfe.get_current_stage() == "http_req_header") +then + local req_headers_tab = tfe.req.get_headers() + for k, v in pairs(req_headers_tab) do + print(k,v) + if k == "User-Agent" then + tfe.req.set_header("user-agent", "curl-v1.1") + end + if k == "Pragma" then + tfe.req.set_header("pragma", "nil") + end + end + --tfe.exit(0) + tfe.req.set_header("x-tg-construct-by", "tfe") + local method = tfe.req.get_method() + print(method) +end + +if(tfe.get_current_stage() == "http_req_uri") +then + local req_uri=tfe.req.get_uri() + if req_uri then + tfe.req.set_uri("team") + end +end + +if(tfe.get_current_stage() == "http_resp_header") +then + local resp_headers_tab = tfe.resp.get_headers() + for k, v in pairs(resp_headers_tab) do + print(k,v) + if k == "Content-Type" then + tfe.resp.set_header("Content-Type", "utf8") + end + if k == "Expires" then + tfe.resp.set_header("Expires", "nil") + end + end + local status_code = tfe.resp.get_status_code() + print(status_code) +end + +if(tfe.get_current_stage() == "http_req_body") +then + local req_body = tfe.req.get_body_data() + if req_body then + tfe.req.set_body_data(req_body, " set req body") + end + len=#req_body + return len +end + +if(tfe.get_current_stage() == "http_resp_body") +then + local resp_body = tfe.resp.get_body_data() + if resp_body then + tfe.resp.set_body_data(resp_body, " set resp body") + end +end + diff --git a/resource/pangu/table_info.conf b/resource/pangu/table_info.conf index 3ba83e4..cb284d9 100644 --- a/resource/pangu/table_info.conf +++ b/resource/pangu/table_info.conf @@ -57,4 +57,5 @@ 37 TSG_SECURITY_DESTINATION_LOCATION virtual TSG_OBJ_GEO_LOCATION -- 38 TSG_FIELD_DOH_QNAME virtual ["TSG_OBJ_FQDN","TSG_OBJ_FQDN_CAT"] -- 39 TSG_FIELD_DOH_HOST virtual ["TSG_OBJ_FQDN","TSG_OBJ_FQDN_CAT"] -- -40 PXY_SSL_FINGERPRINT plugin {"key":2,"valid":4} \ No newline at end of file +40 PXY_SSL_FINGERPRINT plugin {"key":2,"valid":4} +41 PXY_PROFILE_RUN_SCRIPTS plugin {"key":1,"foreign":"2","valid":4} diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index db1a31a..a661483 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -173,6 +173,10 @@ add_library(rdkafka SHARED IMPORTED GLOBAL) set_property(TARGET rdkafka PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/librdkafka.so) set_property(TARGET rdkafka PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}/MESA) +add_library(tsglua SHARED IMPORTED GLOBAL) +set_property(TARGET tsglua PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libtsglua.so) +set_property(TARGET tsglua PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + add_library(mrzcpd SHARED IMPORTED GLOBAL) set_property(TARGET mrzcpd PROPERTY IMPORTED_LOCATION ${MRZCPD_LIB_DIR}/libmarsio.so) set_property(TARGET mrzcpd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MRZCPD_INCLUDE_DIR})