|
|
|
@ -42,22 +42,28 @@ |
|
|
|
|
|
|
|
|
|
#include <grpc/support/alloc.h> |
|
|
|
|
#include <grpc/support/log.h> |
|
|
|
|
#include <grpc/support/string_util.h> |
|
|
|
|
|
|
|
|
|
static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_frame_parser(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_header_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing, int is_continuation); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
|
int is_continuation); |
|
|
|
|
static int init_data_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_rst_stream_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_settings_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_window_update_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_goaway_parser(grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_ping_parser(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_goaway_parser(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing); |
|
|
|
|
static int init_skip_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing, int is_header); |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
|
int is_header); |
|
|
|
|
|
|
|
|
|
static int parse_frame_slice(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
@ -74,23 +80,11 @@ void grpc_chttp2_prepare_to_read( |
|
|
|
|
transport_parsing->next_stream_id = transport_global->next_stream_id; |
|
|
|
|
|
|
|
|
|
/* update the parsing view of incoming window */ |
|
|
|
|
if (transport_parsing->incoming_window != transport_global->incoming_window) { |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( |
|
|
|
|
"parse", transport_parsing, incoming_window, |
|
|
|
|
(gpr_int64)transport_global->incoming_window - |
|
|
|
|
(gpr_int64)transport_parsing->incoming_window); |
|
|
|
|
transport_parsing->incoming_window = transport_global->incoming_window; |
|
|
|
|
} |
|
|
|
|
while (grpc_chttp2_list_pop_incoming_window_updated( |
|
|
|
|
while (grpc_chttp2_list_pop_unannounced_incoming_window_available( |
|
|
|
|
transport_global, transport_parsing, &stream_global, &stream_parsing)) { |
|
|
|
|
stream_parsing->id = stream_global->id; |
|
|
|
|
if (stream_parsing->incoming_window != stream_global->incoming_window) { |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( |
|
|
|
|
"parse", transport_parsing, stream_parsing, incoming_window, |
|
|
|
|
(gpr_int64)stream_global->incoming_window - |
|
|
|
|
(gpr_int64)stream_parsing->incoming_window); |
|
|
|
|
stream_parsing->incoming_window = stream_global->incoming_window; |
|
|
|
|
} |
|
|
|
|
GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing, |
|
|
|
|
incoming_window, stream_global, |
|
|
|
|
unannounced_incoming_window_for_parse); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0); |
|
|
|
@ -101,6 +95,8 @@ void grpc_chttp2_publish_reads( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_chttp2_stream_global *stream_global; |
|
|
|
|
grpc_chttp2_stream_parsing *stream_parsing; |
|
|
|
|
int was_zero; |
|
|
|
|
int is_zero; |
|
|
|
|
|
|
|
|
|
/* transport_parsing->last_incoming_stream_id is used as
|
|
|
|
|
last-grpc_chttp2_stream-id when |
|
|
|
@ -144,98 +140,102 @@ void grpc_chttp2_publish_reads( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* propagate flow control tokens to global state */ |
|
|
|
|
if (transport_parsing->outgoing_window_update) { |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( |
|
|
|
|
"parsed", transport_global, outgoing_window, |
|
|
|
|
transport_parsing->outgoing_window_update); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( |
|
|
|
|
"parsed", transport_parsing, outgoing_window_update, |
|
|
|
|
-(gpr_int64)transport_parsing->outgoing_window_update); |
|
|
|
|
transport_global->outgoing_window += |
|
|
|
|
transport_parsing->outgoing_window_update; |
|
|
|
|
transport_parsing->outgoing_window_update = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (transport_parsing->incoming_window_delta) { |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( |
|
|
|
|
"parsed", transport_global, incoming_window, |
|
|
|
|
-(gpr_int64)transport_parsing->incoming_window_delta); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( |
|
|
|
|
"parsed", transport_parsing, incoming_window_delta, |
|
|
|
|
-(gpr_int64)transport_parsing->incoming_window_delta); |
|
|
|
|
transport_global->incoming_window -= |
|
|
|
|
transport_parsing->incoming_window_delta; |
|
|
|
|
transport_parsing->incoming_window_delta = 0; |
|
|
|
|
was_zero = transport_global->outgoing_window <= 0; |
|
|
|
|
GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window, |
|
|
|
|
transport_parsing, outgoing_window); |
|
|
|
|
is_zero = transport_global->outgoing_window <= 0; |
|
|
|
|
if (was_zero && !is_zero) { |
|
|
|
|
while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, |
|
|
|
|
&stream_global)) { |
|
|
|
|
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (transport_parsing->incoming_window < |
|
|
|
|
transport_global->connection_window_target * 3 / 4) { |
|
|
|
|
gpr_int64 announce_bytes = transport_global->connection_window_target - |
|
|
|
|
transport_parsing->incoming_window; |
|
|
|
|
GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global, |
|
|
|
|
announce_incoming_window, announce_bytes); |
|
|
|
|
GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing, |
|
|
|
|
incoming_window, announce_bytes); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* for each stream that saw an update, fixup global state */ |
|
|
|
|
while (grpc_chttp2_list_pop_parsing_seen_stream( |
|
|
|
|
transport_global, transport_parsing, &stream_global, &stream_parsing)) { |
|
|
|
|
/* update incoming flow control window */ |
|
|
|
|
if (stream_parsing->incoming_window_delta) { |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( |
|
|
|
|
"parsed", transport_parsing, stream_global, incoming_window, |
|
|
|
|
-(gpr_int64)stream_parsing->incoming_window_delta); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( |
|
|
|
|
"parsed", transport_parsing, stream_parsing, incoming_window_delta, |
|
|
|
|
-(gpr_int64)stream_parsing->incoming_window_delta); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( |
|
|
|
|
"parsed", transport_parsing, stream_global, max_recv_bytes, |
|
|
|
|
-(gpr_int64)stream_parsing->incoming_window_delta); |
|
|
|
|
stream_global->incoming_window -= stream_parsing->incoming_window_delta; |
|
|
|
|
GPR_ASSERT(stream_global->max_recv_bytes >= |
|
|
|
|
stream_parsing->incoming_window_delta); |
|
|
|
|
stream_global->max_recv_bytes -= stream_parsing->incoming_window_delta; |
|
|
|
|
stream_parsing->incoming_window_delta = 0; |
|
|
|
|
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); |
|
|
|
|
if (stream_parsing->seen_error) { |
|
|
|
|
stream_global->seen_error = 1; |
|
|
|
|
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* update outgoing flow control window */ |
|
|
|
|
if (stream_parsing->outgoing_window_update) { |
|
|
|
|
int was_zero = stream_global->outgoing_window <= 0; |
|
|
|
|
int is_zero; |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("parsed", transport_parsing, |
|
|
|
|
stream_global, outgoing_window, |
|
|
|
|
stream_parsing->outgoing_window_update); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( |
|
|
|
|
"parsed", transport_parsing, stream_parsing, outgoing_window_update, |
|
|
|
|
-(gpr_int64)stream_parsing->outgoing_window_update); |
|
|
|
|
GPR_ASSERT(stream_parsing->outgoing_window_update <= GPR_UINT32_MAX); |
|
|
|
|
stream_global->outgoing_window += |
|
|
|
|
(gpr_uint32)stream_parsing->outgoing_window_update; |
|
|
|
|
stream_parsing->outgoing_window_update = 0; |
|
|
|
|
is_zero = stream_global->outgoing_window <= 0; |
|
|
|
|
if (was_zero && !is_zero) { |
|
|
|
|
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
was_zero = stream_global->outgoing_window <= 0; |
|
|
|
|
GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global, |
|
|
|
|
outgoing_window, stream_parsing, |
|
|
|
|
outgoing_window); |
|
|
|
|
is_zero = stream_global->outgoing_window <= 0; |
|
|
|
|
if (was_zero && !is_zero) { |
|
|
|
|
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* updating closed status */ |
|
|
|
|
if (stream_parsing->received_close) { |
|
|
|
|
stream_global->read_closed = 1; |
|
|
|
|
grpc_chttp2_list_add_read_write_state_changed(transport_global, |
|
|
|
|
stream_global); |
|
|
|
|
stream_global->max_recv_bytes -= (gpr_uint32)GPR_MIN( |
|
|
|
|
stream_global->max_recv_bytes, stream_parsing->received_bytes); |
|
|
|
|
stream_parsing->received_bytes = 0; |
|
|
|
|
|
|
|
|
|
/* publish incoming stream ops */ |
|
|
|
|
if (stream_global->incoming_frames.tail != NULL) { |
|
|
|
|
stream_global->incoming_frames.tail->is_tail = 0; |
|
|
|
|
} |
|
|
|
|
if (stream_parsing->data_parser.incoming_frames.head != NULL) { |
|
|
|
|
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
grpc_chttp2_incoming_frame_queue_merge( |
|
|
|
|
&stream_global->incoming_frames, |
|
|
|
|
&stream_parsing->data_parser.incoming_frames); |
|
|
|
|
if (stream_global->incoming_frames.tail != NULL) { |
|
|
|
|
stream_global->incoming_frames.tail->is_tail = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!stream_global->published_initial_metadata && |
|
|
|
|
stream_parsing->got_metadata_on_parse[0]) { |
|
|
|
|
stream_parsing->got_metadata_on_parse[0] = 0; |
|
|
|
|
stream_global->published_initial_metadata = 1; |
|
|
|
|
GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, |
|
|
|
|
stream_parsing->metadata_buffer[0], |
|
|
|
|
stream_global->received_initial_metadata); |
|
|
|
|
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
if (!stream_global->published_trailing_metadata && |
|
|
|
|
stream_parsing->got_metadata_on_parse[1]) { |
|
|
|
|
stream_parsing->got_metadata_on_parse[1] = 0; |
|
|
|
|
stream_global->published_trailing_metadata = 1; |
|
|
|
|
GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, |
|
|
|
|
stream_parsing->metadata_buffer[1], |
|
|
|
|
stream_global->received_trailing_metadata); |
|
|
|
|
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (stream_parsing->saw_rst_stream) { |
|
|
|
|
stream_global->cancelled = 1; |
|
|
|
|
stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status( |
|
|
|
|
(grpc_chttp2_error_code)stream_parsing->rst_stream_reason); |
|
|
|
|
if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) { |
|
|
|
|
stream_global->published_cancelled = 1; |
|
|
|
|
if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) { |
|
|
|
|
grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status( |
|
|
|
|
(grpc_chttp2_error_code)stream_parsing->rst_stream_reason); |
|
|
|
|
char *status_details; |
|
|
|
|
gpr_slice slice_details; |
|
|
|
|
gpr_asprintf(&status_details, "Received RST_STREAM err=%d", |
|
|
|
|
stream_parsing->rst_stream_reason); |
|
|
|
|
slice_details = gpr_slice_from_copied_string(status_details); |
|
|
|
|
gpr_free(status_details); |
|
|
|
|
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, |
|
|
|
|
status_code, &slice_details); |
|
|
|
|
} |
|
|
|
|
grpc_chttp2_list_add_read_write_state_changed(transport_global, |
|
|
|
|
stream_global); |
|
|
|
|
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, |
|
|
|
|
1, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* publish incoming stream ops */ |
|
|
|
|
if (stream_parsing->data_parser.incoming_sopb.nops > 0) { |
|
|
|
|
grpc_incoming_metadata_buffer_move_to_referencing_sopb( |
|
|
|
|
&stream_parsing->incoming_metadata, &stream_global->incoming_metadata, |
|
|
|
|
&stream_parsing->data_parser.incoming_sopb); |
|
|
|
|
grpc_sopb_move_to(&stream_parsing->data_parser.incoming_sopb, |
|
|
|
|
&stream_global->incoming_sopb); |
|
|
|
|
grpc_chttp2_list_add_read_write_state_changed(transport_global, |
|
|
|
|
stream_global); |
|
|
|
|
if (stream_parsing->received_close) { |
|
|
|
|
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, |
|
|
|
|
1, 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -363,7 +363,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, |
|
|
|
|
GPR_ASSERT(cur < end); |
|
|
|
|
transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur); |
|
|
|
|
transport_parsing->deframe_state = GRPC_DTS_FRAME; |
|
|
|
|
if (!init_frame_parser(transport_parsing)) { |
|
|
|
|
if (!init_frame_parser(exec_ctx, transport_parsing)) { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (transport_parsing->incoming_stream_id) { |
|
|
|
@ -428,7 +428,8 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, |
|
|
|
|
GPR_UNREACHABLE_CODE(return 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
static int init_frame_parser(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
if (transport_parsing->expect_continuation_stream_id != 0) { |
|
|
|
|
if (transport_parsing->incoming_frame_type != |
|
|
|
|
GRPC_CHTTP2_FRAME_CONTINUATION) { |
|
|
|
@ -445,30 +446,30 @@ static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
transport_parsing->incoming_stream_id); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
return init_header_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_header_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} |
|
|
|
|
switch (transport_parsing->incoming_frame_type) { |
|
|
|
|
case GRPC_CHTTP2_FRAME_DATA: |
|
|
|
|
return init_data_frame_parser(transport_parsing); |
|
|
|
|
return init_data_frame_parser(exec_ctx, transport_parsing); |
|
|
|
|
case GRPC_CHTTP2_FRAME_HEADER: |
|
|
|
|
return init_header_frame_parser(transport_parsing, 0); |
|
|
|
|
return init_header_frame_parser(exec_ctx, transport_parsing, 0); |
|
|
|
|
case GRPC_CHTTP2_FRAME_CONTINUATION: |
|
|
|
|
gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame"); |
|
|
|
|
return 0; |
|
|
|
|
case GRPC_CHTTP2_FRAME_RST_STREAM: |
|
|
|
|
return init_rst_stream_parser(transport_parsing); |
|
|
|
|
return init_rst_stream_parser(exec_ctx, transport_parsing); |
|
|
|
|
case GRPC_CHTTP2_FRAME_SETTINGS: |
|
|
|
|
return init_settings_frame_parser(transport_parsing); |
|
|
|
|
return init_settings_frame_parser(exec_ctx, transport_parsing); |
|
|
|
|
case GRPC_CHTTP2_FRAME_WINDOW_UPDATE: |
|
|
|
|
return init_window_update_frame_parser(transport_parsing); |
|
|
|
|
return init_window_update_frame_parser(exec_ctx, transport_parsing); |
|
|
|
|
case GRPC_CHTTP2_FRAME_PING: |
|
|
|
|
return init_ping_parser(transport_parsing); |
|
|
|
|
return init_ping_parser(exec_ctx, transport_parsing); |
|
|
|
|
case GRPC_CHTTP2_FRAME_GOAWAY: |
|
|
|
|
return init_goaway_parser(transport_parsing); |
|
|
|
|
return init_goaway_parser(exec_ctx, transport_parsing); |
|
|
|
|
default: |
|
|
|
|
gpr_log(GPR_ERROR, "Unknown frame type %02x", |
|
|
|
|
transport_parsing->incoming_frame_type); |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 0); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -482,7 +483,8 @@ static grpc_chttp2_parse_error skip_parser( |
|
|
|
|
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } |
|
|
|
|
|
|
|
|
|
static int init_skip_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing, int is_header) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
|
int is_header) { |
|
|
|
|
if (is_header) { |
|
|
|
|
gpr_uint8 is_eoh = transport_parsing->expect_continuation_stream_id != 0; |
|
|
|
|
transport_parsing->parser = grpc_chttp2_header_parser_parse; |
|
|
|
@ -499,65 +501,51 @@ static int init_skip_frame_parser( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_chttp2_parsing_become_skip_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
init_skip_frame_parser( |
|
|
|
|
transport_parsing, |
|
|
|
|
exec_ctx, transport_parsing, |
|
|
|
|
transport_parsing->parser == grpc_chttp2_header_parser_parse); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_chttp2_parse_error update_incoming_window( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
|
grpc_chttp2_stream_parsing *stream_parsing) { |
|
|
|
|
if (transport_parsing->incoming_frame_size > |
|
|
|
|
transport_parsing->incoming_window) { |
|
|
|
|
gpr_uint32 incoming_frame_size = transport_parsing->incoming_frame_size; |
|
|
|
|
if (incoming_frame_size > transport_parsing->incoming_window) { |
|
|
|
|
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", |
|
|
|
|
transport_parsing->incoming_frame_size, |
|
|
|
|
transport_parsing->incoming_window); |
|
|
|
|
return GRPC_CHTTP2_CONNECTION_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (transport_parsing->incoming_frame_size > |
|
|
|
|
stream_parsing->incoming_window) { |
|
|
|
|
if (incoming_frame_size > stream_parsing->incoming_window) { |
|
|
|
|
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", |
|
|
|
|
transport_parsing->incoming_frame_size, |
|
|
|
|
stream_parsing->incoming_window); |
|
|
|
|
return GRPC_CHTTP2_CONNECTION_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( |
|
|
|
|
"data", transport_parsing, incoming_window, |
|
|
|
|
-(gpr_int64)transport_parsing->incoming_frame_size); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("data", transport_parsing, |
|
|
|
|
incoming_window_delta, |
|
|
|
|
transport_parsing->incoming_frame_size); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( |
|
|
|
|
"data", transport_parsing, stream_parsing, incoming_window, |
|
|
|
|
-(gpr_int64)transport_parsing->incoming_frame_size); |
|
|
|
|
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("data", transport_parsing, stream_parsing, |
|
|
|
|
incoming_window_delta, |
|
|
|
|
transport_parsing->incoming_frame_size); |
|
|
|
|
|
|
|
|
|
transport_parsing->incoming_window -= transport_parsing->incoming_frame_size; |
|
|
|
|
transport_parsing->incoming_window_delta += |
|
|
|
|
transport_parsing->incoming_frame_size; |
|
|
|
|
stream_parsing->incoming_window -= transport_parsing->incoming_frame_size; |
|
|
|
|
stream_parsing->incoming_window_delta += |
|
|
|
|
transport_parsing->incoming_frame_size; |
|
|
|
|
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window, |
|
|
|
|
incoming_frame_size); |
|
|
|
|
GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing, |
|
|
|
|
incoming_window, incoming_frame_size); |
|
|
|
|
stream_parsing->received_bytes += incoming_frame_size; |
|
|
|
|
|
|
|
|
|
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); |
|
|
|
|
|
|
|
|
|
return GRPC_CHTTP2_PARSE_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_data_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_chttp2_stream_parsing *stream_parsing = |
|
|
|
|
grpc_chttp2_parsing_lookup_stream(transport_parsing, |
|
|
|
|
transport_parsing->incoming_stream_id); |
|
|
|
|
grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK; |
|
|
|
|
if (!stream_parsing || stream_parsing->received_close) |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 0); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); |
|
|
|
|
if (err == GRPC_CHTTP2_PARSE_OK) { |
|
|
|
|
err = update_incoming_window(transport_parsing, stream_parsing); |
|
|
|
|
err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing); |
|
|
|
|
} |
|
|
|
|
if (err == GRPC_CHTTP2_PARSE_OK) { |
|
|
|
|
err = grpc_chttp2_data_parser_begin_frame( |
|
|
|
@ -577,7 +565,7 @@ static int init_data_frame_parser( |
|
|
|
|
&transport_parsing->qbuf, |
|
|
|
|
grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, |
|
|
|
|
GRPC_CHTTP2_PROTOCOL_ERROR)); |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 0); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); |
|
|
|
|
case GRPC_CHTTP2_CONNECTION_ERROR: |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
@ -586,11 +574,13 @@ static int init_data_frame_parser( |
|
|
|
|
|
|
|
|
|
static void free_timeout(void *p) { gpr_free(p); } |
|
|
|
|
|
|
|
|
|
static void on_header(void *tp, grpc_mdelem *md) { |
|
|
|
|
static void on_initial_header(void *tp, grpc_mdelem *md) { |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing = tp; |
|
|
|
|
grpc_chttp2_stream_parsing *stream_parsing = |
|
|
|
|
transport_parsing->incoming_stream; |
|
|
|
|
|
|
|
|
|
GPR_TIMER_BEGIN("on_initial_header", 0); |
|
|
|
|
|
|
|
|
|
GPR_ASSERT(stream_parsing); |
|
|
|
|
|
|
|
|
|
GRPC_CHTTP2_IF_TRACING(gpr_log( |
|
|
|
@ -598,6 +588,12 @@ static void on_header(void *tp, grpc_mdelem *md) { |
|
|
|
|
transport_parsing->is_client ? "CLI" : "SVR", |
|
|
|
|
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); |
|
|
|
|
|
|
|
|
|
if (md->key == transport_parsing->elem_grpc_status_ok->key && |
|
|
|
|
md != transport_parsing->elem_grpc_status_ok) { |
|
|
|
|
/* TODO(ctiller): check for a status like " 0" */ |
|
|
|
|
stream_parsing->seen_error = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (md->key == transport_parsing->str_grpc_timeout) { |
|
|
|
|
gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); |
|
|
|
|
if (!cached_timeout) { |
|
|
|
@ -612,24 +608,57 @@ static void on_header(void *tp, grpc_mdelem *md) { |
|
|
|
|
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); |
|
|
|
|
} |
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_set_deadline( |
|
|
|
|
&stream_parsing->incoming_metadata, |
|
|
|
|
&stream_parsing->metadata_buffer[0], |
|
|
|
|
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); |
|
|
|
|
GRPC_MDELEM_UNREF(md); |
|
|
|
|
} else { |
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata, |
|
|
|
|
md); |
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_add( |
|
|
|
|
&stream_parsing->metadata_buffer[0], md); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); |
|
|
|
|
|
|
|
|
|
GPR_TIMER_END("on_initial_header", 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void on_trailing_header(void *tp, grpc_mdelem *md) { |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing = tp; |
|
|
|
|
grpc_chttp2_stream_parsing *stream_parsing = |
|
|
|
|
transport_parsing->incoming_stream; |
|
|
|
|
|
|
|
|
|
GPR_TIMER_BEGIN("on_trailing_header", 0); |
|
|
|
|
|
|
|
|
|
GPR_ASSERT(stream_parsing); |
|
|
|
|
|
|
|
|
|
GRPC_CHTTP2_IF_TRACING(gpr_log( |
|
|
|
|
GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id, |
|
|
|
|
transport_parsing->is_client ? "CLI" : "SVR", |
|
|
|
|
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); |
|
|
|
|
|
|
|
|
|
if (md->key == transport_parsing->elem_grpc_status_ok->key && |
|
|
|
|
md != transport_parsing->elem_grpc_status_ok) { |
|
|
|
|
/* TODO(ctiller): check for a status like " 0" */ |
|
|
|
|
stream_parsing->seen_error = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->metadata_buffer[1], |
|
|
|
|
md); |
|
|
|
|
|
|
|
|
|
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); |
|
|
|
|
|
|
|
|
|
GPR_TIMER_END("on_trailing_header", 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_header_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing, int is_continuation) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, |
|
|
|
|
int is_continuation) { |
|
|
|
|
gpr_uint8 is_eoh = (transport_parsing->incoming_frame_flags & |
|
|
|
|
GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0; |
|
|
|
|
int via_accept = 0; |
|
|
|
|
grpc_chttp2_stream_parsing *stream_parsing; |
|
|
|
|
|
|
|
|
|
/* TODO(ctiller): when to increment header_frames_received? */ |
|
|
|
|
|
|
|
|
|
if (is_eoh) { |
|
|
|
|
transport_parsing->expect_continuation_stream_id = 0; |
|
|
|
|
} else { |
|
|
|
@ -649,7 +678,7 @@ static int init_header_frame_parser( |
|
|
|
|
if (is_continuation) { |
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
"grpc_chttp2_stream disbanded before CONTINUATION received"); |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} |
|
|
|
|
if (transport_parsing->is_client) { |
|
|
|
|
if ((transport_parsing->incoming_stream_id & 1) && |
|
|
|
@ -660,7 +689,7 @@ static int init_header_frame_parser( |
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
"ignoring new grpc_chttp2_stream creation on client"); |
|
|
|
|
} |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} else if (transport_parsing->last_incoming_stream_id > |
|
|
|
|
transport_parsing->incoming_stream_id) { |
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
@ -669,19 +698,19 @@ static int init_header_frame_parser( |
|
|
|
|
"id=%d, new grpc_chttp2_stream id=%d", |
|
|
|
|
transport_parsing->last_incoming_stream_id, |
|
|
|
|
transport_parsing->incoming_stream_id); |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} else if ((transport_parsing->incoming_stream_id & 1) == 0) { |
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
"ignoring grpc_chttp2_stream with non-client generated index %d", |
|
|
|
|
transport_parsing->incoming_stream_id); |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} |
|
|
|
|
stream_parsing = transport_parsing->incoming_stream = |
|
|
|
|
grpc_chttp2_parsing_accept_stream( |
|
|
|
|
transport_parsing, transport_parsing->incoming_stream_id); |
|
|
|
|
exec_ctx, transport_parsing, transport_parsing->incoming_stream_id); |
|
|
|
|
if (stream_parsing == NULL) { |
|
|
|
|
gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"); |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} |
|
|
|
|
via_accept = 1; |
|
|
|
|
} else { |
|
|
|
@ -691,11 +720,21 @@ static int init_header_frame_parser( |
|
|
|
|
if (stream_parsing->received_close) { |
|
|
|
|
gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header"); |
|
|
|
|
transport_parsing->incoming_stream = NULL; |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 1); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} |
|
|
|
|
transport_parsing->parser = grpc_chttp2_header_parser_parse; |
|
|
|
|
transport_parsing->parser_data = &transport_parsing->hpack_parser; |
|
|
|
|
transport_parsing->hpack_parser.on_header = on_header; |
|
|
|
|
switch (stream_parsing->header_frames_received) { |
|
|
|
|
case 0: |
|
|
|
|
transport_parsing->hpack_parser.on_header = on_initial_header; |
|
|
|
|
break; |
|
|
|
|
case 1: |
|
|
|
|
transport_parsing->hpack_parser.on_header = on_trailing_header; |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
gpr_log(GPR_ERROR, "too many header frames received"); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 1); |
|
|
|
|
} |
|
|
|
|
transport_parsing->hpack_parser.on_header_user_data = transport_parsing; |
|
|
|
|
transport_parsing->hpack_parser.is_boundary = is_eoh; |
|
|
|
|
transport_parsing->hpack_parser.is_eof = |
|
|
|
@ -708,7 +747,7 @@ static int init_header_frame_parser( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_window_update_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame( |
|
|
|
|
&transport_parsing->simple.window_update, |
|
|
|
|
transport_parsing->incoming_frame_size, |
|
|
|
@ -722,7 +761,8 @@ static int init_window_update_frame_parser( |
|
|
|
|
return ok; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
static int init_ping_parser(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame( |
|
|
|
|
&transport_parsing->simple.ping, |
|
|
|
|
transport_parsing->incoming_frame_size, |
|
|
|
@ -733,7 +773,7 @@ static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_rst_stream_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame( |
|
|
|
|
&transport_parsing->simple.rst_stream, |
|
|
|
|
transport_parsing->incoming_frame_size, |
|
|
|
@ -741,7 +781,7 @@ static int init_rst_stream_parser( |
|
|
|
|
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( |
|
|
|
|
transport_parsing, transport_parsing->incoming_stream_id); |
|
|
|
|
if (!transport_parsing->incoming_stream) { |
|
|
|
|
return init_skip_frame_parser(transport_parsing, 0); |
|
|
|
|
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); |
|
|
|
|
} |
|
|
|
|
transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; |
|
|
|
|
transport_parsing->parser_data = &transport_parsing->simple.rst_stream; |
|
|
|
@ -749,7 +789,7 @@ static int init_rst_stream_parser( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_goaway_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame( |
|
|
|
|
&transport_parsing->goaway_parser, |
|
|
|
|
transport_parsing->incoming_frame_size, |
|
|
|
@ -760,7 +800,7 @@ static int init_goaway_parser( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_settings_frame_parser( |
|
|
|
|
grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { |
|
|
|
|
int ok; |
|
|
|
|
|
|
|
|
|
if (transport_parsing->incoming_stream_id != 0) { |
|
|
|
@ -806,7 +846,7 @@ static int parse_frame_slice(grpc_exec_ctx *exec_ctx, |
|
|
|
|
} |
|
|
|
|
return 1; |
|
|
|
|
case GRPC_CHTTP2_STREAM_ERROR: |
|
|
|
|
grpc_chttp2_parsing_become_skip_parser(transport_parsing); |
|
|
|
|
grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); |
|
|
|
|
if (stream_parsing) { |
|
|
|
|
stream_parsing->saw_rst_stream = 1; |
|
|
|
|
stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; |
|
|
|
|