#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 thread_num; struct elua_script **elua_ctx; 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 void lua_http_headers_clear() { 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) { 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); } } 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; } int http_lua_profile_for_test(char *profile_id_str, struct elua_script ***elua_ctx, char **profile_msg, size_t *msg_len, int *timeout) { size_t input_sz; const char *filename[]= {"./test_data/http_session.lua", "./test_data/header_filter_by_lua.lua"}; int profile_id=atoi(profile_id_str); char *input= tfe_read_file(filename[profile_id], &input_sz); *profile_msg=tfe_strdup(input); *msg_len=input_sz; *timeout=1000; *elua_ctx=g_tsg_lua_pattern->elua_ctx; FREE(&input); return 0; } 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; } TEST(TSG_LUA_SCRIPT, Lua_TimeOut) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; clock_gettime(CLOCK_REALTIME, &(start_time)); ret = execute_lua_script_rule(lua_script, (char *)profile_id_str, NULL, thread_id, (void *)&tsg_ctx); EXPECT_TRUE(ret!=0); clock_gettime(CLOCK_REALTIME, &(end_time)); printf("take time %lu(s)\n", end_time.tv_sec - start_time.tv_sec); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Req_Uri) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; tsg_ctx.session->req->req_spec.uri = tfe_strdup("forecast"); ret = execute_lua_script_rule(lua_script, (char *)profile_id_str, NULL, thread_id, (void *)&tsg_ctx); EXPECT_TRUE(ret==0); EXPECT_STREQ(tsg_ctx.rewrite_uri,"team"); FREE(&tsg_ctx.rewrite_uri); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Req_Header) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; tsg_ctx.session->req->req_spec.method = TFE_HTTP_METHOD_GET; ret = execute_lua_script_rule(lua_script, (char *)profile_id_str, 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"); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Resp_Header) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; tsg_ctx.session->resp->resp_spec.resp_code = 200; ret = execute_lua_script_rule(lua_script, (char *)profile_id_str, 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"); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Req_Data) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; 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, (char *)profile_id_str, 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); size_t __http_body_len = evbuffer_get_length(tsg_ctx.http_lua_body); char __http_body_tmp[__http_body_len+1]; memset(__http_body_tmp, 0, sizeof(__http_body_tmp)); memcpy(__http_body_tmp, __http_body, __http_body_len); EXPECT_STREQ(__http_body_tmp, "This is request data set req body"); printf("__http_body: %s\n",__http_body_tmp); evbuffer_free(tsg_ctx.http_body); evbuffer_free(tsg_ctx.http_lua_body); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Resq_Data) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; 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, (char *)profile_id_str, 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); size_t __http_body_len = evbuffer_get_length(tsg_ctx.http_lua_body); char __http_body_tmp[__http_body_len+1]; memset(__http_body_tmp, 0, sizeof(__http_body_tmp)); memcpy(__http_body_tmp, __http_body, __http_body_len); EXPECT_STREQ(__http_body_tmp, "This is response data set resp body"); printf("__http_body_tmp: %s\n",__http_body_tmp); evbuffer_free(tsg_ctx.http_body); evbuffer_free(tsg_ctx.http_lua_body); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Lua_Http_Session) { int ret=0; int thread_id=0; const char *profile_id_str = "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 = http_lua_profile_for_test; tsg_ctx.elua_ctx=http_lua_ctx_new(lua_script, thread_id); ret = execute_lua_script_rule(lua_script, (char *)profile_id_str, tsg_ctx.elua_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, (char *)profile_id_str, tsg_ctx.elua_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); size_t __http_body_len = evbuffer_get_length(tsg_ctx.http_lua_body); char __http_body_tmp[__http_body_len+1]; memset(__http_body_tmp, 0, sizeof(__http_body_tmp)); memcpy(__http_body_tmp, __http_body, __http_body_len); EXPECT_STREQ(__http_body_tmp, "This is response data set resp body"); printf("__http_body: %s\n",__http_body_tmp); evbuffer_free(tsg_ctx.http_body); evbuffer_free(tsg_ctx.http_lua_body); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; http_lua_ctx_free(lua_script, thread_id, tsg_ctx.elua_ctx); lua_http_session_destory((struct tfe_http_session *)tsg_ctx.session); } TEST(TSG_LUA_SCRIPT, Lua_Http_Header_Filter) { int ret=0; int thread_id=0; const char *profile_id_str = "1"; 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 = http_lua_profile_for_test; tsg_ctx.elua_ctx=http_lua_ctx_new(lua_script, thread_id); lua_http_headers_clear(); tsg_ctx.replacing=tsg_ctx.session->resp; ret = execute_lua_script_rule(lua_script, (char *)profile_id_str, tsg_ctx.elua_ctx, thread_id, (void *)&tsg_ctx); EXPECT_TRUE(ret==0); const char *server_type_val=tfe_http_std_field_read(tsg_ctx.replacing, TFE_HTTP_SERVER); EXPECT_TRUE(server_type_val!=NULL); EXPECT_STREQ(server_type_val, "nqinx"); const char *location_type_val=tfe_http_std_field_read(tsg_ctx.replacing, TFE_HTTP_LOCATION); EXPECT_TRUE(location_type_val!=NULL); printf("location:%s\n",location_type_val); const char *date_type_val=tfe_http_std_field_read(tsg_ctx.replacing, TFE_HTTP_DATE); EXPECT_TRUE(date_type_val!=NULL); printf("date:%s\n",date_type_val); 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, (char *)profile_id_str, tsg_ctx.elua_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_TRUE(__http_body!=NULL); elua_cleanup_script(g_tsg_lua_pattern->elua_ctx[thread_id]); FREE(&g_tsg_lua_pattern->elua_ctx[thread_id]); g_tsg_lua_pattern->elua_ctx[thread_id]=NULL; http_lua_ctx_free(lua_script, thread_id, tsg_ctx.elua_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 thread_num=1; struct tsg_lua_script *lua_script=ALLOC(struct tsg_lua_script, 1); http_lua_handle_create(lua_script, thread_num, "tfe"); tsg_lua_pattern->elua_ctx = ALLOC(struct elua_script*, thread_num); 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(); }