static grpc_error *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; grpc_error *err = transport_parsing->parser( exec_ctx, transport_parsing->parser_data, transport_parsing, stream_parsing, slice, is_last); if (err == GRPC_ERROR_NONE) { if (stream_parsing) { grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } return GRPC_ERROR_NONE; } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) { if (grpc_http_trace) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); grpc_error_free_string(msg); } grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); if (stream_parsing) { stream_parsing->forced_close_error = err; gpr_slice_buffer_add( &transport_parsing->qbuf, grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, GRPC_CHTTP2_PROTOCOL_ERROR, &stream_parsing->stats.outgoing)); } else { GRPC_ERROR_UNREF(err); } } return err; }
static int parse_frame_slice(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(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(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_log(GPR_ERROR, "should never reach here"); abort(); return 0; }
static grpc_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) { char *msg; gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, transport_parsing->incoming_frame_size, transport_parsing->incoming_window); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } if (incoming_frame_size > stream_parsing->incoming_window) { char *msg; gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, transport_parsing->incoming_frame_size, stream_parsing->incoming_window); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } 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_ERROR_NONE; }
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); }
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 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 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 = true; } const size_t new_size = stream_parsing->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md); grpc_chttp2_transport_global *transport_global = &TRANSPORT_FROM_PARSING(transport_parsing)->global; const size_t metadata_size_limit = transport_global->settings[GRPC_LOCAL_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { if (!stream_parsing->exceeded_metadata_size) { gpr_log(GPR_DEBUG, "received trailing metadata size exceeds limit (%" PRIuPTR " vs. %" PRIuPTR ")", new_size, metadata_size_limit); stream_parsing->seen_error = true; stream_parsing->exceeded_metadata_size = true; } GRPC_MDELEM_UNREF(md); } else { 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 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); }
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( 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) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; grpc_chttp2_window_update_parser *p = parser; while (p->byte != 4 && cur != end) { p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte)); cur++; p->byte++; } if (stream_parsing != NULL) { stream_parsing->stats.incoming.framing_bytes += (uint32_t)(end - cur); } if (p->byte == 4) { uint32_t received_update = p->amount; if (received_update == 0 || (received_update & 0x80000000u)) { gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount); return GRPC_CHTTP2_CONNECTION_ERROR; } GPR_ASSERT(is_last); if (transport_parsing->incoming_stream_id != 0) { if (stream_parsing != NULL) { GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing, stream_parsing, outgoing_window, received_update); grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } } else { GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing, outgoing_window, received_update); } } return GRPC_CHTTP2_PARSE_OK; }
static grpc_chttp2_parse_error update_incoming_window( grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing) { if (transport_parsing->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) { 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_list_add_parsing_seen_stream(transport_parsing, stream_parsing); return GRPC_CHTTP2_PARSE_OK; }
static void on_header(void *tp, grpc_mdelem *md) { grpc_chttp2_transport_parsing *transport_parsing = tp; grpc_chttp2_stream_parsing *stream_parsing = transport_parsing->incoming_stream; 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 == transport_parsing->str_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_CLOCK_REALTIME); } grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); } grpc_chttp2_incoming_metadata_buffer_set_deadline( &stream_parsing->incoming_metadata, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), *cached_timeout)); GRPC_MDELEM_UNREF(md); } else { grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata, md); } grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); }
grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *const end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; grpc_chttp2_data_parser *p = parser; gpr_uint32 message_flags = 0; if (is_last && p->is_last_frame) { stream_parsing->received_close = 1; } if (cur == end) { return GRPC_CHTTP2_PARSE_OK; } switch (p->state) { fh_0: case GRPC_CHTTP2_DATA_FH_0: p->frame_type = *cur; switch (p->frame_type) { case 0: p->is_frame_compressed = 0; /* GPR_FALSE */ break; case 1: p->is_frame_compressed = 1; /* GPR_TRUE */ break; default: gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); return GRPC_CHTTP2_STREAM_ERROR; } if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_1; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_1: p->frame_size = ((gpr_uint32)*cur) << 24; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_2; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_2: p->frame_size |= ((gpr_uint32)*cur) << 16; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_3; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_3: p->frame_size |= ((gpr_uint32)*cur) << 8; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_4; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_4: p->frame_size |= ((gpr_uint32)*cur); p->state = GRPC_CHTTP2_DATA_FRAME; ++cur; if (p->is_frame_compressed) { message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } grpc_sopb_add_begin_message(&p->incoming_sopb, p->frame_size, message_flags); /* fallthrough */ case GRPC_CHTTP2_DATA_FRAME: if (cur == end) { grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); if ((gpr_uint32)(end - cur) == p->frame_size) { grpc_sopb_add_slice(&p->incoming_sopb, gpr_slice_sub(slice, cur - beg, end - beg)); p->state = GRPC_CHTTP2_DATA_FH_0; return GRPC_CHTTP2_PARSE_OK; } else if ((gpr_uint32)(end - cur) > p->frame_size) { grpc_sopb_add_slice( &p->incoming_sopb, gpr_slice_sub(slice, cur - beg, cur + p->frame_size - beg)); cur += p->frame_size; goto fh_0; /* loop */ } else { grpc_sopb_add_slice(&p->incoming_sopb, gpr_slice_sub(slice, cur - beg, end - beg)); p->frame_size -= (end - cur); return GRPC_CHTTP2_PARSE_OK; } } gpr_log(GPR_ERROR, "should never reach here"); abort(); return GRPC_CHTTP2_CONNECTION_ERROR; }
grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( 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) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; grpc_chttp2_data_parser *p = parser; uint32_t message_flags; grpc_chttp2_incoming_byte_stream *incoming_byte_stream; if (is_last && p->is_last_frame) { stream_parsing->received_close = 1; } if (cur == end) { return GRPC_CHTTP2_PARSE_OK; } switch (p->state) { fh_0: case GRPC_CHTTP2_DATA_FH_0: p->frame_type = *cur; switch (p->frame_type) { case 0: p->is_frame_compressed = 0; /* GPR_FALSE */ break; case 1: p->is_frame_compressed = 1; /* GPR_TRUE */ break; default: gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); return GRPC_CHTTP2_STREAM_ERROR; } if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_1; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_1: p->frame_size = ((uint32_t)*cur) << 24; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_2; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_2: p->frame_size |= ((uint32_t)*cur) << 16; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_3; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_3: p->frame_size |= ((uint32_t)*cur) << 8; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_4; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_4: p->frame_size |= ((uint32_t)*cur); p->state = GRPC_CHTTP2_DATA_FRAME; ++cur; message_flags = 0; if (p->is_frame_compressed) { message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } p->parsing_frame = incoming_byte_stream = grpc_chttp2_incoming_byte_stream_create( exec_ctx, transport_parsing, stream_parsing, p->frame_size, message_flags, &p->incoming_frames); /* fallthrough */ case GRPC_CHTTP2_DATA_FRAME: if (cur == end) { grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); if ((uint32_t)(end - cur) == p->frame_size) { grpc_chttp2_incoming_byte_stream_push( exec_ctx, p->parsing_frame, gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, 1); p->parsing_frame = NULL; p->state = GRPC_CHTTP2_DATA_FH_0; return GRPC_CHTTP2_PARSE_OK; } else if ((uint32_t)(end - cur) > p->frame_size) { grpc_chttp2_incoming_byte_stream_push( exec_ctx, p->parsing_frame, gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(cur + p->frame_size - beg))); grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, 1); p->parsing_frame = NULL; cur += p->frame_size; goto fh_0; /* loop */ } else { grpc_chttp2_incoming_byte_stream_push( exec_ctx, p->parsing_frame, gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); GPR_ASSERT((size_t)(end - cur) <= p->frame_size); p->frame_size -= (uint32_t)(end - cur); return GRPC_CHTTP2_PARSE_OK; } } GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); }
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 = true; } 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 { const size_t new_size = stream_parsing->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); grpc_chttp2_transport_global *transport_global = &TRANSPORT_FROM_PARSING(transport_parsing)->global; const size_t metadata_size_limit = transport_global->settings[GRPC_LOCAL_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { if (!stream_parsing->exceeded_metadata_size) { gpr_log(GPR_DEBUG, "received initial metadata size exceeds limit (%" PRIuPTR " vs. %" PRIuPTR ")", new_size, metadata_size_limit); stream_parsing->seen_error = true; stream_parsing->exceeded_metadata_size = true; } 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); }