diff --git a/plugin/protocol/http/src/http_entry.cpp b/plugin/protocol/http/src/http_entry.cpp index 141d3ff..debc43e 100644 --- a/plugin/protocol/http/src/http_entry.cpp +++ b/plugin/protocol/http/src/http_entry.cpp @@ -416,7 +416,7 @@ enum tfe_stream_action http_connection_entry(const struct tfe_stream * stream, e { hf_private_in->stream_action = hf_private_in->user_stream_action; } - + /* Call user callback, tell user we resume from suspend */ assert(hs_private->resume_tag_singal); hs_private->resume_tag_singal = false; @@ -540,7 +540,6 @@ enum tfe_stream_action http_connection_entry_data(const struct tfe_stream * stre enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme) { struct http_connection_private * ht_conn = (struct http_connection_private *) (*pme); - if (ht_conn->is_preempted == 0) { /* If the server push response before client send request, this must not be HTTP, detach the stream */ diff --git a/plugin/protocol/http2/include/internal/http2_stream.h b/plugin/protocol/http2/include/internal/http2_stream.h index 1c8e675..d406a2d 100644 --- a/plugin/protocol/http2/include/internal/http2_stream.h +++ b/plugin/protocol/http2/include/internal/http2_stream.h @@ -82,6 +82,7 @@ struct h2_stream_data_t{ int spd_set; int spd_valid; int rse_set; + int flag_end; tfe_http_event spd_event; struct http_frame_session_ctx *frame_ctx; diff --git a/plugin/protocol/http2/src/http2_plugin.cpp b/plugin/protocol/http2/src/http2_plugin.cpp index 7576fef..eb27935 100644 --- a/plugin/protocol/http2/src/http2_plugin.cpp +++ b/plugin/protocol/http2/src/http2_plugin.cpp @@ -128,7 +128,6 @@ http2_stream_data(const struct tfe_stream * stream, unsigned int thread_id, struct stream_tap_info_t *tapinfo = (struct stream_tap_info_t *)(*pme); if (tapinfo->preempted == 0){ - if (dir == CONN_DIR_UPSTREAM){ if (len < SET_FRAME_LENGTH){ defer_bytes = SET_FRAME_LENGTH; @@ -146,7 +145,6 @@ http2_stream_data(const struct tfe_stream * stream, unsigned int thread_id, goto finish; } } - if (dir == CONN_DIR_DOWNSTREAM){ /* Protocol Identification, we need 24 bytes at least to tell it is HTTP2 or not */ if (len < MAGIC_FRAME_LENGTH){ diff --git a/plugin/protocol/http2/src/http2_stream.cpp b/plugin/protocol/http2/src/http2_stream.cpp index 73ab8f7..b848fc2 100644 --- a/plugin/protocol/http2/src/http2_stream.cpp +++ b/plugin/protocol/http2/src/http2_stream.cpp @@ -73,22 +73,6 @@ static const struct value_string headers_vals[] = {TFE_HTTP_LAST_MODIFIED, "last-modified"}, }; -/* ACK Header : 0x000x000x000x040x010x000x000x000x00*/ -static uint8_t ackheader[] = { - 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 -}; - -static int ping(const unsigned char *data, size_t len) -{ - if (len >= 8 && - (data[3] == 0x6 && - (data[4] == 0x1 || data[4] == 0x0) && - (data[16] == 0x0 || data[16] == 0x1))){ - return 1; - } - return 0; -} - struct user_event_dispatch { const struct tfe_stream *tf_stream; @@ -803,6 +787,35 @@ nghttp2_client_send(nghttp2_session *session, const uint8_t *data, return (ssize_t)length; } +void nghttp2_disect_goaway(struct tfe_session_info_t *session_info, int server) +{ + unsigned int thread_id = session_info->thread_id; + const struct tfe_stream * stream = session_info->tf_stream; + + struct h2_stream_data_t *h2_stream = NULL; + struct h2_stream_data_t *_h2_stream = NULL; + + TAILQ_FOREACH_SAFE(h2_stream, &session_info->list, next, _h2_stream){ + TAILQ_REMOVE(&session_info->list, h2_stream, next); + if (h2_stream->frame_ctx){ + http_frame_raise_session_end(h2_stream->frame_ctx, stream, &h2_stream->tfe_session, + thread_id); + h2_stream->frame_ctx = NULL; + } + delete_http2_stream_data(h2_stream, session_info->tf_stream, 1); + free(h2_stream); + h2_stream = NULL; + } + if (session_info->as_client && !server){ + nghttp2_session_del(session_info->as_client); + session_info->as_client = NULL; + } + if (session_info->as_server && server){ + nghttp2_session_del(session_info->as_server); + session_info->as_server = NULL; + } +} + static int nghttp2_client_on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, void *user_data) @@ -822,20 +835,21 @@ nghttp2_client_on_frame_recv(nghttp2_session *session, stream_set_id(&session_info->h2_id, frame->hd.stream_id); break; case NGHTTP2_HEADERS: - if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE && - frame->hd.flags & NGHTTP2_FLAG_END_HEADERS){ + if ((frame->headers.cat == NGHTTP2_HCAT_RESPONSE) && + (frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)){ h2_stream = (struct h2_stream_data_t *)nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); if (!h2_stream){ TFE_LOG_ERROR(rt_log_data()->run_log_handle, "Upstream id %d, can't find stream information(addr = %p)", frame->hd.stream_id, session_info); break; } - resp = h2_stream->resp; - suspend_start(h2_stream, resp, session_info->tf_stream); fill_resp_spec_from_handle(h2_stream->resp); + h2_stream->frame_type |= TFE_NGHTTP2_HEADERS; + stream_set_id(&session_info->h2_id, frame->hd.stream_id); + resp->event_cb(resp, EV_HTTP_RESP_HDR, NULL, 0, resp->event_cb_user); if (h2_stream->spd_set){ h2_stream->spd_event = EV_HTTP_RESP_HDR; @@ -846,8 +860,13 @@ nghttp2_client_on_frame_recv(nghttp2_session *session, break; case NGHTTP2_WINDOW_UPDATE: break; + case NGHTTP2_PING: + break; + case NGHTTP2_PRIORITY: + break; case NGHTTP2_GOAWAY: - TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Upstream(as client) control frame goaway"); + nghttp2_disect_goaway(session_info, 1); + TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Up stream control frame goaway"); break; } return 0; @@ -864,12 +883,17 @@ nghttp2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, const unsigned char *data; struct http2_half_private * resp = NULL; + struct tfe_session_info_t *session_info = (struct tfe_session_info_t *)user_data; + struct h2_stream_data_t *h2_stream = (struct h2_stream_data_t *)nghttp2_session_get_stream_user_data(session, stream_id); if (!h2_stream){ TFE_LOG_ERROR(rt_log_data()->run_log_handle, "On data callback can't get downstream information, id = %d", stream_id); goto finish; } + h2_stream->frame_type |= TFE_NGHTTP2_DATA; + stream_set_id(&session_info->h2_id, stream_id); + resp = h2_stream->resp; if (resp->body.gzip != HTTP2_CONTENT_ENCODING_NONE){ ret = inflate_read(input, input_len, &uncompr, &uncompr_len, @@ -907,6 +931,7 @@ nghttp2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, resp->event_cb(resp, EV_HTTP_RESP_END, NULL, 0, resp->event_cb_user); } + resp->body.flags = flags; resp->body_state = MANAGE_STAGE_COMPLETE; resp->message_state = MANAGE_STAGE_COMPLETE; @@ -924,8 +949,9 @@ nghttp2_client_on_stream_close(nghttp2_session *session, int32_t stream_id, struct h2_stream_data_t *h2_stream; struct tfe_session_info_t *session_info = (struct tfe_session_info_t *)user_data; - TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Client stream close stream_id = %d, error_code = %d", - stream_id, error_code); + if (error_code != 0) + TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Up stream abnormal exit, id = %d, error_code = %d", + stream_id, error_code); h2_stream = TAILQ_LIST_FIND(session_info, stream_id); if (!h2_stream) { @@ -944,12 +970,17 @@ nghttp2_client_on_stream_close(nghttp2_session *session, int32_t stream_id, resp->event_cb_user); } } - resp->body.flags = NGHTTP2_FLAG_END_STREAM; resp->body_state = MANAGE_STAGE_COMPLETE; resp->message_state = MANAGE_STAGE_COMPLETE; h2_stream->frame_type |= TFE_NGHTTP2_DATA; stream_set_id(&session_info->h2_id, stream_id); + }else{ + TAILQ_REMOVE(&session_info->list, h2_stream, next); + delete_http2_stream_data(h2_stream, session_info->tf_stream, 1); + free(h2_stream); + h2_stream = NULL; } + return 0; } @@ -977,7 +1008,6 @@ nghttp2_client_on_header(nghttp2_session *session, frame->hd.stream_id, session_info); break; } - //printf("%d, %s %s, %d\n",frame->hd.stream_id, name, value, frame->hd.flags); resp = h2_stream->resp; head = ALLOC(struct header_data, 1); head->nv.name = (uint8_t *)tfe_strdup((const char *)name); @@ -999,8 +1029,7 @@ nghttp2_client_on_header(nghttp2_session *session, headers = &resp->headers; headers->flag = frame->hd.flags; headers_add_tail(headers, head); - h2_stream->frame_type |= TFE_NGHTTP2_HEADERS; - stream_set_id(&session_info->h2_id, frame->hd.stream_id); + break; case NGHTTP2_PUSH_PROMISE: if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) @@ -1185,8 +1214,13 @@ nghttp2_server_on_frame_recv(nghttp2_session *session, break; case NGHTTP2_WINDOW_UPDATE: break; + case NGHTTP2_PING: + break; + case NGHTTP2_PRIORITY: + break; case NGHTTP2_GOAWAY: - TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Control frame goaway"); + nghttp2_disect_goaway(session_info, 0); + TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Down stream control frame goaway"); break; default: break; @@ -1218,8 +1252,10 @@ nghttp2_server_on_stream_close(nghttp2_session *session, int32_t stream_id, if (!h2_stream) { return 0; } - TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "downstream(as server) %d is close, error_code = %d", stream_id, error_code); - return 0; + if (error_code != 0) + TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Down stream abnormal exit, id = %d, error_code = %d", + stream_id, error_code); + return 0; } static int @@ -1423,7 +1459,7 @@ finish: } static enum tfe_stream_action -nghttp2_server_frame_submit_data(struct tfe_session_info_t *session_info, struct h2_stream_data_t **h2_stream, +server_frame_submit_data(struct tfe_session_info_t *session_info, struct h2_stream_data_t **h2_stream, uint16_t *nghttp2_type) { enum tfe_stream_action stream_action = ACTION_FORWARD_DATA; @@ -1437,8 +1473,7 @@ nghttp2_server_frame_submit_data(struct tfe_session_info_t *session_info, struct struct data_t *body = &resp->body; if (body->flags == NGHTTP2_FLAG_END_STREAM && resp->message_state == MANAGE_STAGE_COMPLETE){ - TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Remove stream id(%d), h2_stream addr %p", - (*h2_stream)->stream_id, *h2_stream); + TFE_LOG_DEBUG(rt_log_data()->run_log_handle, "Data stream exit, id = %d", (*h2_stream)->stream_id); TAILQ_REMOVE(&session_info->list, *h2_stream, next); delete_http2_stream_data(*h2_stream, session_info->tf_stream, 1); @@ -1655,7 +1690,7 @@ finish: static enum tfe_stream_action nghttp2_server_frame_submit_header(struct h2_stream_data_t *h2_stream, - uint16_t *nghttp2_type) + uint16_t *nghttp2_type) { enum tfe_stream_action stream_action = ACTION_FORWARD_DATA; @@ -1711,7 +1746,7 @@ finish: return; } -static enum tfe_stream_action +static enum tfe_stream_action __attribute__((__unused__)) nghttp2_server_frame_submit_push_promise(struct tfe_session_info_t *session_info, struct h2_stream_data_t *h2_stream) { @@ -1766,27 +1801,26 @@ nghttp2_server_frame_submit_response(struct tfe_session_info_t *session_info, int rv = -1; nghttp2_nv hdrs[128] = {0}; struct http2_headers *headers = NULL; - struct http2_half_private *resp = NULL; + struct http2_half_private *pangu_resp = NULL; - resp = h2_stream->pangu_resp; - if (resp == NULL) + pangu_resp = h2_stream->pangu_resp; + if (pangu_resp == NULL) return ACTION_FORWARD_DATA; - if (resp->message_state != MANAGE_STAGE_COMPLETE){ + if (pangu_resp->message_state != MANAGE_STAGE_COMPLETE){ session_info->state = 0; return ACTION_DROP_DATA; } - - headers = &resp->headers; + headers = &pangu_resp->headers; if (headers->nvlen <= 0) return ACTION_FORWARD_DATA; - struct data_t *body = &resp->body; + struct data_t *body = &pangu_resp->body; char str_sz_evbuf_body[TFE_STRING_MAX]; snprintf(str_sz_evbuf_body, sizeof(str_sz_evbuf_body) - 1, "%lu", evbuffer_get_length(body->evbuf_body)); const static struct http_field_name __cont_encoding_length_name = {TFE_HTTP_CONT_LENGTH, NULL}; - tfe_http_field_write(&resp->half_public, &__cont_encoding_length_name, str_sz_evbuf_body); + tfe_http_field_write(&pangu_resp->half_public, &__cont_encoding_length_name, str_sz_evbuf_body); nghttp2_data_provider data_prd; data_prd.source.ptr = (void *)body; @@ -1820,7 +1854,7 @@ nghttp2_server_frame_submit(struct tfe_session_info_t *session_info) nghttp2_stream->frame_type &= ~TFE_NGHTTP2_HEADERS; } if (nghttp2_stream->frame_type & TFE_NGHTTP2_DATA){ - stream_action = nghttp2_server_frame_submit_data(session_info, &nghttp2_stream, &nghttp2_stream->frame_type); + stream_action = server_frame_submit_data(session_info, &nghttp2_stream, &nghttp2_stream->frame_type); if (nghttp2_stream) nghttp2_stream->frame_type &= ~TFE_NGHTTP2_DATA; else @@ -1831,7 +1865,11 @@ nghttp2_server_frame_submit(struct tfe_session_info_t *session_info) nghttp2_stream->frame_type &= ~TFE_NGHTTP2_SETTINGS; } if (nghttp2_stream->frame_type & TFE_NGHTTP2_PUSH_PROMISE){ - stream_action = nghttp2_server_frame_submit_push_promise(session_info, nghttp2_stream); + /*Because a data stream contains multiple stream ids, resulting in data drop, + there is no processing of the committed push frame at present. + Under the condition that the main process is not affected, + the committed push frame is not encapsulated ***/ + //stream_action = nghttp2_server_frame_submit_push_promise(session_info, nghttp2_stream); nghttp2_stream->frame_type &= ~TFE_NGHTTP2_PUSH_PROMISE; } if (nghttp2_stream->frame_type & TFE_NGHTTP2_RESPONSE){ @@ -1840,7 +1878,6 @@ nghttp2_server_frame_submit(struct tfe_session_info_t *session_info) } } nghttp2_stream_disable_rid(&session_info->h2_id); - return stream_action; } @@ -1871,14 +1908,6 @@ detect_up_stream_protocol(struct tfe_session_info_t *session_info, const struct int readlen = 0; enum tfe_stream_action stream_action = ACTION_FORWARD_DATA; - if (len >= 9 && !memcmp(data, ackheader, 9)){ - len = 9; - goto finish; - } - - if (len > 9 && !memcmp((data + len - 9), ackheader, 9)){ - len = len - 9; - } readlen = nghttp2_session_mem_recv(session_info->as_client, data, len); if (readlen < 0){ TFE_LOG_ERROR(rt_log_data()->run_log_handle, "Failed to process server requests. Link message %s", @@ -1897,7 +1926,7 @@ detect_up_stream_protocol(struct tfe_session_info_t *session_info, const struct } err: tfe_stream_detach(tfe_stream); -finish: + tfe_stream_action_set_opt(tfe_stream, ACTION_OPT_DROP_BYTES, &len, sizeof(len)); return ACTION_DROP_DATA; } @@ -1912,15 +1941,6 @@ detect_down_stream_protocol(struct tfe_session_info_t *session_info, const struc session_info->tf_stream = tfe_stream; session_info->thread_id = thread_id; - if (len >= 9 && !memcmp(data, ackheader, 9)){ - /** todo: confirmation frames are automatically replied by the local agent, Immediately forward */ - len = 9; - goto finish; - } - - if (len > 9 && !memcmp((data + len - 9), ackheader, 9)){ - len = len - 9; - } readlen = nghttp2_session_mem_recv(session_info->as_server, data, len); if (readlen < 0){ TFE_LOG_ERROR(rt_log_data()->run_log_handle, "Failed to process client requests. Link message %s", @@ -1939,7 +1959,7 @@ detect_down_stream_protocol(struct tfe_session_info_t *session_info, const struc } err: tfe_stream_detach(tfe_stream); -finish: + tfe_stream_action_set_opt(tfe_stream, ACTION_OPT_DROP_BYTES, &len, sizeof(len)); return ACTION_DROP_DATA; } diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index fe5e908..496c74e 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -81,7 +81,7 @@ set_property(TARGET http-parser-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ ExternalProject_Add(nghttp2 PREFIX nghttp2 URL ${CMAKE_CURRENT_SOURCE_DIR}/nghttp2-1.24.0.tar.gz - URL_MD5 d3bf46ac99772d39fa60fa8fd2ab91e5 + URL_MD5 1bf8209fc10da2d46012b03a158e6693 CONFIGURE_COMMAND ./configure --prefix= --disable-shared BUILD_IN_SOURCE 1) diff --git a/vendor/nghttp2-1.24.0.tar.gz b/vendor/nghttp2-1.24.0.tar.gz index 05af0e1..f2eac3e 100644 Binary files a/vendor/nghttp2-1.24.0.tar.gz and b/vendor/nghttp2-1.24.0.tar.gz differ