diff options
Diffstat (limited to 'src/core/lib/transport/chttp2/parsing.c')
-rw-r--r-- | src/core/lib/transport/chttp2/parsing.c | 866 |
1 files changed, 0 insertions, 866 deletions
diff --git a/src/core/lib/transport/chttp2/parsing.c b/src/core/lib/transport/chttp2/parsing.c deleted file mode 100644 index 9ee52f63f2..0000000000 --- a/src/core/lib/transport/chttp2/parsing.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * - * Copyright 2015-2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/lib/transport/chttp2/internal.h" - -#include <string.h> - -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/string_util.h> - -#include "src/core/lib/profiling/timers.h" -#include "src/core/lib/transport/chttp2/http2_errors.h" -#include "src/core/lib/transport/chttp2/status_conversion.h" -#include "src/core/lib/transport/chttp2/timeout_encoding.h" -#include "src/core/lib/transport/static_metadata.h" - -static int init_frame_parser(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing); -static int init_header_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_continuation); -static int init_data_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_rst_stream_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_settings_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_window_update_frame_parser( - 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_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, - gpr_slice slice, int is_last); - -void grpc_chttp2_prepare_to_read( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_parsing *stream_parsing; - - GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0); - - transport_parsing->next_stream_id = transport_global->next_stream_id; - transport_parsing->last_sent_max_table_size = - transport_global->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]; - - /* update the parsing view of incoming window */ - while (grpc_chttp2_list_pop_unannounced_incoming_window_available( - transport_global, transport_parsing, &stream_global, &stream_parsing)) { - 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); -} - -void grpc_chttp2_publish_reads( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - 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 - sending GOAWAY frame. - https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8 - says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream - ID. So, - since we don't have server pushed streams, client should send - GOAWAY last-grpc_chttp2_stream-id=0 in this case. */ - if (!transport_parsing->is_client) { - transport_global->last_incoming_stream_id = - transport_parsing->incoming_stream_id; - } - - /* update global settings */ - if (transport_parsing->settings_updated) { - memcpy(transport_global->settings[GRPC_PEER_SETTINGS], - transport_parsing->settings, sizeof(transport_parsing->settings)); - transport_parsing->settings_updated = 0; - } - - /* update settings based on ack if received */ - if (transport_parsing->settings_ack_received) { - memcpy(transport_global->settings[GRPC_ACKED_SETTINGS], - transport_global->settings[GRPC_SENT_SETTINGS], - GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); - transport_parsing->settings_ack_received = 0; - transport_global->sent_local_settings = 0; - } - - /* move goaway to the global state if we received one (it will be - published later */ - if (transport_parsing->goaway_received) { - grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global, - (uint32_t)transport_parsing->goaway_error, - transport_parsing->goaway_text); - transport_parsing->goaway_text = gpr_empty_slice(); - transport_parsing->goaway_received = 0; - } - - /* propagate flow control tokens to global state */ - 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_become_writable(transport_global, stream_global); - } - } - - if (transport_parsing->incoming_window < - transport_global->connection_window_target * 3 / 4) { - int64_t 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)) { - 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 */ - 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_become_writable(transport_global, stream_global); - } - - stream_global->max_recv_bytes -= (uint32_t)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) { - 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_mark_stream_closed(exec_ctx, transport_global, stream_global, - 1, 1); - } - - if (stream_parsing->received_close) { - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - 1, 0); - } - } -} - -int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice) { - uint8_t *beg = GPR_SLICE_START_PTR(slice); - uint8_t *end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - - if (cur == end) return 1; - - switch (transport_parsing->deframe_state) { - case GRPC_DTS_CLIENT_PREFIX_0: - case GRPC_DTS_CLIENT_PREFIX_1: - case GRPC_DTS_CLIENT_PREFIX_2: - case GRPC_DTS_CLIENT_PREFIX_3: - case GRPC_DTS_CLIENT_PREFIX_4: - case GRPC_DTS_CLIENT_PREFIX_5: - case GRPC_DTS_CLIENT_PREFIX_6: - case GRPC_DTS_CLIENT_PREFIX_7: - case GRPC_DTS_CLIENT_PREFIX_8: - case GRPC_DTS_CLIENT_PREFIX_9: - case GRPC_DTS_CLIENT_PREFIX_10: - case GRPC_DTS_CLIENT_PREFIX_11: - case GRPC_DTS_CLIENT_PREFIX_12: - case GRPC_DTS_CLIENT_PREFIX_13: - case GRPC_DTS_CLIENT_PREFIX_14: - case GRPC_DTS_CLIENT_PREFIX_15: - case GRPC_DTS_CLIENT_PREFIX_16: - case GRPC_DTS_CLIENT_PREFIX_17: - case GRPC_DTS_CLIENT_PREFIX_18: - case GRPC_DTS_CLIENT_PREFIX_19: - case GRPC_DTS_CLIENT_PREFIX_20: - case GRPC_DTS_CLIENT_PREFIX_21: - case GRPC_DTS_CLIENT_PREFIX_22: - case GRPC_DTS_CLIENT_PREFIX_23: - while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) { - if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing - ->deframe_state]) { - gpr_log(GPR_INFO, - "Connect string mismatch: expected '%c' (%d) got '%c' (%d) " - "at byte %d", - GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing - ->deframe_state], - (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING - [transport_parsing->deframe_state], - *cur, (int)*cur, transport_parsing->deframe_state); - return 0; - } - ++cur; - ++transport_parsing->deframe_state; - } - if (cur == end) { - return 1; - } - /* fallthrough */ - dts_fh_0: - case GRPC_DTS_FH_0: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_1; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_1: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_2; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_2: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size |= *cur; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_3; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_3: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_type = *cur; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_4; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_4: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_flags = *cur; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_5; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_5: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_6; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_6: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_7; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_7: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_8; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_8: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur); - transport_parsing->deframe_state = GRPC_DTS_FRAME; - if (!init_frame_parser(exec_ctx, transport_parsing)) { - return 0; - } - if (transport_parsing->incoming_stream_id) { - transport_parsing->last_incoming_stream_id = - transport_parsing->incoming_stream_id; - } - if (transport_parsing->incoming_frame_size == 0) { - if (!parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(), - 1)) { - return 0; - } - transport_parsing->incoming_stream = NULL; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_0; - return 1; - } - goto dts_fh_0; /* loop */ - } - if (++cur == end) { - return 1; - } - /* fallthrough */ - case GRPC_DTS_FRAME: - GPR_ASSERT(cur < end); - if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) { - if (!parse_frame_slice(exec_ctx, transport_parsing, - gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), - (size_t)(end - beg)), - 1)) { - return 0; - } - transport_parsing->deframe_state = GRPC_DTS_FH_0; - transport_parsing->incoming_stream = NULL; - return 1; - } else if ((uint32_t)(end - cur) > - transport_parsing->incoming_frame_size) { - size_t cur_offset = (size_t)(cur - beg); - if (!parse_frame_slice( - exec_ctx, transport_parsing, - gpr_slice_sub_no_ref( - slice, cur_offset, - cur_offset + transport_parsing->incoming_frame_size), - 1)) { - return 0; - } - cur += transport_parsing->incoming_frame_size; - transport_parsing->incoming_stream = NULL; - goto dts_fh_0; /* loop */ - } else { - if (!parse_frame_slice(exec_ctx, transport_parsing, - gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), - (size_t)(end - beg)), - 0)) { - return 0; - } - transport_parsing->incoming_frame_size -= (uint32_t)(end - cur); - return 1; - } - GPR_UNREACHABLE_CODE(return 0); - } - - GPR_UNREACHABLE_CODE(return 0); -} - -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) { - gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x", - transport_parsing->incoming_frame_type); - return 0; - } - if (transport_parsing->expect_continuation_stream_id != - transport_parsing->incoming_stream_id) { - gpr_log(GPR_ERROR, - "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " - "grpc_chttp2_stream %08x", - transport_parsing->expect_continuation_stream_id, - transport_parsing->incoming_stream_id); - return 0; - } - 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(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_HEADER: - 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(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_SETTINGS: - return init_settings_frame_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_WINDOW_UPDATE: - return init_window_update_frame_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_PING: - return init_ping_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_GOAWAY: - 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(exec_ctx, transport_parsing, 0); - } -} - -static grpc_chttp2_parse_error skip_parser( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - return GRPC_CHTTP2_PARSE_OK; -} - -static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } - -static int init_skip_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_header) { - if (is_header) { - uint8_t is_eoh = transport_parsing->expect_continuation_stream_id != 0; - transport_parsing->parser = grpc_chttp2_header_parser_parse; - transport_parsing->parser_data = &transport_parsing->hpack_parser; - transport_parsing->hpack_parser.on_header = skip_header; - transport_parsing->hpack_parser.on_header_user_data = NULL; - transport_parsing->hpack_parser.is_boundary = is_eoh; - transport_parsing->hpack_parser.is_eof = - (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); - } else { - transport_parsing->parser = skip_parser; - } - return 1; -} - -void grpc_chttp2_parsing_become_skip_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - init_skip_frame_parser( - exec_ctx, transport_parsing, - transport_parsing->parser == grpc_chttp2_header_parser_parse); -} - -static grpc_chttp2_parse_error update_incoming_window( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing) { - uint32_t 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 (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_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_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(exec_ctx, transport_parsing, 0); - if (err == GRPC_CHTTP2_PARSE_OK) { - err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing); - } - if (err == GRPC_CHTTP2_PARSE_OK) { - err = grpc_chttp2_data_parser_begin_frame( - &stream_parsing->data_parser, transport_parsing->incoming_frame_flags); - } - switch (err) { - case GRPC_CHTTP2_PARSE_OK: - transport_parsing->incoming_stream = stream_parsing; - transport_parsing->parser = grpc_chttp2_data_parser_parse; - transport_parsing->parser_data = &stream_parsing->data_parser; - return 1; - case GRPC_CHTTP2_STREAM_ERROR: - stream_parsing->received_close = 1; - stream_parsing->saw_rst_stream = 1; - stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; - gpr_slice_buffer_add( - &transport_parsing->qbuf, - grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR)); - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); - case GRPC_CHTTP2_CONNECTION_ERROR: - return 0; - } - GPR_UNREACHABLE_CODE(return 0); -} - -static void free_timeout(void *p) { gpr_free(p); } - -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( - GPR_INFO, "HTTP:%d:HDR:%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 == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { - /* TODO(ctiller): check for a status like " 0" */ - stream_parsing->seen_error = 1; - } - - if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) { - gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); - if (!cached_timeout) { - /* not already parsed: parse it now, and store the result away */ - cached_timeout = gpr_malloc(sizeof(gpr_timespec)); - if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value), - cached_timeout)) { - gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", - grpc_mdstr_as_c_string(md->value)); - *cached_timeout = gpr_inf_future(GPR_TIMESPAN); - } - grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); - } - grpc_chttp2_incoming_metadata_buffer_set_deadline( - &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->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 == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { - /* 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_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_continuation) { - uint8_t 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 { - transport_parsing->expect_continuation_stream_id = - transport_parsing->incoming_stream_id; - } - - if (!is_continuation) { - transport_parsing->header_eof = (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0; - } - - /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */ - stream_parsing = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - if (stream_parsing == NULL) { - if (is_continuation) { - gpr_log(GPR_ERROR, - "grpc_chttp2_stream disbanded before CONTINUATION received"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - if (transport_parsing->is_client) { - if ((transport_parsing->incoming_stream_id & 1) && - transport_parsing->incoming_stream_id < - transport_parsing->next_stream_id) { - /* this is an old (probably cancelled) grpc_chttp2_stream */ - } else { - gpr_log(GPR_ERROR, - "ignoring new grpc_chttp2_stream creation on client"); - } - 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, - "ignoring out of order new grpc_chttp2_stream request on server; " - "last grpc_chttp2_stream " - "id=%d, new grpc_chttp2_stream id=%d", - transport_parsing->last_incoming_stream_id, - transport_parsing->incoming_stream_id); - 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(exec_ctx, transport_parsing, 1); - } - stream_parsing = transport_parsing->incoming_stream = - grpc_chttp2_parsing_accept_stream( - 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(exec_ctx, transport_parsing, 1); - } - via_accept = 1; - } else { - transport_parsing->incoming_stream = stream_parsing; - } - GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1)); - 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(exec_ctx, transport_parsing, 1); - } - transport_parsing->parser = grpc_chttp2_header_parser_parse; - transport_parsing->parser_data = &transport_parsing->hpack_parser; - 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 = - (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); - if (!is_continuation && (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { - grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser); - } - return 1; -} - -static int init_window_update_frame_parser( - 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, - transport_parsing->incoming_frame_flags); - if (transport_parsing->incoming_stream_id) { - transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - } - transport_parsing->parser = grpc_chttp2_window_update_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.window_update; - return ok; -} - -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, - transport_parsing->incoming_frame_flags); - transport_parsing->parser = grpc_chttp2_ping_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.ping; - return ok; -} - -static int init_rst_stream_parser( - 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, - transport_parsing->incoming_frame_flags); - 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(exec_ctx, transport_parsing, 0); - } - transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.rst_stream; - return ok; -} - -static int init_goaway_parser( - 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, - transport_parsing->incoming_frame_flags); - transport_parsing->parser = grpc_chttp2_goaway_parser_parse; - transport_parsing->parser_data = &transport_parsing->goaway_parser; - return ok; -} - -static int init_settings_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - int ok; - - if (transport_parsing->incoming_stream_id != 0) { - gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d", - transport_parsing->incoming_stream_id); - return 0; - } - - ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame( - &transport_parsing->simple.settings, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags, - transport_parsing->settings); - if (!ok) { - return 0; - } - if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { - transport_parsing->settings_ack_received = 1; - grpc_chttp2_hptbl_set_max_bytes( - &transport_parsing->hpack_parser.table, - transport_parsing->last_sent_max_table_size); - } - transport_parsing->parser = grpc_chttp2_settings_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.settings; - return ok; -} - -/* -static int is_window_update_legal(int64_t window_update, int64_t window) { - return window + window_update < MAX_WINDOW; -} -*/ - -static int parse_frame_slice(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice, int is_last) { - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; - switch (transport_parsing->parser(exec_ctx, transport_parsing->parser_data, - transport_parsing, stream_parsing, slice, - is_last)) { - case GRPC_CHTTP2_PARSE_OK: - if (stream_parsing) { - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - } - return 1; - case GRPC_CHTTP2_STREAM_ERROR: - 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; - gpr_slice_buffer_add( - &transport_parsing->qbuf, - grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR)); - } - return 1; - case GRPC_CHTTP2_CONNECTION_ERROR: - return 0; - } - GPR_UNREACHABLE_CODE(return 0); -} |