diff --git a/plugin/protocol/http2/src/http2_stream.cpp b/plugin/protocol/http2/src/http2_stream.cpp index 93ed2da..2f70b61 100644 --- a/plugin/protocol/http2/src/http2_stream.cpp +++ b/plugin/protocol/http2/src/http2_stream.cpp @@ -171,6 +171,20 @@ headers_init(struct tfe_h2_header *header) TAILQ_INIT(&header->h2_field_list); } +const char * method_idx_to_str(int encode) +{ + switch (encode) + { + case HTTP2_CONTENT_ENCODING_GZIP: return "gzip"; + case HTTP2_CONTENT_ENCODING_X_GZIP: return "x-gzip"; + case HTTP2_CONTENT_ENCODING_DEFLATE: return "deflate"; + case HTTP2_CONTENT_ENCODING_BZIP2: return "bzip2"; + case HTTP2_CONTENT_ENCODING_X_BZIP2: return "x-bzip2"; + case HTTP2_CONTENT_ENCODING_BR: return "br"; + default: return ""; + } +} + static int method_to_str_idx(const char * method) { @@ -712,7 +726,8 @@ upstream_read_callback(nghttp2_session *session, int32_t stream_id, static enum tfe_stream_action nghttp2_frame_submit_built_resp(struct tfe_h2_stream *h2_stream_info, - struct tfe_h2_session *h2_session) + struct tfe_h2_session *h2_session, + nghttp2_data_provider *data_prd) { int rv = -1; struct tfe_h2_header *h2_header = NULL; @@ -725,28 +740,32 @@ nghttp2_frame_submit_built_resp(struct tfe_h2_stream *h2_stream_info, } h2_header = &pangu_resp->header; if (h2_header->nvlen <= 0) + { return ACTION_FORWARD_DATA; - + } struct tfe_h2_payload *body = &pangu_resp->h2_payload; body->flags |= NGHTTP2_FLAG_END_STREAM; 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 encoding_field = {TFE_HTTP_CONT_LENGTH, NULL}; - tfe_http_field_write(&pangu_resp->half_public, &encoding_field, str_sz_evbuf_body); + const static struct http_field_name cont_field = {TFE_HTTP_CONT_LENGTH, NULL}; + tfe_http_field_write(&pangu_resp->half_public, &cont_field, str_sz_evbuf_body); - nghttp2_data_provider data_prd; - data_prd.source.ptr = (void *)body; - data_prd.read_callback = upstream_read_callback; + if (body->gzip != HTTP2_CONTENT_ENCODING_NONE) + { + const static struct http_field_name encoding_field = {TFE_HTTP_CONT_ENCODING, NULL}; + const char *content_encoding = method_idx_to_str(body->gzip); + tfe_http_field_write(&pangu_resp->half_public, &encoding_field, content_encoding); + } + + data_prd->source.ptr = (void *)body; + data_prd->read_callback = upstream_read_callback; nghttp2_nv hdrs[h2_header->nvlen]; /*Adapt Http uri Settings**/ - tfe_http_field_write(&pangu_resp->half_public, &encoding_field, str_sz_evbuf_body); - - rv = nghttp2_submit_response(h2_stream_info->as_server, h2_session->ngh2_stream_id, tfe_h2_header_convert_nv(h2_header, hdrs), - h2_header->nvlen, &data_prd); + h2_header->nvlen, data_prd); if (rv != 0){ return ACTION_FORWARD_DATA; } @@ -757,7 +776,8 @@ nghttp2_frame_submit_built_resp(struct tfe_h2_stream *h2_stream_info, static enum tfe_stream_action nghttp2_frame_submit_built_req(struct tfe_h2_stream *h2_stream_info, - struct tfe_h2_session *h2_session) + struct tfe_h2_session *h2_session, + nghttp2_data_provider *data_prd) { int32_t stream_id = -1; struct tfe_h2_header *h2_header = NULL; @@ -778,15 +798,14 @@ nghttp2_frame_submit_built_req(struct tfe_h2_stream *h2_stream_info, const static struct http_field_name encoding_field = {TFE_HTTP_CONT_LENGTH, NULL}; tfe_http_field_write(&plugin_built_req->half_public, &encoding_field, str_sz_evbuf_body); - nghttp2_data_provider data_prd; - data_prd.source.ptr = (void *)body; - data_prd.read_callback = upstream_read_callback; + data_prd->source.ptr = (void *)body; + data_prd->read_callback = upstream_read_callback; nghttp2_nv hdrs[h2_header->nvlen]; /*Adapt Http uri Settings**/ stream_id = nghttp2_submit_request(h2_stream_info->as_client, NULL, tfe_h2_header_modify_field(h2_header, hdrs, ":path", plugin_built_req->url_storage), - h2_header->nvlen, &data_prd, h2_session); + h2_header->nvlen, data_prd, h2_session); if (stream_id < 0){ TFE_LOG_ERROR(logger()->handle, "Could not submit request: %s", @@ -800,8 +819,9 @@ nghttp2_frame_submit_built_req(struct tfe_h2_stream *h2_stream_info, static enum tfe_stream_action nghttp2_submit_data_by_h2_half(struct tfe_h2_stream *connection, - struct tfe_h2_session *h2_session, - enum tfe_conn_dir dir) + struct tfe_h2_session *h2_session, + nghttp2_data_provider *data_provider, + enum tfe_conn_dir dir) { enum tfe_stream_action stream_action = ACTION_DROP_DATA; @@ -810,23 +830,21 @@ nghttp2_submit_data_by_h2_half(struct tfe_h2_stream *connection, if (h2_session->plugin_built_resp) { - stream_action = nghttp2_frame_submit_built_resp(connection, h2_session); + stream_action = nghttp2_frame_submit_built_resp(connection, h2_session, data_provider); } else if (h2_session->plugin_built_req) { - stream_action = nghttp2_frame_submit_built_req(connection, h2_session); + stream_action = nghttp2_frame_submit_built_req(connection, h2_session, data_provider); } else { int rv = -1; struct tfe_h2_payload *body = &h2_half->h2_payload; - - nghttp2_data_provider upstream_data_provider; - upstream_data_provider.source.ptr = (void *)body; - upstream_data_provider.read_callback = upstream_read_callback; + data_provider->source.ptr = (void *)body; + data_provider->read_callback = upstream_read_callback; rv = nghttp2_submit_data(ngh2_session, body->flags, - h2_session->ngh2_stream_id, &upstream_data_provider); + h2_session->ngh2_stream_id, data_provider); if (rv != 0){ stream_action = ACTION_FORWARD_DATA; //printf("Fatal server submit data error: %s\n", nghttp2_strerror(rv)); @@ -1178,7 +1196,10 @@ nghttp2_submit_complete_data(struct tfe_h2_stream *h2_stream_info, h2_half->body_state = H2_READ_STATE_COMPLETE; h2_half->message_state = H2_READ_STATE_COMPLETE; - stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, CONN_DIR_UPSTREAM); + /*registeredSend data**/ + nghttp2_data_provider *data_provider; + data_provider = ALLOC(nghttp2_data_provider, 1); + stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, data_provider, CONN_DIR_UPSTREAM); if (stream_action == ACTION_DROP_DATA){ xret = nghttp2_session_send(ngh2_session); if (xret != 0) { @@ -1188,6 +1209,8 @@ nghttp2_submit_complete_data(struct tfe_h2_stream *h2_stream_info, } if (stream_action == ACTION_USER_DATA) stream_action = ACTION_DROP_DATA; + free(data_provider); + data_provider = NULL; h2_stream_info->stream_action = stream_action; return 1; } @@ -1201,9 +1224,7 @@ nghttp2_submit_frame_data(struct tfe_h2_stream *h2_stream_info,const nghttp2_fra h2_session = TAILQ_LIST_FIND(h2_stream_info, frame->hd.stream_id); if (NULL == h2_session) { - TFE_LOG_ERROR(logger()->handle, "id %d, can't find stream information(addr = %p)", - frame->hd.stream_id, h2_stream_info); - return 0;; + return 0; } struct tfe_h2_half_private *h2_half = tfe_h2_stream_get_half(h2_session, dir); @@ -1410,7 +1431,7 @@ fill_resp_spec_from_handle(struct tfe_h2_half_private *half_private) } int -nghttp2_headers_write_log(struct tfe_h2_session *h2_session, const char * str_stream_info, +nghttp2_write_log(struct tfe_h2_session *h2_session, const char * str_stream_info, int dir) { /* Request */ @@ -1451,6 +1472,47 @@ nghttp2_headers_write_log(struct tfe_h2_session *h2_session, const char * str_st return 0; } +static enum tfe_stream_action +nghttp2_submit_built_response(struct tfe_h2_stream *h2_stream_info, + struct tfe_h2_session *h2_session) +{ + int xret = -1; + char value[128] = {0}; + enum tfe_stream_action stream_action = ACTION_FORWARD_DATA; + struct tfe_h2_half_private *resp = h2_session->plugin_built_resp; + + struct http_field_name field; + field.field_id = TFE_HTTP_UNKNOWN_FIELD; + field.field_name = "X-TG-Construct-By"; + snprintf(value, sizeof(value), "tfe/%s", tfe_version()); + tfe_h2_header_add_field(&resp->header, &field, (const char *)value, 0); + + field.field_id = TFE_HTTP_UNKNOWN_FIELD; + field.field_name = ":status"; + snprintf(value, sizeof(value), "%d", resp->method_or_status); + tfe_h2_header_add_field(&resp->header, &field, (const char *)value, 0); + + nghttp2_data_provider *data_prd; + data_prd = ALLOC(nghttp2_data_provider, 1); + stream_action = nghttp2_frame_submit_built_resp(h2_stream_info, h2_session, data_prd); + if (stream_action == ACTION_DROP_DATA) + { + xret = nghttp2_session_send(h2_stream_info->as_server); + if (xret != 0) { + stream_action = ACTION_FORWARD_DATA; + TFE_LOG_ERROR(logger()->handle, "Fatal downstream send error: %s\n", + nghttp2_strerror(xret)); + } + } + if (stream_action == ACTION_DROP_DATA) + { + stream_action = (enum tfe_stream_action)ACTION_USER_DATA; + } + free(data_prd); + data_prd = NULL; + return stream_action; +} + static enum tfe_stream_action nghttp2_server_frame_submit_header(struct tfe_h2_stream *h2_stream_info, struct tfe_h2_session *h2_session) @@ -1461,7 +1523,14 @@ nghttp2_server_frame_submit_header(struct tfe_h2_stream *h2_stream_info, enum tfe_stream_action stream_action = ACTION_DROP_DATA; if (h2_session->plugin_built_resp != NULL){ - stream_action = (enum tfe_stream_action)ACTION_USER_DATA; + struct tfe_h2_payload *h2_payload = &(h2_session->plugin_built_resp->h2_payload); + if (h2_payload->evbuf_body != NULL && (evbuffer_get_length(h2_payload->evbuf_body) > 0)) + { + stream_action = nghttp2_submit_built_response(h2_stream_info, h2_session); + } + else{ + stream_action = (enum tfe_stream_action)ACTION_USER_DATA; + } return stream_action; } resp = h2_session->resp; @@ -1517,7 +1586,7 @@ nghttp2_server_submit_header(struct tfe_h2_stream *h2_stream_info, int32_t strea stream_action = ACTION_DEFER_DATA; goto finish; } - nghttp2_headers_write_log(h2_session,h2_stream_info->tf_stream->str_stream_info, CONN_DIR_UPSTREAM); + nghttp2_write_log(h2_session,h2_stream_info->tf_stream->str_stream_info, CONN_DIR_UPSTREAM); stream_action = nghttp2_server_frame_submit_header(h2_stream_info, h2_session); if (stream_action == ACTION_DROP_DATA){ @@ -1558,8 +1627,7 @@ fill_req_spec_from_handle(struct tfe_h2_half_private *half_private) continue; } } - char *urltmp = half_private->url_storage; - urltmp = (char *)malloc(urllen + 1); + char *urltmp = ALLOC(char, urllen + 1); if(urltmp){ sprintf(urltmp, "%s%s", (char *)req_spec->host, (char *)req_spec->uri); req_spec->url = urltmp; @@ -1585,41 +1653,6 @@ suspend_stop(struct tfe_h2_session *h2_session, } #endif -static enum tfe_stream_action -nghttp2_submit_built_response(struct tfe_h2_stream *h2_stream_info, - struct tfe_h2_session *h2_session) -{ - int xret = -1; - char value[128] = {0}; - enum tfe_stream_action stream_action = ACTION_FORWARD_DATA; - struct tfe_h2_half_private *resp = h2_session->plugin_built_resp; - - struct http_field_name field; - field.field_id = TFE_HTTP_UNKNOWN_FIELD; - field.field_name = "X-TG-Construct-By"; - snprintf(value, sizeof(value), "tfe/%s", tfe_version()); - tfe_h2_header_add_field(&resp->header, &field, (const char *)value, 0); - - field.field_id = TFE_HTTP_UNKNOWN_FIELD; - field.field_name = ":status"; - snprintf(value, sizeof(value), "%d", resp->method_or_status); - tfe_h2_header_add_field(&resp->header, &field, (const char *)value, 0); - - stream_action = nghttp2_frame_submit_built_resp(h2_stream_info, h2_session); - if (stream_action == ACTION_DROP_DATA){ - xret = nghttp2_session_send(h2_stream_info->as_server); - if (xret != 0) { - stream_action = ACTION_FORWARD_DATA; - TFE_LOG_ERROR(logger()->handle, "Fatal downstream send error: %s\n", - nghttp2_strerror(xret)); - } - } - if (stream_action == ACTION_DROP_DATA){ - stream_action = (enum tfe_stream_action)ACTION_USER_DATA; - } - return stream_action; -} - static void downstream_create_resp(struct tfe_h2_session *h2_session, nghttp2_session *as_client, nghttp2_session *as_server, const struct tfe_stream *tf_stream, unsigned int thread_id) @@ -1663,7 +1696,7 @@ nghttp2_client_frame_submit_header(struct tfe_h2_stream *h2_stream_info, /*Create C' half_private_resp**/ downstream_create_resp(h2_session, h2_stream_info->as_client, h2_stream_info->as_server, h2_stream_info->tf_stream, h2_stream_info->thread_id); - nghttp2_session_set_next_stream_id(h2_stream_info->as_client, h2_session->ngh2_stream_id); + //nghttp2_session_set_next_stream_id(h2_stream_info->as_client, h2_session->ngh2_stream_id); if (h2_session->plugin_built_resp) { @@ -1726,7 +1759,7 @@ nghttp2_client_submit_header(struct tfe_h2_stream *h2_stream_info, int32_t strea req->event_cb(req, EV_HTTP_REQ_HDR, NULL, 0, req->event_cb_user); - nghttp2_headers_write_log(h2_session, h2_stream_info->tf_stream->str_stream_info, CONN_DIR_DOWNSTREAM); + nghttp2_write_log(h2_session, h2_stream_info->tf_stream->str_stream_info, CONN_DIR_DOWNSTREAM); stream_action = nghttp2_client_frame_submit_header(h2_stream_info, h2_session); if (stream_action == ACTION_DROP_DATA){ xret = nghttp2_session_send(h2_stream_info->as_client); @@ -1963,13 +1996,19 @@ nghttp2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, struct tfe_h2_stream *h2_stream_info = (struct tfe_h2_stream *)user_data; - struct tfe_h2_session *h2_session = (struct tfe_h2_session *)nghttp2_session_get_stream_user_data(session, stream_id); - if (!h2_session){ - TFE_LOG_ERROR(logger()->handle, "On data callback can't get downstream information, id = %d", - stream_id); - goto finish; + /*proc build resp*/ + struct tfe_h2_session *h2_session = TAILQ_LIST_FIND(h2_stream_info, stream_id); + if (NULL == h2_session) + { + h2_stream_info->stream_action = ACTION_DROP_DATA; + return 0; } resp = h2_session->resp; + if (resp == NULL){ + h2_stream_info->stream_action = ACTION_DROP_DATA; + return 0; + } + evbuffer_add(resp->h2_payload.evbuf_body, input, input_len); if (resp->h2_payload.gzip != HTTP2_CONTENT_ENCODING_NONE){ @@ -2011,7 +2050,10 @@ nghttp2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, } if (uncompr_len) FREE(&uncompr); - stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, CONN_DIR_UPSTREAM); + + nghttp2_data_provider *data_provider = NULL; + data_provider = ALLOC(nghttp2_data_provider, 1); + stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, data_provider, CONN_DIR_UPSTREAM); if (stream_action == ACTION_DROP_DATA){ xret = nghttp2_session_send(h2_stream_info->as_server); if (xret != 0) { @@ -2019,15 +2061,11 @@ nghttp2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, TFE_LOG_ERROR(logger()->handle, "Fatal upstream(%d) send error: %s\n",stream_id, nghttp2_strerror(xret)); } } - - #ifdef TFE_LOG_HTTP2 - TFE_LOG_DEBUG(logger()->handle, "%s, 1, submit data %d, stream_id:%d, action:%d", h2_stream_info->tf_stream->str_stream_info, - (int)input_len, stream_id, stream_action); - #endif if (stream_action == ACTION_USER_DATA) stream_action = ACTION_DROP_DATA; + free(data_provider); + data_provider = NULL; h2_stream_info->stream_action = stream_action; -finish: return 0; } @@ -2330,7 +2368,9 @@ nghttp2_server_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, } if (uncompr_len) FREE(&uncompr); - stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, CONN_DIR_DOWNSTREAM); + nghttp2_data_provider *data_provider; + data_provider = ALLOC(nghttp2_data_provider, 1); + stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, data_provider, CONN_DIR_DOWNSTREAM); if (stream_action == ACTION_DROP_DATA){ xret = nghttp2_session_send(h2_stream_info->as_client); if (xret != 0) { @@ -2340,6 +2380,8 @@ nghttp2_server_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, } if (stream_action == ACTION_USER_DATA) stream_action = ACTION_DROP_DATA; + free(data_provider); + data_provider = NULL; h2_stream_info->stream_action = stream_action; finish: return 0; @@ -2402,6 +2444,12 @@ delete_server_session_data(struct tfe_h2_stream *h2_stream_info) TAILQ_FOREACH_SAFE(h2_session, &h2_stream_info->h2_session_list, next, peer_h2_stream) { TAILQ_REMOVE(&h2_stream_info->h2_session_list, h2_session, next); + if (h2_session->frame_ctx){ + http_frame_raise_session_end(h2_session->frame_ctx, h2_stream_info->tf_stream, &h2_session->tfe_session, + h2_stream_info->thread_id); + h2_session->frame_ctx = NULL; + } + delete_http2_stream_data(h2_session, h2_stream_info->tf_stream, 1); free(h2_session); h2_session = NULL; } @@ -2418,6 +2466,12 @@ delete_client_session_data(struct tfe_h2_stream *h2_stream_info) TAILQ_FOREACH_SAFE(h2_session, &h2_stream_info->h2_session_list, next, peer_h2_stream){ TAILQ_REMOVE(&h2_stream_info->h2_session_list, h2_session, next); + if (h2_session->frame_ctx){ + http_frame_raise_session_end(h2_session->frame_ctx, h2_stream_info->tf_stream, &h2_session->tfe_session, + h2_stream_info->thread_id); + h2_session->frame_ctx = NULL; + } + delete_http2_stream_data(h2_session, h2_stream_info->tf_stream, 1); free(h2_session); h2_session = NULL; }