static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) { grpc_chttp2_transport *t = tp; grpc_chttp2_stream *s = t->incoming_stream; GPR_TIMER_BEGIN("on_initial_header", 0); GPR_ASSERT(s != NULL); GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->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" */ s->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_http2_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( &s->metadata_buffer[0], gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); GRPC_MDELEM_UNREF(md); } else { const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); const size_t metadata_size_limit = t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { gpr_log(GPR_DEBUG, "received initial metadata size exceeds limit (%" PRIuPTR " vs. %" PRIuPTR ")", new_size, metadata_size_limit); grpc_chttp2_cancel_stream( exec_ctx, t, s, grpc_error_set_int( GRPC_ERROR_CREATE("received initial metadata size exceeds limit"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; GRPC_MDELEM_UNREF(md); } else { grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md); } } GPR_TIMER_END("on_initial_header", 0); }
static gpr_uint32 decode_status(grpc_mdelem *md) { gpr_uint32 status; void *user_data = grpc_mdelem_get_user_data(md, destroy_status); if (user_data) { status = ((gpr_uint32)(gpr_intptr) user_data) - STATUS_OFFSET; } else { if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value), GPR_SLICE_LENGTH(md->value->slice), &status)) { status = GRPC_STATUS_UNKNOWN; /* could not parse status code */ } grpc_mdelem_set_user_data(md, destroy_status, (void *)(gpr_intptr)(status + STATUS_OFFSET)); } return status; }
static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { size_t i; grpc_compression_algorithm algorithm; gpr_slice_buffer accept_encoding_parts; gpr_slice accept_encoding_slice; void *accepted_user_data; accepted_user_data = grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer); if (accepted_user_data != NULL) { call->encodings_accepted_by_peer = (gpr_uint32)(((gpr_uintptr)accepted_user_data) - 1); return; } accept_encoding_slice = mdel->value->slice; gpr_slice_buffer_init(&accept_encoding_parts); gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts); /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already * zeroes the whole grpc_call */ /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); for (i = 0; i < accept_encoding_parts.count; i++) { const gpr_slice *accept_encoding_entry_slice = &accept_encoding_parts.slices[i]; if (grpc_compression_algorithm_parse( (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice), GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); } else { char *accept_encoding_entry_str = gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); gpr_log(GPR_ERROR, "Invalid entry in accept encoding metadata: '%s'. Ignoring.", accept_encoding_entry_str); gpr_free(accept_encoding_entry_str); } } gpr_slice_buffer_destroy(&accept_encoding_parts); grpc_mdelem_set_user_data( mdel, destroy_encodings_accepted_by_peer, (void *)(((gpr_uintptr)call->encodings_accepted_by_peer) + 1)); }
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 test_user_data_works(void) { int *ud1; int *ud2; grpc_mdelem *md; LOG_TEST("test_user_data_works"); grpc_init(); ud1 = gpr_malloc(sizeof(int)); *ud1 = 1; ud2 = gpr_malloc(sizeof(int)); *ud2 = 2; md = grpc_mdelem_from_strings("abc", "123"); grpc_mdelem_set_user_data(md, gpr_free, ud1); grpc_mdelem_set_user_data(md, gpr_free, ud2); GPR_ASSERT(grpc_mdelem_get_user_data(md, gpr_free) == ud1); GRPC_MDELEM_UNREF(md); grpc_shutdown(); }
static gpr_uint32 decode_compression(grpc_mdelem *md) { grpc_compression_algorithm algorithm; void *user_data = grpc_mdelem_get_user_data(md, destroy_compression); if (user_data) { algorithm = ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET; } else { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str); assert(0); } grpc_mdelem_set_user_data( md, destroy_compression, (void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET)); } return algorithm; }
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); }
static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem md) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; grpc_chttp2_stream *s = t->incoming_stream; GPR_TIMER_BEGIN("on_initial_header", 0); GPR_ASSERT(s != NULL); if (GRPC_TRACER_ON(grpc_http_trace)) { char *key = grpc_slice_to_c_string(GRPC_MDKEY(md)); char *value = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR", key, value); gpr_free(key); gpr_free(value); } if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { /* TODO(ctiller): check for a status like " 0" */ s->seen_error = true; } if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) { gpr_timespec *cached_timeout = (gpr_timespec *)grpc_mdelem_get_user_data(md, free_timeout); gpr_timespec timeout; if (cached_timeout == NULL) { /* not already parsed: parse it now, and store the result away */ cached_timeout = (gpr_timespec *)gpr_malloc(sizeof(gpr_timespec)); if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) { char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); gpr_free(val); *cached_timeout = gpr_inf_future(GPR_TIMESPAN); } timeout = *cached_timeout; grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); } else { timeout = *cached_timeout; } grpc_chttp2_incoming_metadata_buffer_set_deadline( &s->metadata_buffer[0], gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), timeout)); GRPC_MDELEM_UNREF(exec_ctx, md); } else { const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); const size_t metadata_size_limit = t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { gpr_log(GPR_DEBUG, "received initial metadata size exceeds limit (%" PRIuPTR " vs. %" PRIuPTR ")", new_size, metadata_size_limit); grpc_chttp2_cancel_stream( exec_ctx, t, s, grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING( "received initial metadata size exceeds limit"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; GRPC_MDELEM_UNREF(exec_ctx, md); } else { grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add( exec_ctx, &s->metadata_buffer[0], md); if (error != GRPC_ERROR_NONE) { grpc_chttp2_cancel_stream(exec_ctx, t, s, error); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; GRPC_MDELEM_UNREF(exec_ctx, md); } } } GPR_TIMER_END("on_initial_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 = 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); }