From c2f0bde211fc820554bb6b1d635c0920d8677e81 Mon Sep 17 00:00:00 2001 From: Lu Qiuwen Date: Tue, 25 Sep 2018 10:17:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E8=B0=83=E9=80=9AHTTP?= =?UTF-8?q?=E9=87=8D=E5=AE=9A=E5=90=91=E4=B8=9A=E5=8A=A1=20*=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0HTTP=20Status=E6=A0=87=E5=87=86=E5=8C=96=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=8F=8A=E8=BE=85=E5=8A=A9=E5=87=BD=E6=95=B0=EF=BC=9B?= =?UTF-8?q?=20*=20=E5=A2=9E=E5=8A=A0HTTP=E8=A7=A3=E6=9E=90=E5=B1=82?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=BA=94=E7=AD=94=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20*=20=E4=BF=AE=E6=AD=A3=E4=BA=86Pangu=20HTTP=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=AF=BC=E8=87=B4=E6=AE=B5=E9=94=99=E8=AF=AF=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E7=B3=BB=E5=88=97=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/include/tfe_http.h | 82 ++++++++- common/src/tfe_http.cpp | 34 +++- plugin/business/pangu-http/pangu_http.cpp | 32 +++- .../http/include/internal/http_common.h | 10 ++ .../http/include/internal/http_half.h | 13 +- plugin/protocol/http/src/http_entry.cpp | 88 +++++++--- plugin/protocol/http/src/http_half.cpp | 166 +++++++++++++----- plugin/protocol/http/test/test_http_half.cpp | 4 +- vendor/CMakeLists.txt | 3 +- 9 files changed, 350 insertions(+), 82 deletions(-) diff --git a/common/include/tfe_http.h b/common/include/tfe_http.h index 0295e0e..65c02bb 100644 --- a/common/include/tfe_http.h +++ b/common/include/tfe_http.h @@ -10,7 +10,7 @@ #include /* Copy from http_parser.h */ -#define HTTP_METHOD_MAP(XX) \ +#define __HTTP_METHOD_MAP(XX) \ XX(0, DELETE, DELETE) \ XX(1, GET, GET) \ XX(2, HEAD, HEAD) \ @@ -54,10 +54,79 @@ /* icecast */ \ XX(33, SOURCE, SOURCE) \ +/* Status Codes */ +#define __HTTP_STATUS_MAP(XX) \ + XX(100, CONTINUE, Continue) \ + XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ + XX(102, PROCESSING, Processing) \ + XX(200, OK, OK) \ + XX(201, CREATED, Created) \ + XX(202, ACCEPTED, Accepted) \ + XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ + XX(204, NO_CONTENT, No Content) \ + XX(205, RESET_CONTENT, Reset Content) \ + XX(206, PARTIAL_CONTENT, Partial Content) \ + XX(207, MULTI_STATUS, Multi-Status) \ + XX(208, ALREADY_REPORTED, Already Reported) \ + XX(226, IM_USED, IM Used) \ + XX(300, MULTIPLE_CHOICES, Multiple Choices) \ + XX(301, MOVED_PERMANENTLY, Moved Permanently) \ + XX(302, FOUND, Found) \ + XX(303, SEE_OTHER, See Other) \ + XX(304, NOT_MODIFIED, Not Modified) \ + XX(305, USE_PROXY, Use Proxy) \ + XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ + XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ + XX(400, BAD_REQUEST, Bad Request) \ + XX(401, UNAUTHORIZED, Unauthorized) \ + XX(402, PAYMENT_REQUIRED, Payment Required) \ + XX(403, FORBIDDEN, Forbidden) \ + XX(404, NOT_FOUND, Not Found) \ + XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ + XX(406, NOT_ACCEPTABLE, Not Acceptable) \ + XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ + XX(408, REQUEST_TIMEOUT, Request Timeout) \ + XX(409, CONFLICT, Conflict) \ + XX(410, GONE, Gone) \ + XX(411, LENGTH_REQUIRED, Length Required) \ + XX(412, PRECONDITION_FAILED, Precondition Failed) \ + XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ + XX(414, URI_TOO_LONG, URI Too Long) \ + XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ + XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ + XX(417, EXPECTATION_FAILED, Expectation Failed) \ + XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ + XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ + XX(423, LOCKED, Locked) \ + XX(424, FAILED_DEPENDENCY, Failed Dependency) \ + XX(426, UPGRADE_REQUIRED, Upgrade Required) \ + XX(428, PRECONDITION_REQUIRED, Precondition Required) \ + XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ + XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ + XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ + XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ + XX(501, NOT_IMPLEMENTED, Not Implemented) \ + XX(502, BAD_GATEWAY, Bad Gateway) \ + XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ + XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ + XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ + XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ + XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ + XX(508, LOOP_DETECTED, Loop Detected) \ + XX(510, NOT_EXTENDED, Not Extended) \ + XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ + enum tfe_http_std_method { -#define XX(num, name, string) TFE_HTTP_##name = num, - HTTP_METHOD_MAP(XX) +#define XX(num, name, string) TFE_HTTP_METHOD_##name = num, + __HTTP_METHOD_MAP(XX) +#undef XX +}; + +enum tfe_http_std_status +{ +#define XX(num, name, string) TFE_HTTP_STATUS_##name = num, + __HTTP_STATUS_MAP(XX) #undef XX }; @@ -181,6 +250,9 @@ struct tfe_http_half struct tfe_http_session { unsigned int session_id; + short major_version; + short minor_version; + struct tfe_http_session_ops * ops; struct tfe_http_half * req; struct tfe_http_half * resp; @@ -214,6 +286,10 @@ void http_field_destory(struct http_field_name *); const char * http_std_method_to_string(enum tfe_http_std_method method); enum tfe_http_std_method http_std_method_construct(const char * str_method); +/* Tools functions for standard HTTP status */ +const char * http_std_status_to_string(enum tfe_http_std_status status); +enum tfe_http_std_status http_std_status_construct(const char * str_status); + static inline const char * tfe_http_field_read(const struct tfe_http_half * half, const struct http_field_name * name) { diff --git a/common/src/tfe_http.cpp b/common/src/tfe_http.cpp index 022f09b..45d8803 100644 --- a/common/src/tfe_http.cpp +++ b/common/src/tfe_http.cpp @@ -43,18 +43,34 @@ static const char * __str_std_header_field_map[] = [TFE_HTTP_ACCEPT_ENCODING] = "Accept-Encoding" }; -static const char * __str_std_method_map[] = +static const char * __str_std_method_map[1024] = {}; +void __str_std_method_map_init() __attribute__((constructor, used)); +void __str_std_method_map_init() { -#define XX(num, name, string) [TFE_HTTP_##name] = #string, - HTTP_METHOD_MAP(XX) +#define XX(num, name, string) __str_std_method_map[TFE_HTTP_METHOD_##name] = #string; + __HTTP_METHOD_MAP(XX) #undef XX -}; +} + +static const char * __str_std_status_map[1024] = {}; +void __str_std_status_map_init() __attribute__((constructor, used)); +void __str_std_status_map_init() +{ +#define XX(num, name, string) __str_std_status_map[TFE_HTTP_STATUS_##name] = #string; + __HTTP_STATUS_MAP(XX) +#undef XX +} const char * http_std_method_to_string(enum tfe_http_std_method method) { return __str_std_method_map[method]; } +const char * http_std_status_to_string(enum tfe_http_std_status status) +{ + return __str_std_status_map[status]; +} + struct http_field_name * http_field_name_duplicate(const struct http_field_name * orig) { struct http_field_name * __duplicated = ALLOC(struct http_field_name, 1); @@ -188,12 +204,20 @@ void http_frame_raise_event(struct http_frame_session_ctx * ht_frame, struct tfe_plugin * plugin_info_iter; TFE_PLUGIN_FOREACH(plugin_info_iter, &__for_each_iterator) { - if (plugin_info_iter->on_session_data == NULL) continue; + if (plugin_info_iter->on_session_data == NULL) + { + continue; + } /* Calling ctx, in callback can fetch by calling frame_plugin_status_get_XXX */ ht_frame->calling_plugin = plugin_info_iter; ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id]; + if (ht_frame->calling_plugin_status->detached) + { + continue; + } + void ** calling_pme = &ht_frame->calling_plugin_status->pme; plugin_info_iter->on_session_data(stream, ht_session, event, data, datalen, thread_id, calling_pme); } diff --git a/plugin/business/pangu-http/pangu_http.cpp b/plugin/business/pangu-http/pangu_http.cpp index bd1b8b2..ddd8bce 100644 --- a/plugin/business/pangu-http/pangu_http.cpp +++ b/plugin/business/pangu-http/pangu_http.cpp @@ -768,10 +768,13 @@ static void http_redirect(const struct tfe_http_session * session, enum tfe_http { int resp_code = 0, ret = 0; char * url = NULL; + struct tfe_http_half * response = NULL; struct tfe_http_session * to_write = NULL; + url = ALLOC(char, ctx->enforce_rules[0].serv_def_len); - ret = sscanf(ctx->enforce_para, "code=%d%[^;];url=%*[^;];", &resp_code, url); + ret = sscanf(ctx->enforce_para, "code=%d;url=%[^;]", &resp_code, url); + if (ret != 2) { TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid redirect rule %d paramter %s", @@ -780,10 +783,16 @@ static void http_redirect(const struct tfe_http_session * session, enum tfe_http } to_write = tfe_http_session_allow_write(session); + if (to_write == NULL) + { + assert(0); + } + response = tfe_http_session_response_create(to_write, resp_code); _wrap_std_field_write(response, TFE_HTTP_LOCATION, url); + tfe_http_session_response_set(to_write, response); - response = NULL; + tfe_http_session_detach(session); error_out: free(url); @@ -862,16 +871,24 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht Maat_stream_scan_string_end(&(ctx->sp)); ctx->sp = NULL; } + if (hit_cnt > 0) { ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce); - if (ctx->enforce_rules[0].serv_def_len > MAX_SERVICE_DEFINE_LEN) + size_t __serv_def_len = (size_t)ctx->enforce_rules[0].serv_def_len; + ctx->enforce_para = ALLOC(char, __serv_def_len); + + if (__serv_def_len > MAX_SERVICE_DEFINE_LEN) { - ctx->enforce_para = ALLOC(char, ctx->enforce_rules->serv_def_len); - read_rule_ret = Maat_read_rule(g_pangu_rt->maat, ctx->enforce_rules + 0, - MAAT_RULE_SERV_DEFINE, ctx->enforce_para, ctx->enforce_rules[0].serv_def_len); + read_rule_ret = Maat_read_rule(g_pangu_rt->maat, &ctx->enforce_rules[0], MAAT_RULE_SERV_DEFINE, + ctx->enforce_para, ctx->enforce_rules[0].serv_def_len); assert(read_rule_ret == ctx->enforce_rules[0].serv_def_len); } + else + { + strcpy(ctx->enforce_para, ctx->enforce_rules[0].service_defined); + } + if (hit_cnt > 1) { p = buff; @@ -879,11 +896,13 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht { p += snprintf(p, sizeof(buff) - (p - buff), "%d:", result[i].config_id); } + *p = '\0'; TFE_LOG_INFO(g_pangu_rt->local_logger, "Multiple rules matched: url=%s num=%lu ids=%s execute=%d.", session->req->req_spec.url, hit_cnt, buff, ctx->enforce_rules[0].config_id); } } + return ctx->action; } @@ -949,6 +968,7 @@ Re_Enter: case PG_ACTION_REJECT: http_reject(session, events, ctx); break; case PG_ACTION_REDIRECT: http_redirect(session, events, ctx); + break; case PG_ACTION_REPLACE: http_replace(stream, session, events, body_frag, frag_size, ctx); break; case PG_ACTION_WHITELIST: tfe_http_session_detach(session); diff --git a/plugin/protocol/http/include/internal/http_common.h b/plugin/protocol/http/include/internal/http_common.h index 1cd66db..67245df 100644 --- a/plugin/protocol/http/include/internal/http_common.h +++ b/plugin/protocol/http/include/internal/http_common.h @@ -30,6 +30,10 @@ struct http_session_private struct http_connection_private * hc_private; /* HTTP FRAME CTX */ struct http_frame_session_ctx * ht_frame; + /* USER SETUP REQUEST HALF */ + struct http_half_private * hf_private_req_user; + /* USER SETUP RESPONSE HALF */ + struct http_half_private * hf_private_resp_user; }; struct http_connection_private @@ -82,6 +86,12 @@ static inline const struct tfe_http_session * to_hs_public(const struct http_ses return &hs_private->hs_public; } +static inline struct tfe_http_session * to_hs_public(struct http_session_private * hs_private) +{ + if (hs_private == NULL) return NULL; + return &hs_private->hs_public; +} + static inline struct http_session_private * to_hs_private(struct tfe_http_session * hs_public) { if (hs_public == NULL) return NULL; diff --git a/plugin/protocol/http/include/internal/http_half.h b/plugin/protocol/http/include/internal/http_half.h index 16bf5a8..1a9e3fe 100644 --- a/plugin/protocol/http/include/internal/http_half.h +++ b/plugin/protocol/http/include/internal/http_half.h @@ -50,22 +50,28 @@ struct http_half_private short major; short minor; + /* URI */ struct evbuffer * evbuf_uri; char * url_storage; + /* Header Parser */ struct evbuffer * evbuf_header_field; struct evbuffer * evbuf_header_value; bool is_evbuf_header_field_set; bool is_evbuf_header_value_set; - struct evbuffer * evbuf_body; - + /* Status */ enum hf_private_status body_status; enum hf_private_status message_status; /* default stream action */ enum tfe_stream_action stream_action; enum tfe_stream_action user_stream_action; + + /* Setup by User */ + bool is_setup_by_user; + struct evbuffer * evbuf_body; + struct evbuffer * evbuf_raw; }; struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor); @@ -85,6 +91,7 @@ void hf_private_destory(struct http_half_private * hf_private); * -1 for error. */ int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len); +void hf_private_construct(struct http_half_private * hf_private); void hf_private_set_callback(struct http_half_private * hf_private, hf_private_cb * cb, void * user, void (* fn_user_deleter)(void *)); @@ -96,6 +103,8 @@ struct http_session_private * hs_private_create(struct http_connection_private * void hs_private_destory(struct http_session_private * hs_private); + + void hs_private_hf_private_set(struct http_session_private * hs_private, struct http_half_private * hf, enum tfe_http_direction); diff --git a/plugin/protocol/http/src/http_entry.cpp b/plugin/protocol/http/src/http_entry.cpp index b142b0b..cada659 100644 --- a/plugin/protocol/http/src/http_entry.cpp +++ b/plugin/protocol/http/src/http_entry.cpp @@ -9,6 +9,7 @@ #include #include #include +#include struct http_plugin __g_http_plugin; struct http_plugin * g_http_plugin = &__g_http_plugin; @@ -143,8 +144,11 @@ enum tfe_stream_action __http_connection_entry_on_response(const struct tfe_stre struct http_connection_private * hc_private, unsigned int thread_id, const unsigned char * data, size_t len) { struct http_session_private * hs_private = TAILQ_FIRST(&hc_private->hs_private_list); - struct http_half_private * hf_private_response = to_hf_response_private(hs_private); + struct http_half_private * hf_private_resp_in; + struct http_half_private * hf_private_resp_user; + int ret = 0; + size_t __action_byptes; /* Standalone response, it means missing something or malformed http protocol */ if (hs_private == NULL) @@ -153,44 +157,71 @@ enum tfe_stream_action __http_connection_entry_on_response(const struct tfe_stre goto __errout; } + hf_private_resp_in = to_hf_response_private(hs_private); + hf_private_resp_user = hs_private->hf_private_resp_user; + /* First time parse http response */ - if (hf_private_response == NULL) + if (hf_private_resp_in == NULL) { /* HTTP Version */ short resp_major = to_hf_request_private(hs_private)->major; short resp_minor = to_hf_request_private(hs_private)->minor; /* Response */ - hf_private_response = hf_private_create(TFE_HTTP_RESPONSE, resp_major, resp_minor); - hs_private_hf_private_set(hs_private, hf_private_response, TFE_HTTP_RESPONSE); - hf_private_set_session(hf_private_response, hs_private); + hf_private_resp_in = hf_private_create(TFE_HTTP_RESPONSE, resp_major, resp_minor); + hs_private_hf_private_set(hs_private, hf_private_resp_in, TFE_HTTP_RESPONSE); + hf_private_set_session(hf_private_resp_in, hs_private); - /* Closure, catch stream, session and thread_id */ - struct user_event_dispatch_closure * __closure = ALLOC(struct user_event_dispatch_closure, 1); - __closure->thread_id = thread_id; - __closure->stream = stream; - __closure->session = to_hs_public(hs_private); + if (hf_private_resp_user != NULL) + { + /* Set nothing callback, dont call user callback because the data need to be droped */ + hf_private_set_callback(hf_private_resp_in, NULL, NULL, NULL); + /* Drop all data, because the user's response need to be send */ + hf_private_resp_in->stream_action = ACTION_DROP_DATA; + } + else + { + /* Closure, catch stream, session and thread_id */ + struct user_event_dispatch_closure * __closure = ALLOC(struct user_event_dispatch_closure, 1); + __closure->thread_id = thread_id; + __closure->stream = stream; + __closure->session = to_hs_public(hs_private); - /* Set callback, this callback used to raise business event */ - hf_private_set_callback(hf_private_response, __user_event_dispatch, __closure, free); + /* Set callback, this callback used to raise business event */ + hf_private_set_callback(hf_private_resp_in, __user_event_dispatch, __closure, free); + /* Inherit user stream action, this action can affact session's behavior */ + hf_private_resp_in->user_stream_action = to_hf_request_private(hs_private)->user_stream_action; + } + } - /* Inherit user stream action, this action can affact session's behavior */ - hf_private_response->user_stream_action = to_hf_request_private(hs_private)->user_stream_action; + if (hf_private_resp_user != NULL) + { + /* Construct, and write response immediately */ + hf_private_construct(hf_private_resp_user); + size_t __to_write_len = evbuffer_get_length(hf_private_resp_user->evbuf_raw); + unsigned char * __to_write = evbuffer_pullup(hf_private_resp_user->evbuf_raw, __to_write_len); + + /* Write the data to stream, UPSTREAM is the incoming direction for response */ + ret = tfe_stream_write(stream, CONN_DIR_DOWNSTREAM, __to_write, __to_write_len); + if (unlikely(ret < 0)) { assert(0); } + + hf_private_destory(hf_private_resp_user); + hs_private->hf_private_resp_user = NULL; } /* Parse the content, the data which in defered state has been ignored. */ - ret = hf_private_parse(hf_private_response, data, len); + ret = hf_private_parse(hf_private_resp_in, data, len); /* Need more data, no boundary touched */ if (ret == 0) { - if (hf_private_response->stream_action == ACTION_DROP_DATA || - hf_private_response->stream_action == ACTION_FORWARD_DATA) + if (hf_private_resp_in->stream_action == ACTION_DROP_DATA || + hf_private_resp_in->stream_action == ACTION_FORWARD_DATA) { - hf_private_response->parse_cursor = 0; + hf_private_resp_in->parse_cursor = 0; } - return hf_private_response->stream_action; + return hf_private_resp_in->stream_action; } /* Some kind of error happened, write log and detach the stream */ @@ -203,13 +234,30 @@ enum tfe_stream_action __http_connection_entry_on_response(const struct tfe_stre goto __errout; } - if (hf_private_response->message_status == STATUS_COMPLETE) + if (hf_private_resp_in->message_status == STATUS_COMPLETE) { http_frame_raise_session_end(hs_private->ht_frame, stream, &hs_private->hs_public, thread_id); TAILQ_REMOVE(&hc_private->hs_private_list, hs_private, next); hs_private_destory(hs_private); } + __action_byptes = hf_private_resp_in->parse_cursor; + hf_private_resp_in->parse_cursor = 0; + + if (hf_private_resp_in->stream_action == ACTION_FORWARD_DATA) + { + tfe_stream_action_set_opt(stream, ACTION_OPT_FOWARD_BYTES, &__action_byptes, sizeof(__action_byptes)); + return ACTION_FORWARD_DATA; + } + + if (hf_private_resp_in->stream_action == ACTION_DROP_DATA) + { + tfe_stream_action_set_opt(stream, ACTION_OPT_DROP_BYTES, &__action_byptes, sizeof(__action_byptes)); + return ACTION_DROP_DATA; + } + + goto __errout; + __errout: tfe_stream_detach(stream); return ACTION_FORWARD_DATA; diff --git a/plugin/protocol/http/src/http_half.cpp b/plugin/protocol/http/src/http_half.cpp index 9b79fc2..fec3b3a 100644 --- a/plugin/protocol/http/src/http_half.cpp +++ b/plugin/protocol/http/src/http_half.cpp @@ -121,10 +121,10 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st /* accept-encoding, host is located in header's K-V structure */ hf_req_spec->method = (enum tfe_http_std_method) parser->method; const static struct http_field_name __host_field_name = - { - .field_id = TFE_HTTP_HOST, - .field_name = NULL - }; + { + .field_id = TFE_HTTP_HOST, + .field_name = NULL + }; hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name); @@ -158,28 +158,28 @@ void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, s /* Content Type */ const static struct http_field_name __cont_encoding_type_name = - { - .field_id = TFE_HTTP_CONT_TYPE, - .field_name = NULL - }; + { + .field_id = TFE_HTTP_CONT_TYPE, + .field_name = NULL + }; hf_resp_spec->content_type = (char *) tfe_http_field_read(hf_public, &__cont_encoding_type_name); /* Content Length */ const static struct http_field_name __cont_encoding_length_name = - { - .field_id = TFE_HTTP_CONT_LENGTH, - .field_name = NULL - }; + { + .field_id = TFE_HTTP_CONT_LENGTH, + .field_name = NULL + }; hf_resp_spec->content_length = (char *) tfe_http_field_read(hf_public, &__cont_encoding_length_name); /* Content Encoding */ const static struct http_field_name __cont_encoding_field_name = - { - .field_id = TFE_HTTP_CONT_ENCODING, - .field_name = NULL - }; + { + .field_id = TFE_HTTP_CONT_ENCODING, + .field_name = NULL + }; hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name); } @@ -251,6 +251,13 @@ static int __parser_callback_on_headers_complete(http_parser * parser) hf_public->major_version = parser->http_major; hf_public->minor_version = parser->http_minor; + /* Copy version to session */ + if(hf_private->session != NULL) + { + to_hs_public(hf_private->session)->major_version = hf_public->major_version; + to_hs_public(hf_private->session)->minor_version = hf_public->minor_version; + } + if (hf_direction == TFE_HTTP_REQUEST) { __hf_public_req_fill_from_private(hf_private, parser); @@ -439,14 +446,14 @@ void hf_ops_free(struct tfe_http_half * half) } struct tfe_http_half_ops __http_half_ops = -{ - .ops_http_field_read = hf_ops_field_read, - .ops_http_field_write = hf_ops_field_write, - .ops_http_allow_write = hf_ops_allow_write, - .ops_http_field_iterate = hf_ops_field_iterate, - .ops_append_body = hf_ops_append_body, - .ops_free = hf_ops_free -}; + { + .ops_http_field_read = hf_ops_field_read, + .ops_http_field_write = hf_ops_field_write, + .ops_http_allow_write = hf_ops_allow_write, + .ops_http_field_iterate = hf_ops_field_iterate, + .ops_append_body = hf_ops_append_body, + .ops_free = hf_ops_free + }; struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor) { @@ -526,13 +533,13 @@ int hf_private_parse(struct http_half_private * hf_private, const unsigned char static struct tfe_http_session * hs_ops_allow_write(const struct tfe_http_session * session) { - struct http_session_private * hs_private = to_hs_private((struct tfe_http_session *)session); - return http_frame_currect_plugin_preempt(hs_private->ht_frame) ? (struct tfe_http_session *)session : NULL; + struct http_session_private * hs_private = to_hs_private((struct tfe_http_session *) session); + return http_frame_currect_plugin_preempt(hs_private->ht_frame) == 0 ? (struct tfe_http_session *) session : NULL; } void hs_ops_detach(const struct tfe_http_session * session) { - struct http_session_private * hs_private = to_hs_private((struct tfe_http_session *)session); + struct http_session_private * hs_private = to_hs_private((struct tfe_http_session *) session); return http_frame_currect_plugin_detach(hs_private->ht_frame); } @@ -543,35 +550,108 @@ void hs_ops_drop(struct tfe_http_session * session) void hs_ops_request_set(struct tfe_http_session * session, struct tfe_http_half * req) { - return; + struct http_half_private * hf_private = to_hf_private(req); + struct http_session_private * hs_private = to_hs_private(session); + + assert(hs_private->hf_private_req_user != NULL); + hs_private->hf_private_req_user = hf_private; } void hs_ops_response_set(struct tfe_http_session * session, struct tfe_http_half * resp) { - return; + struct http_half_private * hf_private = to_hf_private(resp); + struct http_session_private * hs_private = to_hs_private(session); + + assert(hs_private->hf_private_resp_user == NULL); + hs_private->hf_private_resp_user = hf_private; } struct tfe_http_half * hs_ops_request_create(struct tfe_http_session * session, enum tfe_http_std_method method, const char * uri) { - return NULL; + struct http_half_private * hf_req_private = hf_private_create(TFE_HTTP_REQUEST, + session->major_version, session->minor_version); + + hf_req_private->method_or_status = method; + hf_req_private->url_storage = tfe_strdup(uri); + hf_req_private->is_setup_by_user = true; + return to_hf_public(hf_req_private); } struct tfe_http_half * hs_ops_response_create(struct tfe_http_session * session, int resp_code) { - return NULL; + struct http_half_private * hf_resp_private = hf_private_create(TFE_HTTP_RESPONSE, + session->major_version, session->minor_version); + + hf_resp_private->method_or_status = resp_code; + hf_resp_private->is_setup_by_user = true; + return to_hf_public(hf_resp_private); } struct tfe_http_session_ops __http_session_ops = + { + .ops_allow_write = hs_ops_allow_write, + .ops_detach = hs_ops_detach, + .ops_drop = hs_ops_drop, + .ops_request_set = hs_ops_request_set, + .ops_response_set = hs_ops_response_set, + .ops_request_create = hs_ops_request_create, + .ops_response_create = hs_ops_response_create + }; + +void __construct_request_line(struct http_half_private * hf_private) { - .ops_allow_write = hs_ops_allow_write, - .ops_detach = hs_ops_detach, - .ops_drop = hs_ops_drop, - .ops_request_set = hs_ops_request_set, - .ops_response_set = hs_ops_response_set, - .ops_request_create = hs_ops_request_create, - .ops_response_create = hs_ops_response_create -}; + +} + +void __construct_response_line(struct http_half_private * hf_private) +{ + enum tfe_http_std_status __resp_code = (enum tfe_http_std_status) hf_private->method_or_status; + const char * __str_resp_code = http_std_status_to_string(__resp_code); + if (__str_resp_code == NULL) + { + __str_resp_code = ""; + } + + evbuffer_add_printf(hf_private->evbuf_raw, "HTTP/%d.%d %d %s\r\n", + hf_private->major, hf_private->minor, __resp_code, __str_resp_code); +} + +void hf_private_construct(struct http_half_private * hf_private) +{ + assert(hf_private->is_setup_by_user); + struct tfe_http_half * hf_public = to_hf_public(hf_private); + + /* Clear the output buffer */ + if (hf_private->evbuf_raw == NULL) + { + hf_private->evbuf_raw = evbuffer_new(); + assert(hf_private->evbuf_raw != NULL); + } + else + { + size_t __buf_length = evbuffer_get_length(hf_private->evbuf_raw); + evbuffer_drain(hf_private->evbuf_raw, __buf_length); + } + + /* HTTP Request/Response first line */ + if (hf_public->direction == TFE_HTTP_REQUEST) __construct_request_line(hf_private); + else __construct_response_line(hf_private); + + /* Headers */ + void * iterator = NULL; + struct http_field_name field_name{}; + + for (const char * str_value = tfe_http_field_iterate(hf_public, &iterator, &field_name); + str_value != NULL; str_value = tfe_http_field_iterate(hf_public, &iterator, &field_name)) + { + const char * str_field = http_field_to_string(&field_name); + evbuffer_add_printf(hf_private->evbuf_raw, "%s: %s\r\n", str_field, str_value); + } + + /* delimitor between header and body */ + evbuffer_add_printf(hf_private->evbuf_raw, "\r\n"); +} struct http_session_private * hs_private_create(struct http_connection_private * hc_private, struct http_half_private * hf_private_req, struct http_half_private * hf_private_resp) @@ -611,11 +691,11 @@ void __write_access_log(struct http_session_private * hs_private) char __str_resp_code[TFE_STRING_MAX]; if (resp_spec) { - snprintf(__str_resp_code, sizeof(__str_resp_code) - 1, "%d", resp_spec->resp_code); + snprintf(__str_resp_code, sizeof(__str_resp_code) - 1, "%d", resp_spec->resp_code); } else { - snprintf(__str_resp_code, sizeof(__str_resp_code) - 1, "%s", "-"); + snprintf(__str_resp_code, sizeof(__str_resp_code) - 1, "%s", "-"); } /* Content Type */ @@ -640,8 +720,8 @@ void hs_private_destory(struct http_session_private * hs_private) free(hs_private); } -void hs_private_hf_private_set(struct http_session_private * hs_private, struct http_half_private * hf, - enum tfe_http_direction direction) +void hs_private_hf_private_set(struct http_session_private * hs_private, + struct http_half_private * hf, enum tfe_http_direction direction) { struct tfe_http_half ** ref_old_half_public; struct http_half_private * old_half_private; diff --git a/plugin/protocol/http/test/test_http_half.cpp b/plugin/protocol/http/test/test_http_half.cpp index 86ad6ab..9d230bd 100644 --- a/plugin/protocol/http/test/test_http_half.cpp +++ b/plugin/protocol/http/test/test_http_half.cpp @@ -60,7 +60,7 @@ void __get_http_request_header_verify_helper(struct http_half_private * hf_priva auto * hf_public_request = &hf_public->req_spec; /* PUBLIC FIELD */ - EXPECT_EQ(hf_public_request->method, TFE_HTTP_GET); + EXPECT_EQ(hf_public_request->method, TFE_HTTP_METHOD_GET); EXPECT_STREQ(hf_public_request->uri, "/gfwlist/gfwlist/master/gfwlist.txt"); EXPECT_STREQ(hf_public_request->url, "raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"); EXPECT_STREQ(hf_public_request->host, "raw.githubusercontent.com"); @@ -317,7 +317,7 @@ void __http_post_header_verify_helper(struct http_half_private * hf_private) auto * hf_public_request = &hf_public->req_spec; /* PUBLIC FIELD */ - EXPECT_EQ(hf_public_request->method, TFE_HTTP_POST); + EXPECT_EQ(hf_public_request->method, TFE_HTTP_METHOD_POST); EXPECT_STREQ(hf_public_request->uri, "/"); EXPECT_STREQ(hf_public_request->url, "qbwup.imtt.qq.com/"); EXPECT_STREQ(hf_public_request->host, "qbwup.imtt.qq.com"); diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index edb79d9..054fe93 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -33,7 +33,8 @@ ExternalProject_Add(libevent PREFIX libevent CONFIGURE_COMMAND PKG_CONFIG_PATH=${OPENSSL_PKGCONFIG_PATH} ./configure --prefix= --disable-shared --disable-samples BUILD_COMMAND make LDFLAGS="-ldl" - BUILD_IN_SOURCE 1) + BUILD_IN_SOURCE 1 + DEPENDS OpenSSL) ExternalProject_Get_Property(libevent INSTALL_DIR) file(MAKE_DIRECTORY ${INSTALL_DIR}/include)