From c8526a2a58ade6afa7019efc342ecdb915d2e44e Mon Sep 17 00:00:00 2001 From: fengweihao Date: Mon, 10 Jun 2019 14:55:12 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E7=AD=96=E7=95=A5=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E4=B8=ADhost=E4=B8=BA=E4=B9=B1=E7=A0=81=202.=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dhttp2=E8=AF=B7=E6=B1=82=E4=BD=93=E6=9B=BF=E6=8D=A2?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E6=97=A0=E6=95=88=203.=E4=BF=AE=E5=A4=8Devbu?= =?UTF-8?q?ffer=5Fpullup=E8=8E=B7=E5=8F=96=E6=95=B0=E6=8D=AE=E9=95=BF?= =?UTF-8?q?=E5=BA=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/protocol/http2/src/http2_stream.cpp | 224 +++++++++++++++------ 1 file changed, 161 insertions(+), 63 deletions(-) diff --git a/plugin/protocol/http2/src/http2_stream.cpp b/plugin/protocol/http2/src/http2_stream.cpp index cf53aa7..182b5d1 100644 --- a/plugin/protocol/http2/src/http2_stream.cpp +++ b/plugin/protocol/http2/src/http2_stream.cpp @@ -144,7 +144,7 @@ tfe_h2_header_modify_field(struct tfe_h2_header *header, nghttp2_nv *hdrs, const struct tfe_h2_field *h2_field = NULL, *peer_h2_field = NULL; TAILQ_FOREACH_SAFE(h2_field, &header->h2_field_list, next, peer_h2_field) - { + { hdrs[nvlen].name = h2_field->nv.name; hdrs[nvlen].namelen = h2_field->nv.namelen; if (filed_value && (0==strcasecmp((const char*)h2_field->nv.name, field_name))) @@ -229,6 +229,10 @@ static nghttp2_session * tfe_h2_stream_get_nghttp2_peer_session(struct tfe_h2_st return (dir==CONN_DIR_UPSTREAM?connection->as_client: connection->as_server); } +static struct tfe_h2_half_private *tfe_h2_stream_get_half(struct tfe_h2_session *h2_session, enum tfe_conn_dir dir) +{ + return (dir==CONN_DIR_UPSTREAM?h2_session->resp: h2_session->req); +} static nghttp2_settings_entry* nghttp2_iv_packet(nghttp2_settings settings, @@ -410,8 +414,18 @@ finish: return xret; } +static void delete_http_req_spec(struct tfe_http_req_spec *req_spec) +{ + if (req_spec->uri) + free((char *)req_spec->uri); + if (req_spec->host) + free((char *)req_spec->host); + if (req_spec->url) + free((char *)req_spec->url); +} + void delete_stream_half_data(struct tfe_h2_half_private **data, - int body_flag) + int body_flag, enum tfe_conn_dir dir) { if (*data){ @@ -427,6 +441,11 @@ void delete_stream_half_data(struct tfe_h2_half_private **data, FREE(&((*data)->url_storage)); delete_nv_packet_data(&((*data)->header)); + if (dir == CONN_DIR_DOWNSTREAM) + { + struct tfe_http_req_spec *req_spec = &((*data)->half_public.req_spec); + delete_http_req_spec(req_spec); + } if((*data)->event_cb_user_deleter != NULL) (*data)->event_cb_user_deleter((*data)->event_cb_user); free(*data); @@ -439,7 +458,7 @@ void h2_half_ops_free(struct tfe_http_half * half) { struct tfe_h2_half_private * h2_private = nghttp2_to_half_private(half); - delete_stream_half_data(&h2_private, 1); + delete_stream_half_data(&h2_private, 1, CONN_DIR_DOWNSTREAM); free(h2_private); h2_private = NULL; @@ -658,8 +677,8 @@ upstream_read_callback(nghttp2_session *session, int32_t stream_id, ssize_t datalen = 0, inputlen=0; struct tfe_h2_payload *to_send_body = (struct tfe_h2_payload *)source->ptr; - if (!to_send_body->evbuf_body || !(input = evbuffer_pullup(to_send_body->evbuf_body, -1)) - || 0==(inputlen = evbuffer_get_length(to_send_body->evbuf_body))) + if (!to_send_body->evbuf_body || 0==(inputlen = evbuffer_get_length(to_send_body->evbuf_body)) + ||!(input = evbuffer_pullup(to_send_body->evbuf_body, MIN(length, inputlen)))) { if ((to_send_body->flags & NGHTTP2_FLAG_END_STREAM) == 0) { @@ -676,7 +695,7 @@ upstream_read_callback(nghttp2_session *session, int32_t stream_id, } static enum tfe_stream_action -nghttp2_server_frame_submit_response(struct tfe_h2_stream *h2_stream_info, +nghttp2_frame_submit_built_resp(struct tfe_h2_stream *h2_stream_info, struct tfe_h2_session *h2_session) { int rv = -1; @@ -721,20 +740,70 @@ nghttp2_server_frame_submit_response(struct tfe_h2_stream *h2_stream_info, } static enum tfe_stream_action -server_frame_submit_data(struct tfe_h2_stream *connection, - struct tfe_h2_session *h2_session, - enum tfe_conn_dir dir) +nghttp2_frame_submit_built_req(struct tfe_h2_stream *h2_stream_info, + struct tfe_h2_session *h2_session) +{ + int32_t stream_id = -1; + struct tfe_h2_header *h2_header = NULL; + struct tfe_h2_half_private *plugin_built_req = h2_session->plugin_built_req; + + if (plugin_built_req->message_state != H2_READ_STATE_COMPLETE){ + return (enum tfe_stream_action)ACTION_USER_DATA; + } + h2_header = &plugin_built_req->header; + if (h2_header->nvlen <= 0) + return ACTION_FORWARD_DATA; + + struct tfe_h2_payload *body = &plugin_built_req->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(&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; + + 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); + + if (stream_id < 0){ + TFE_LOG_ERROR(logger()->handle, "Could not submit request: %s", + nghttp2_strerror(stream_id)); + return ACTION_FORWARD_DATA; + } + delete_nv_packet_data(h2_header); + + return ACTION_DROP_DATA; +} + +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) { enum tfe_stream_action stream_action = ACTION_DROP_DATA; - struct tfe_h2_half_private *resp = (dir == CONN_DIR_UPSTREAM) ? h2_session->resp : h2_session->req; + struct tfe_h2_half_private *h2_half = (dir == CONN_DIR_UPSTREAM) ? h2_session->resp : h2_session->req; nghttp2_session *ngh2_session = tfe_h2_stream_get_nghttp2_session(connection, dir); - if (h2_session->plugin_built_resp){ - stream_action = nghttp2_server_frame_submit_response(connection, h2_session); - }else{ + if (h2_session->plugin_built_resp) + { + stream_action = nghttp2_frame_submit_built_resp(connection, h2_session); + } + else if (h2_session->plugin_built_req) + { + stream_action = nghttp2_frame_submit_built_req(connection, h2_session); + } + else + { int rv = -1; - struct tfe_h2_payload *body = &resp->h2_payload; + struct tfe_h2_payload *body = &h2_half->h2_payload; nghttp2_data_provider upstream_data_provider; upstream_data_provider.source.ptr = (void *)body; @@ -927,9 +996,9 @@ void delete_http2_stream_data(struct tfe_h2_session *h2_session, const struct tfe_stream *tf_stream, int body_flag) { - delete_stream_half_data(&h2_session->req, body_flag); + delete_stream_half_data(&h2_session->req, body_flag, CONN_DIR_DOWNSTREAM); - delete_stream_half_data(&h2_session->resp, body_flag); + delete_stream_half_data(&h2_session->resp, body_flag, CONN_DIR_UPSTREAM); } void nghttp2_disect_goaway(struct tfe_h2_stream *h2_stream_info) @@ -1028,7 +1097,7 @@ nghttp2_submit_frame_window_update(struct tfe_h2_stream *connection,const nghttp } static int -nghttp2_submit_end_header(struct tfe_h2_stream *h2_stream_info, +nghttp2_submit_header_by_not_modify(struct tfe_h2_stream *h2_stream_info, struct tfe_h2_session *h2_session) { int xret = -1; @@ -1064,32 +1133,38 @@ nghttp2_submit_end_header(struct tfe_h2_stream *h2_stream_info, } static int -nghttp2_submit_end_stream_payload(struct tfe_h2_stream *h2_stream_info, - struct tfe_h2_session *h2_session) +nghttp2_submit_complete_data(struct tfe_h2_stream *h2_stream_info, + struct tfe_h2_session *h2_session, enum tfe_conn_dir dir) { int xret = -1; enum tfe_stream_action stream_action = ACTION_DROP_DATA; + + struct tfe_h2_half_private *h2_half = tfe_h2_stream_get_half(h2_session, dir); + nghttp2_session *ngh2_session = tfe_h2_stream_get_nghttp2_session(h2_stream_info, dir); - struct tfe_h2_half_private *resp = h2_session->resp; + + enum tfe_http_event http_body_event = (dir==CONN_DIR_UPSTREAM?EV_HTTP_RESP_BODY_END: EV_HTTP_REQ_BODY_END); + enum tfe_http_event http_event = (dir==CONN_DIR_UPSTREAM?EV_HTTP_RESP_END: EV_HTTP_REQ_END); - if (resp->body_state != H2_READ_STATE_BEGIN){ - if (resp->event_cb) { - resp->event_cb(resp, EV_HTTP_RESP_BODY_END, NULL, 0, - resp->event_cb_user); + if (h2_half->body_state != H2_READ_STATE_BEGIN) + { + if (h2_half->event_cb) { + h2_half->event_cb(h2_half, http_body_event, NULL, 0, + h2_half->event_cb_user); } - if (resp->event_cb) { - resp->event_cb(resp, EV_HTTP_RESP_END, NULL, 0, - resp->event_cb_user); + if (h2_half->event_cb) { + h2_half->event_cb(h2_half, http_event, NULL, 0, + h2_half->event_cb_user); } } - struct tfe_h2_payload *payload = &resp->h2_payload; + struct tfe_h2_payload *payload = &h2_half->h2_payload; payload->flags |= NGHTTP2_FLAG_END_STREAM; - resp->body_state = H2_READ_STATE_COMPLETE; - resp->message_state = H2_READ_STATE_COMPLETE; + h2_half->body_state = H2_READ_STATE_COMPLETE; + h2_half->message_state = H2_READ_STATE_COMPLETE; - stream_action = server_frame_submit_data(h2_stream_info, h2_session, CONN_DIR_UPSTREAM); + stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, CONN_DIR_UPSTREAM); if (stream_action == ACTION_DROP_DATA){ - xret = nghttp2_session_send(h2_stream_info->as_server); + xret = nghttp2_session_send(ngh2_session); if (xret != 0) { stream_action = ACTION_FORWARD_DATA; TFE_LOG_ERROR(logger()->handle, "Fatal upstream send error: %s %d\n",nghttp2_strerror(xret), __LINE__); @@ -1105,28 +1180,26 @@ static int nghttp2_submit_frame_data(struct tfe_h2_stream *h2_stream_info,const nghttp2_frame *frame, enum tfe_conn_dir dir) { - struct tfe_h2_half_private *resp = NULL; struct tfe_h2_session *h2_session = NULL; - if (dir == CONN_DIR_DOWNSTREAM){ - goto finish; + 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;; } + struct tfe_h2_half_private *h2_half = tfe_h2_stream_get_half(h2_session, dir); - if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM){ - h2_session = (struct tfe_h2_session *)nghttp2_session_get_stream_user_data(h2_stream_info->as_client, - frame->hd.stream_id); - if (!h2_session){ - TFE_LOG_ERROR(logger()->handle, "Upstream id %d, can't find stream information(addr = %p)", - frame->hd.stream_id, h2_stream_info); - goto finish; - } - resp = h2_session->resp; - resp->h2_payload.padlen = frame->data.padlen; - if (resp->body_state != H2_READ_STATE_COMPLETE){ - nghttp2_submit_end_stream_payload(h2_stream_info, h2_session); + if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) + { + if (dir == CONN_DIR_UPSTREAM) + h2_half->h2_payload.padlen = frame->data.padlen; + + if (h2_half->body_state != H2_READ_STATE_COMPLETE){ + nghttp2_submit_complete_data(h2_stream_info, h2_session, dir); } } -finish: return 0; } @@ -1459,12 +1532,12 @@ fill_req_spec_from_handle(struct tfe_h2_half_private *half_private) continue; } if (!strncmp((char *)(h2_field->nv.name), ":authority", strlen(":authority"))){ - req_spec->host = (const char *)(h2_field->nv.value); + req_spec->host = tfe_strdup((const char *)(h2_field->nv.value)); urllen += h2_field->nv.valuelen; continue; } if (!strncmp((char *)(h2_field->nv.name), ":path", strlen(":path"))){ - req_spec->uri = (const char*)(h2_field->nv.value); + req_spec->uri = tfe_strdup((const char*)(h2_field->nv.value)); urllen += h2_field->nv.valuelen; continue; } @@ -1516,7 +1589,7 @@ nghttp2_submit_built_response(struct tfe_h2_stream *h2_stream_info, snprintf(value, sizeof(value), "%d", resp->method_or_status); tfe_h2_header_add_field(&resp->header, &field, (const char *)value, 0); - stream_action = nghttp2_server_frame_submit_response(h2_stream_info, h2_session); + 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) { @@ -1571,18 +1644,20 @@ nghttp2_client_frame_submit_header(struct tfe_h2_stream *h2_stream_info, if (req == NULL){ return ACTION_FORWARD_DATA; } - if (h2_session->plugin_built_resp){ + + if (h2_session->plugin_built_resp) + { stream_action = nghttp2_submit_built_response(h2_stream_info, h2_session); return stream_action; } - headers = &req->header; - if (headers->nvlen <= 0){ + if (headers->nvlen <= 0) + { return ACTION_FORWARD_DATA; } /*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); + 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_nv hdrs[headers->nvlen]; @@ -1590,6 +1665,11 @@ nghttp2_client_frame_submit_header(struct tfe_h2_stream *h2_stream_info, method = nghttp2_get_method(h2_session->req); if (method == (enum tfe_http_std_method)NGHTTP2_METHOD_POST || method == (enum tfe_http_std_method)NGHTTP2_METHOD_PUT){ + if (h2_session->plugin_built_req) + { + stream_action = (enum tfe_stream_action)ACTION_USER_DATA; + return stream_action; + } stream_id = nghttp2_submit_headers(h2_stream_info->as_client, headers->flag, -1, NULL, tfe_h2_header_modify_field(headers, hdrs, ":path", req->url_storage), headers->nvlen, h2_session); @@ -1796,7 +1876,7 @@ nghttp2_on_stream_close(nghttp2_session *session, const nghttp2_frame *frame, co if (error_code == 0 && resp->body_state != H2_READ_STATE_COMPLETE){ if (resp->body_state == H2_READ_STATE_BEGIN && h2_stream_info->stream_action != ACTION_DEFER_DATA) - nghttp2_submit_end_header(h2_stream_info, h2_session); + nghttp2_submit_header_by_not_modify(h2_stream_info, h2_session); goto end; } finish: @@ -1915,7 +1995,7 @@ nghttp2_client_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, } if (uncompr_len) FREE(&uncompr); - stream_action = server_frame_submit_data(h2_stream_info, h2_session, CONN_DIR_UPSTREAM); + stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, CONN_DIR_UPSTREAM); if (stream_action == ACTION_DROP_DATA){ xret = nghttp2_session_send(h2_stream_info->as_server); if (xret != 0) { @@ -2209,9 +2289,32 @@ nghttp2_server_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, data = input; len = input_len; /*todo post data scan**/ + if (req->body_state == H2_READ_STATE_BEGIN){ + if (req->event_cb) { + req->event_cb(req, EV_HTTP_REQ_BODY_BEGIN, NULL, len, + req->event_cb_user); + } + if (flags == NGHTTP2_FLAG_END_STREAM){ + req->h2_payload.flags = 0; + }else{ + req->h2_payload.flags = flags; + } + req->body_state = H2_READ_STATE_READING; + } + if (req->body_state == H2_READ_STATE_READING){ + if (req->event_cb) { + req->event_cb(req, EV_HTTP_REQ_BODY_CONT, data, len, + req->event_cb_user); + } + if (flags == NGHTTP2_FLAG_END_STREAM){ + req->h2_payload.flags = 0; + }else{ + req->h2_payload.flags = flags; + } + } if (uncompr_len) FREE(&uncompr); - stream_action = server_frame_submit_data(h2_stream_info, h2_session, CONN_DIR_DOWNSTREAM); + stream_action = nghttp2_submit_data_by_h2_half(h2_stream_info, h2_session, CONN_DIR_DOWNSTREAM); if (stream_action == ACTION_DROP_DATA){ xret = nghttp2_session_send(h2_stream_info->as_client); if (xret != 0) { @@ -2219,11 +2322,6 @@ nghttp2_server_on_data_chunk_recv(nghttp2_session *session, uint8_t flags, TFE_LOG_ERROR(logger()->handle, "Fatal upstream send error: %s, %d\n",nghttp2_strerror(xret), __LINE__); } } - - #ifdef TFE_LOG_HTTP2 - TFE_LOG_INFO(logger()->handle, "%s, %d, submit data %d, stream_id:%d, action:%d", h2_stream_info->tf_stream->str_stream_info, - 0, (int)input_len, stream_id, h2_stream_info->stream_action); - #endif if (stream_action == ACTION_USER_DATA) stream_action = ACTION_DROP_DATA; h2_stream_info->stream_action = stream_action;