pull/7793/head
Craig Tiller 9 years ago
parent 49c644ca6a
commit 31375ac49c
  1. 41
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  2. 431
      src/core/ext/transport/chttp2/transport/hpack_parser.c
  3. 8
      src/core/ext/transport/chttp2/transport/hpack_parser.h
  4. 6
      src/core/ext/transport/chttp2/transport/internal.h
  5. 28
      src/core/ext/transport/chttp2/transport/parsing.c
  6. 9
      test/core/transport/chttp2/hpack_parser_fuzzer_test.c
  7. 6
      test/core/transport/chttp2/hpack_parser_test.c

@ -102,12 +102,6 @@ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error); grpc_error *error);
/** Cancel a stream: coming from the transport API */
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
grpc_error *error);
static void close_from_api(grpc_exec_ctx *exec_ctx, static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, grpc_chttp2_stream_global *stream_global,
@ -917,10 +911,11 @@ static void maybe_start_some_streams(
while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
&stream_global)) { &stream_global)) {
cancel_from_api(exec_ctx, transport_global, stream_global, grpc_chttp2_cancel_stream(
grpc_error_set_int( exec_ctx, transport_global, stream_global,
GRPC_ERROR_CREATE("Stream IDs exhausted"), grpc_error_set_int(GRPC_ERROR_CREATE("Stream IDs exhausted"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE));
} }
} }
@ -1010,7 +1005,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} }
if (op->cancel_error != GRPC_ERROR_NONE) { if (op->cancel_error != GRPC_ERROR_NONE) {
cancel_from_api(exec_ctx, transport_global, stream_global, grpc_chttp2_cancel_stream(exec_ctx, transport_global, stream_global,
GRPC_ERROR_REF(op->cancel_error)); GRPC_ERROR_REF(op->cancel_error));
} }
@ -1035,7 +1030,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
stream_global->send_initial_metadata->deadline); stream_global->send_initial_metadata->deadline);
} }
if (metadata_size > metadata_peer_limit) { if (metadata_size > metadata_peer_limit) {
cancel_from_api( grpc_chttp2_cancel_stream(
exec_ctx, transport_global, stream_global, exec_ctx, transport_global, stream_global,
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(
@ -1102,7 +1097,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
transport_global->settings[GRPC_PEER_SETTINGS] transport_global->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (metadata_size > metadata_peer_limit) { if (metadata_size > metadata_peer_limit) {
cancel_from_api( grpc_chttp2_cancel_stream(
exec_ctx, transport_global, stream_global, exec_ctx, transport_global, stream_global,
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(
@ -1316,14 +1311,6 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
&stream_global->incoming_frames)) != NULL) { &stream_global->incoming_frames)) != NULL) {
incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
} }
if (stream_global->exceeded_metadata_size) {
cancel_from_api(
exec_ctx, transport_global, stream_global,
grpc_error_set_int(
GRPC_ERROR_CREATE(
"received initial metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
}
} }
grpc_chttp2_incoming_metadata_buffer_publish( grpc_chttp2_incoming_metadata_buffer_publish(
&stream_global->metadata_buffer[0], &stream_global->metadata_buffer[0],
@ -1360,14 +1347,6 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
&stream_global->incoming_frames)) != NULL) { &stream_global->incoming_frames)) != NULL) {
incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
} }
if (stream_global->exceeded_metadata_size) {
cancel_from_api(
exec_ctx, transport_global, stream_global,
grpc_error_set_int(
GRPC_ERROR_CREATE(
"received trailing metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
}
} }
if (stream_global->all_incoming_byte_streams_finished) { if (stream_global->all_incoming_byte_streams_finished) {
grpc_chttp2_incoming_metadata_buffer_publish( grpc_chttp2_incoming_metadata_buffer_publish(
@ -1449,7 +1428,7 @@ static void status_codes_from_error(grpc_error *error, gpr_timespec deadline,
} }
} }
static void cancel_from_api(grpc_exec_ctx *exec_ctx, void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, grpc_chttp2_stream_global *stream_global,
grpc_error *due_to_error) { grpc_error *due_to_error) {
@ -1744,7 +1723,7 @@ static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
void *user_data, void *user_data,
grpc_chttp2_stream_global *stream_global) { grpc_chttp2_stream_global *stream_global) {
cancel_stream_cb_args *args = user_data; cancel_stream_cb_args *args = user_data;
cancel_from_api(args->exec_ctx, transport_global, stream_global, grpc_chttp2_cancel_stream(args->exec_ctx, transport_global, stream_global,
GRPC_ERROR_REF(args->error)); GRPC_ERROR_REF(args->error));
} }

@ -78,69 +78,96 @@ typedef enum {
a set of indirect jumps, and so not waste stack space. */ a set of indirect jumps, and so not waste stack space. */
/* forward declarations for parsing states */ /* forward declarations for parsing states */
static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_begin(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_error(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end, grpc_error *error); const uint8_t *end, grpc_error *error);
static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p, static grpc_error *still_parse_error(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p, static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p, static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p, static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_value_string_with_indexed_key( static grpc_error *parse_value_string_with_indexed_key(
grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end);
static grpc_error *parse_value_string_with_literal_key( static grpc_error *parse_value_string_with_literal_key(
grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end);
static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value0(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value1(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value2(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value3(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p, static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p, static grpc_error *parse_indexed_field(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_indexed_field_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_incidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_incidx_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_notidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_notidx_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_nvridx_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end); const uint8_t *end);
static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p, static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end); const uint8_t *cur, const uint8_t *end);
/* we translate the first byte of a hpack field into one of these decoding /* we translate the first byte of a hpack field into one of these decoding
@ -639,8 +666,8 @@ static const uint8_t inverse_base64[256] = {
}; };
/* emission helpers */ /* emission helpers */
static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
int add_to_table) { grpc_mdelem *md, int add_to_table) {
if (add_to_table) { if (add_to_table) {
grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md); grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md);
if (err != GRPC_ERROR_NONE) return err; if (err != GRPC_ERROR_NONE) return err;
@ -649,7 +676,7 @@ static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
GRPC_MDELEM_UNREF(md); GRPC_MDELEM_UNREF(md);
return GRPC_ERROR_CREATE("on_header callback not set"); return GRPC_ERROR_CREATE("on_header callback not set");
} }
p->on_header(p->on_header_user_data, md); p->on_header(exec_ctx, p->on_header_user_data, md);
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
@ -661,78 +688,86 @@ static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
} }
/* jump to the next state */ /* jump to the next state */
static grpc_error *parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_next(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
p->state = *p->next_state++; p->state = *p->next_state++;
return p->state(p, cur, end); return p->state(exec_ctx, p, cur, end);
} }
/* begin parsing a header: all functionality is encoded into lookup tables /* begin parsing a header: all functionality is encoded into lookup tables
above */ above */
static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_begin(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_begin; p->state = parse_begin;
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
return first_byte_action[first_byte_lut[*cur]](p, cur, end); return first_byte_action[first_byte_lut[*cur]](exec_ctx, p, cur, end);
} }
/* stream dependency and prioritization data: we just skip it */ /* stream dependency and prioritization data: we just skip it */
static grpc_error *parse_stream_weight(grpc_chttp2_hpack_parser *p, static grpc_error *parse_stream_weight(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_stream_weight; p->state = parse_stream_weight;
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
return p->after_prioritization(p, cur + 1, end); return p->after_prioritization(exec_ctx, p, cur + 1, end);
} }
static grpc_error *parse_stream_dep3(grpc_chttp2_hpack_parser *p, static grpc_error *parse_stream_dep3(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_stream_dep3; p->state = parse_stream_dep3;
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
return parse_stream_weight(p, cur + 1, end); return parse_stream_weight(exec_ctx, p, cur + 1, end);
} }
static grpc_error *parse_stream_dep2(grpc_chttp2_hpack_parser *p, static grpc_error *parse_stream_dep2(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_stream_dep2; p->state = parse_stream_dep2;
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
return parse_stream_dep3(p, cur + 1, end); return parse_stream_dep3(exec_ctx, p, cur + 1, end);
} }
static grpc_error *parse_stream_dep1(grpc_chttp2_hpack_parser *p, static grpc_error *parse_stream_dep1(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_stream_dep1; p->state = parse_stream_dep1;
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
return parse_stream_dep2(p, cur + 1, end); return parse_stream_dep2(exec_ctx, p, cur + 1, end);
} }
static grpc_error *parse_stream_dep0(grpc_chttp2_hpack_parser *p, static grpc_error *parse_stream_dep0(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_stream_dep0; p->state = parse_stream_dep0;
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
return parse_stream_dep1(p, cur + 1, end); return parse_stream_dep1(exec_ctx, p, cur + 1, end);
} }
/* emit an indexed field; for now just logs it to console; jumps to /* emit an indexed field; for now just logs it to console; jumps to
begin the next field on completion */ begin the next field on completion */
static grpc_error *finish_indexed_field(grpc_chttp2_hpack_parser *p, static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
@ -743,21 +778,23 @@ static grpc_error *finish_indexed_field(grpc_chttp2_hpack_parser *p,
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents); GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
} }
GRPC_MDELEM_REF(md); GRPC_MDELEM_REF(md);
grpc_error *err = on_hdr(p, md, 0); grpc_error *err = on_hdr(exec_ctx, p, md, 0);
if (err != GRPC_ERROR_NONE) return err; if (err != GRPC_ERROR_NONE) return err;
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* parse an indexed field with index < 127 */ /* parse an indexed field with index < 127 */
static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p, static grpc_error *parse_indexed_field(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->index = (*cur) & 0x7f; p->index = (*cur) & 0x7f;
return finish_indexed_field(p, cur + 1, end); return finish_indexed_field(exec_ctx, p, cur + 1, end);
} }
/* parse an indexed field with index >= 127 */ /* parse an indexed field with index >= 127 */
static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_indexed_field_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -766,49 +803,53 @@ static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
p->next_state = and_then; p->next_state = and_then;
p->index = 0x7f; p->index = 0x7f;
p->parsing.value = &p->index; p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end); return parse_value0(exec_ctx, p, cur + 1, end);
} }
/* finish a literal header with incremental indexing: just log, and jump to ' /* finish a literal header with incremental indexing: just log, and jump to '
begin */ begin */
static grpc_error *finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
GPR_ASSERT(md != NULL); /* handled in string parsing */ GPR_ASSERT(md != NULL); /* handled in string parsing */
grpc_error *err = grpc_error *err = on_hdr(
on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)), take_string(p, &p->value)),
1); 1);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* finish a literal header with incremental indexing with no index */ /* finish a literal header with incremental indexing with no index */
static grpc_error *finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, static grpc_error *finish_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_error *err = grpc_error *err = on_hdr(
on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
take_string(p, &p->value)), take_string(p, &p->value)),
1); 1);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* parse a literal header with incremental indexing; index < 63 */ /* parse a literal header with incremental indexing; index < 63 */
static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_incidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_incidx}; parse_value_string_with_indexed_key, finish_lithdr_incidx};
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->next_state = and_then; p->next_state = and_then;
p->index = (*cur) & 0x3f; p->index = (*cur) & 0x3f;
return parse_string_prefix(p, cur + 1, end); return parse_string_prefix(exec_ctx, p, cur + 1, end);
} }
/* parse a literal header with incremental indexing; index >= 63 */ /* parse a literal header with incremental indexing; index >= 63 */
static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_incidx_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -818,11 +859,12 @@ static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
p->next_state = and_then; p->next_state = and_then;
p->index = 0x3f; p->index = 0x3f;
p->parsing.value = &p->index; p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end); return parse_value0(exec_ctx, p, cur + 1, end);
} }
/* parse a literal header with incremental indexing; index = 0 */ /* parse a literal header with incremental indexing; index = 0 */
static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -830,48 +872,52 @@ static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
parse_value_string_with_literal_key, finish_lithdr_incidx_v}; parse_value_string_with_literal_key, finish_lithdr_incidx_v};
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->next_state = and_then; p->next_state = and_then;
return parse_string_prefix(p, cur + 1, end); return parse_string_prefix(exec_ctx, p, cur + 1, end);
} }
/* finish a literal header without incremental indexing */ /* finish a literal header without incremental indexing */
static grpc_error *finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
GPR_ASSERT(md != NULL); /* handled in string parsing */ GPR_ASSERT(md != NULL); /* handled in string parsing */
grpc_error *err = grpc_error *err = on_hdr(
on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)), take_string(p, &p->value)),
0); 0);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* finish a literal header without incremental indexing with index = 0 */ /* finish a literal header without incremental indexing with index = 0 */
static grpc_error *finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, static grpc_error *finish_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_error *err = grpc_error *err = on_hdr(
on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
take_string(p, &p->value)), take_string(p, &p->value)),
0); 0);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* parse a literal header without incremental indexing; index < 15 */ /* parse a literal header without incremental indexing; index < 15 */
static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_notidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_notidx}; parse_value_string_with_indexed_key, finish_lithdr_notidx};
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->next_state = and_then; p->next_state = and_then;
p->index = (*cur) & 0xf; p->index = (*cur) & 0xf;
return parse_string_prefix(p, cur + 1, end); return parse_string_prefix(exec_ctx, p, cur + 1, end);
} }
/* parse a literal header without incremental indexing; index >= 15 */ /* parse a literal header without incremental indexing; index >= 15 */
static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_notidx_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -881,11 +927,12 @@ static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
p->next_state = and_then; p->next_state = and_then;
p->index = 0xf; p->index = 0xf;
p->parsing.value = &p->index; p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end); return parse_value0(exec_ctx, p, cur + 1, end);
} }
/* parse a literal header without incremental indexing; index == 0 */ /* parse a literal header without incremental indexing; index == 0 */
static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -893,48 +940,52 @@ static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
parse_value_string_with_literal_key, finish_lithdr_notidx_v}; parse_value_string_with_literal_key, finish_lithdr_notidx_v};
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->next_state = and_then; p->next_state = and_then;
return parse_string_prefix(p, cur + 1, end); return parse_string_prefix(exec_ctx, p, cur + 1, end);
} }
/* finish a literal header that is never indexed */ /* finish a literal header that is never indexed */
static grpc_error *finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
GPR_ASSERT(md != NULL); /* handled in string parsing */ GPR_ASSERT(md != NULL); /* handled in string parsing */
grpc_error *err = grpc_error *err = on_hdr(
on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)), take_string(p, &p->value)),
0); 0);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* finish a literal header that is never indexed with an extra value */ /* finish a literal header that is never indexed with an extra value */
static grpc_error *finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, static grpc_error *finish_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
grpc_error *err = grpc_error *err = on_hdr(
on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
take_string(p, &p->value)), take_string(p, &p->value)),
0); 0);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* parse a literal header that is never indexed; index < 15 */ /* parse a literal header that is never indexed; index < 15 */
static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_nvridx}; parse_value_string_with_indexed_key, finish_lithdr_nvridx};
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->next_state = and_then; p->next_state = and_then;
p->index = (*cur) & 0xf; p->index = (*cur) & 0xf;
return parse_string_prefix(p, cur + 1, end); return parse_string_prefix(exec_ctx, p, cur + 1, end);
} }
/* parse a literal header that is never indexed; index >= 15 */ /* parse a literal header that is never indexed; index >= 15 */
static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_nvridx_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -944,11 +995,12 @@ static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
p->next_state = and_then; p->next_state = and_then;
p->index = 0xf; p->index = 0xf;
p->parsing.value = &p->index; p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end); return parse_value0(exec_ctx, p, cur + 1, end);
} }
/* parse a literal header that is never indexed; index == 0 */ /* parse a literal header that is never indexed; index == 0 */
static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
@ -956,44 +1008,47 @@ static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
parse_value_string_with_literal_key, finish_lithdr_nvridx_v}; parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
p->dynamic_table_update_allowed = 0; p->dynamic_table_update_allowed = 0;
p->next_state = and_then; p->next_state = and_then;
return parse_string_prefix(p, cur + 1, end); return parse_string_prefix(exec_ctx, p, cur + 1, end);
} }
/* finish parsing a max table size change */ /* finish parsing a max table size change */
static grpc_error *finish_max_tbl_size(grpc_chttp2_hpack_parser *p, static grpc_error *finish_max_tbl_size(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (grpc_http_trace) { if (grpc_http_trace) {
gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
} }
grpc_error *err = grpc_error *err =
grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index); grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(p, cur, end); return parse_begin(exec_ctx, p, cur, end);
} }
/* parse a max table size change, max size < 15 */ /* parse a max table size change, max size < 15 */
static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p, static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (p->dynamic_table_update_allowed == 0) { if (p->dynamic_table_update_allowed == 0) {
return parse_error( return parse_error(
p, cur, end, exec_ctx, p, cur, end,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
"More than two max table size changes in a single frame")); "More than two max table size changes in a single frame"));
} }
p->dynamic_table_update_allowed--; p->dynamic_table_update_allowed--;
p->index = (*cur) & 0x1f; p->index = (*cur) & 0x1f;
return finish_max_tbl_size(p, cur + 1, end); return finish_max_tbl_size(exec_ctx, p, cur + 1, end);
} }
/* parse a max table size change, max size >= 15 */ /* parse a max table size change, max size >= 15 */
static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = { static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_max_tbl_size}; finish_max_tbl_size};
if (p->dynamic_table_update_allowed == 0) { if (p->dynamic_table_update_allowed == 0) {
return parse_error( return parse_error(
p, cur, end, exec_ctx, p, cur, end,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
"More than two max table size changes in a single frame")); "More than two max table size changes in a single frame"));
} }
@ -1001,11 +1056,12 @@ static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
p->next_state = and_then; p->next_state = and_then;
p->index = 0x1f; p->index = 0x1f;
p->parsing.value = &p->index; p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end); return parse_value0(exec_ctx, p, cur + 1, end);
} }
/* a parse error: jam the parse state into parse_error, and return error */ /* a parse error: jam the parse state into parse_error, and return error */
static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_error(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end, grpc_error *err) { const uint8_t *end, grpc_error *err) {
GPR_ASSERT(err != GRPC_ERROR_NONE); GPR_ASSERT(err != GRPC_ERROR_NONE);
if (p->last_error == GRPC_ERROR_NONE) { if (p->last_error == GRPC_ERROR_NONE) {
@ -1015,24 +1071,27 @@ static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
return err; return err;
} }
static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p, static grpc_error *still_parse_error(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
return GRPC_ERROR_REF(p->last_error); return GRPC_ERROR_REF(p->last_error);
} }
static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p, static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
GPR_ASSERT(cur != end); GPR_ASSERT(cur != end);
char *msg; char *msg;
gpr_asprintf(&msg, "Illegal hpack op code %d", *cur); gpr_asprintf(&msg, "Illegal hpack op code %d", *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
/* parse the 1st byte of a varint into p->parsing.value /* parse the 1st byte of a varint into p->parsing.value
no overflow is possible */ no overflow is possible */
static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value0(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_value0; p->state = parse_value0;
@ -1042,15 +1101,16 @@ static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
*p->parsing.value += (*cur) & 0x7f; *p->parsing.value += (*cur) & 0x7f;
if ((*cur) & 0x80) { if ((*cur) & 0x80) {
return parse_value1(p, cur + 1, end); return parse_value1(exec_ctx, p, cur + 1, end);
} else { } else {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
} }
/* parse the 2nd byte of a varint into p->parsing.value /* parse the 2nd byte of a varint into p->parsing.value
no overflow is possible */ no overflow is possible */
static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value1(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_value1; p->state = parse_value1;
@ -1060,15 +1120,16 @@ static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7; *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
if ((*cur) & 0x80) { if ((*cur) & 0x80) {
return parse_value2(p, cur + 1, end); return parse_value2(exec_ctx, p, cur + 1, end);
} else { } else {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
} }
/* parse the 3rd byte of a varint into p->parsing.value /* parse the 3rd byte of a varint into p->parsing.value
no overflow is possible */ no overflow is possible */
static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value2(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_value2; p->state = parse_value2;
@ -1078,15 +1139,16 @@ static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14; *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
if ((*cur) & 0x80) { if ((*cur) & 0x80) {
return parse_value3(p, cur + 1, end); return parse_value3(exec_ctx, p, cur + 1, end);
} else { } else {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
} }
/* parse the 4th byte of a varint into p->parsing.value /* parse the 4th byte of a varint into p->parsing.value
no overflow is possible */ no overflow is possible */
static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value3(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_value3; p->state = parse_value3;
@ -1096,15 +1158,16 @@ static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21; *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
if ((*cur) & 0x80) { if ((*cur) & 0x80) {
return parse_value4(p, cur + 1, end); return parse_value4(exec_ctx, p, cur + 1, end);
} else { } else {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
} }
/* parse the 5th byte of a varint into p->parsing.value /* parse the 5th byte of a varint into p->parsing.value
depending on the byte, we may overflow, and care must be taken */ depending on the byte, we may overflow, and care must be taken */
static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
uint8_t c; uint8_t c;
uint32_t cur_value; uint32_t cur_value;
@ -1130,9 +1193,9 @@ static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
*p->parsing.value = cur_value + add_value; *p->parsing.value = cur_value + add_value;
if ((*cur) & 0x80) { if ((*cur) & 0x80) {
return parse_value5up(p, cur + 1, end); return parse_value5up(exec_ctx, p, cur + 1, end);
} else { } else {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
error: error:
@ -1142,13 +1205,14 @@ error:
*p->parsing.value, *cur); *p->parsing.value, *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
/* parse any trailing bytes in a varint: it's possible to append an arbitrary /* parse any trailing bytes in a varint: it's possible to append an arbitrary
number of 0x80's and not affect the value - a zero will terminate - and number of 0x80's and not affect the value - a zero will terminate - and
anything else will overflow */ anything else will overflow */
static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p, static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
while (cur != end && *cur == 0x80) { while (cur != end && *cur == 0x80) {
++cur; ++cur;
@ -1160,7 +1224,7 @@ static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
} }
if (*cur == 0) { if (*cur == 0) {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
char *msg; char *msg;
@ -1170,11 +1234,12 @@ static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
*p->parsing.value, *cur); *p->parsing.value, *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
/* parse a string prefix */ /* parse a string prefix */
static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p, static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (cur == end) { if (cur == end) {
p->state = parse_string_prefix; p->state = parse_string_prefix;
@ -1185,9 +1250,9 @@ static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
p->huff = (*cur) >> 7; p->huff = (*cur) >> 7;
if (p->strlen == 0x7f) { if (p->strlen == 0x7f) {
p->parsing.value = &p->strlen; p->parsing.value = &p->strlen;
return parse_value0(p, cur + 1, end); return parse_value0(exec_ctx, p, cur + 1, end);
} else { } else {
return parse_next(p, cur + 1, end); return parse_next(exec_ctx, p, cur + 1, end);
} }
} }
@ -1205,7 +1270,8 @@ static void append_bytes(grpc_chttp2_hpack_parser_string *str,
str->length += (uint32_t)length; str->length += (uint32_t)length;
} }
static grpc_error *append_string(grpc_chttp2_hpack_parser *p, static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
grpc_chttp2_hpack_parser_string *str = p->parsing.str; grpc_chttp2_hpack_parser_string *str = p->parsing.str;
uint32_t bits; uint32_t bits;
@ -1223,7 +1289,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(p, cur, end, return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character")); GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte0; goto b64_byte0;
@ -1238,7 +1304,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(p, cur, end, return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character")); GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte1; goto b64_byte1;
@ -1253,7 +1319,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(p, cur, end, return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character")); GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte2; goto b64_byte2;
@ -1268,7 +1334,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(p, cur, end, return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character")); GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte3; goto b64_byte3;
@ -1281,11 +1347,12 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
goto b64_byte0; goto b64_byte0;
} }
GPR_UNREACHABLE_CODE(return parse_error( GPR_UNREACHABLE_CODE(return parse_error(
p, cur, end, GRPC_ERROR_CREATE("Should never reach here"))); exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
} }
/* append a null terminator to a string */ /* append a null terminator to a string */
static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
uint8_t terminator = 0; uint8_t terminator = 0;
uint8_t decoded[2]; uint8_t decoded[2];
@ -1298,7 +1365,7 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
break; break;
case B64_BYTE1: case B64_BYTE1:
return parse_error( return parse_error(
p, cur, end, exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */ GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */
case B64_BYTE2: case B64_BYTE2:
bits = p->base64_buffer; bits = p->base64_buffer;
@ -1308,7 +1375,7 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
bits & 0xffff); bits & 0xffff);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
decoded[0] = (uint8_t)(bits >> 16); decoded[0] = (uint8_t)(bits >> 16);
append_bytes(str, decoded, 1); append_bytes(str, decoded, 1);
@ -1321,7 +1388,7 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
bits & 0xff); bits & 0xff);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
decoded[0] = (uint8_t)(bits >> 16); decoded[0] = (uint8_t)(bits >> 16);
decoded[1] = (uint8_t)(bits >> 8); decoded[1] = (uint8_t)(bits >> 8);
@ -1334,13 +1401,14 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
} }
/* decode a nibble from a huffman encoded stream */ /* decode a nibble from a huffman encoded stream */
static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) { static grpc_error *huff_nibble(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, uint8_t nibble) {
int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble]; int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble]; int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
if (emit != -1) { if (emit != -1) {
if (emit >= 0 && emit < 256) { if (emit >= 0 && emit < 256) {
uint8_t c = (uint8_t)emit; uint8_t c = (uint8_t)emit;
grpc_error *err = append_string(p, &c, (&c) + 1); grpc_error *err = append_string(exec_ctx, p, &c, (&c) + 1);
if (err != GRPC_ERROR_NONE) return err; if (err != GRPC_ERROR_NONE) return err;
} else { } else {
assert(emit == 256); assert(emit == 256);
@ -1351,42 +1419,45 @@ static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
} }
/* decode full bytes from a huffman encoded stream */ /* decode full bytes from a huffman encoded stream */
static grpc_error *add_huff_bytes(grpc_chttp2_hpack_parser *p, static grpc_error *add_huff_bytes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
for (; cur != end; ++cur) { for (; cur != end; ++cur) {
grpc_error *err = huff_nibble(p, *cur >> 4); grpc_error *err = huff_nibble(exec_ctx, p, *cur >> 4);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
err = huff_nibble(p, *cur & 0xf); err = huff_nibble(exec_ctx, p, *cur & 0xf);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
/* decode some string bytes based on the current decoding mode /* decode some string bytes based on the current decoding mode
(huffman or not) */ (huffman or not) */
static grpc_error *add_str_bytes(grpc_chttp2_hpack_parser *p, static grpc_error *add_str_bytes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
if (p->huff) { if (p->huff) {
return add_huff_bytes(p, cur, end); return add_huff_bytes(exec_ctx, p, cur, end);
} else { } else {
return append_string(p, cur, end); return append_string(exec_ctx, p, cur, end);
} }
} }
/* parse a string - tries to do large chunks at a time */ /* parse a string - tries to do large chunks at a time */
static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, static grpc_error *parse_string(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) { const uint8_t *end) {
size_t remaining = p->strlen - p->strgot; size_t remaining = p->strlen - p->strgot;
size_t given = (size_t)(end - cur); size_t given = (size_t)(end - cur);
if (remaining <= given) { if (remaining <= given) {
grpc_error *err = add_str_bytes(p, cur, cur + remaining); grpc_error *err = add_str_bytes(exec_ctx, p, cur, cur + remaining);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
err = finish_str(p, cur + remaining, end); err = finish_str(exec_ctx, p, cur + remaining, end);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_next(p, cur + remaining, end); return parse_next(exec_ctx, p, cur + remaining, end);
} else { } else {
grpc_error *err = add_str_bytes(p, cur, cur + given); grpc_error *err = add_str_bytes(exec_ctx, p, cur, cur + given);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
GPR_ASSERT(given <= UINT32_MAX - p->strgot); GPR_ASSERT(given <= UINT32_MAX - p->strgot);
p->strgot += (uint32_t)given; p->strgot += (uint32_t)given;
p->state = parse_string; p->state = parse_string;
@ -1395,7 +1466,8 @@ static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
} }
/* begin parsing a string - performs setup, calls parse_string */ /* begin parsing a string - performs setup, calls parse_string */
static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p, static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end, const uint8_t *cur, const uint8_t *end,
uint8_t binary, uint8_t binary,
grpc_chttp2_hpack_parser_string *str) { grpc_chttp2_hpack_parser_string *str) {
@ -1404,13 +1476,14 @@ static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p,
p->parsing.str = str; p->parsing.str = str;
p->huff_state = 0; p->huff_state = 0;
p->binary = binary; p->binary = binary;
return parse_string(p, cur, end); return parse_string(exec_ctx, p, cur, end);
} }
/* parse the key string */ /* parse the key string */
static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p, static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end) { const uint8_t *cur, const uint8_t *end) {
return begin_parse_string(p, cur, end, NOT_BINARY, &p->key); return begin_parse_string(exec_ctx, p, cur, end, NOT_BINARY, &p->key);
} }
/* check if a key represents a binary header or not */ /* check if a key represents a binary header or not */
@ -1435,24 +1508,27 @@ static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
} }
/* parse the value string */ /* parse the value string */
static grpc_error *parse_value_string(grpc_chttp2_hpack_parser *p, static grpc_error *parse_value_string(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur, const uint8_t *end, const uint8_t *cur, const uint8_t *end,
bool is_binary) { bool is_binary) {
return begin_parse_string(p, cur, end, is_binary ? B64_BYTE0 : NOT_BINARY, return begin_parse_string(exec_ctx, p, cur, end,
&p->value); is_binary ? B64_BYTE0 : NOT_BINARY, &p->value);
} }
static grpc_error *parse_value_string_with_indexed_key( static grpc_error *parse_value_string_with_indexed_key(
grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) {
bool is_binary = false; bool is_binary = false;
grpc_error *err = is_binary_indexed_header(p, &is_binary); grpc_error *err = is_binary_indexed_header(p, &is_binary);
if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_value_string(p, cur, end, is_binary); return parse_value_string(exec_ctx, p, cur, end, is_binary);
} }
static grpc_error *parse_value_string_with_literal_key( static grpc_error *parse_value_string_with_literal_key(
grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
return parse_value_string(p, cur, end, is_binary_literal_header(p)); const uint8_t *end) {
return parse_value_string(exec_ctx, p, cur, end, is_binary_literal_header(p));
} }
/* PUBLIC INTERFACE */ /* PUBLIC INTERFACE */
@ -1484,14 +1560,15 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
gpr_free(p->value.str); gpr_free(p->value.str);
} }
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *beg, const uint8_t *beg,
const uint8_t *end) { const uint8_t *end) {
/* TODO(ctiller): limit the distance of end from beg, and perform multiple /* TODO(ctiller): limit the distance of end from beg, and perform multiple
steps in the event of a large chunk of data to limit steps in the event of a large chunk of data to limit
stack space usage when no tail call optimization is stack space usage when no tail call optimization is
available */ available */
return p->state(p, beg, end); return p->state(exec_ctx, p, beg, end);
} }
grpc_error *grpc_chttp2_header_parser_parse( grpc_error *grpc_chttp2_header_parser_parse(
@ -1504,7 +1581,7 @@ grpc_error *grpc_chttp2_header_parser_parse(
stream_global->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice); stream_global->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice);
} }
grpc_error *error = grpc_chttp2_hpack_parser_parse( grpc_error *error = grpc_chttp2_hpack_parser_parse(
parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice)); exec_ctx, parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice));
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return error; return error;

@ -45,7 +45,8 @@
typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser; typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
typedef grpc_error *(*grpc_chttp2_hpack_parser_state)( typedef grpc_error *(*grpc_chttp2_hpack_parser_state)(
grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end); grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *beg,
const uint8_t *end);
typedef struct { typedef struct {
char *str; char *str;
@ -55,7 +56,7 @@ typedef struct {
struct grpc_chttp2_hpack_parser { struct grpc_chttp2_hpack_parser {
/* user specified callback for each header output */ /* user specified callback for each header output */
void (*on_header)(void *user_data, grpc_mdelem *md); void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem *md);
void *on_header_user_data; void *on_header_user_data;
grpc_error *last_error; grpc_error *last_error;
@ -104,7 +105,8 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
/* returns 1 on success, 0 on error */ /* returns 1 on success, 0 on error */
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *beg, const uint8_t *beg,
const uint8_t *end); const uint8_t *end);

@ -410,7 +410,6 @@ struct grpc_chttp2_stream_global {
/** Has this stream seen an error. /** Has this stream seen an error.
If true, then pending incoming frames can be thrown away. */ If true, then pending incoming frames can be thrown away. */
bool seen_error; bool seen_error;
bool exceeded_metadata_size;
/** the error that resulted in this stream being read-closed */ /** the error that resulted in this stream being read-closed */
grpc_error *read_closed_error; grpc_error *read_closed_error;
@ -762,4 +761,9 @@ void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global, grpc_chttp2_stream_global *stream_global,
bool covered_by_poller, const char *reason); bool covered_by_poller, const char *reason);
void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
grpc_error *due_to_error);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */ #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -354,7 +354,9 @@ static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) {
GRPC_MDELEM_UNREF(md);
}
static grpc_error *init_skip_frame_parser( static grpc_error *init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
@ -458,7 +460,8 @@ static grpc_error *init_data_frame_parser(
static void free_timeout(void *p) { gpr_free(p); } static void free_timeout(void *p) { gpr_free(p); }
static void on_initial_header(void *tp, grpc_mdelem *md) { static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
grpc_mdelem *md) {
grpc_chttp2_transport_global *transport_global = tp; grpc_chttp2_transport_global *transport_global = tp;
grpc_chttp2_stream_global *stream_global = transport_global->incoming_stream; grpc_chttp2_stream_global *stream_global = transport_global->incoming_stream;
@ -500,14 +503,17 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
transport_global->settings[GRPC_ACKED_SETTINGS] transport_global->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (new_size > metadata_size_limit) { if (new_size > metadata_size_limit) {
if (!stream_global->exceeded_metadata_size) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"received initial metadata size exceeds limit (%" PRIuPTR "received initial metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR ")", " vs. %" PRIuPTR ")",
new_size, metadata_size_limit); new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
exec_ctx, transport_global, stream_global,
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, transport_global);
stream_global->seen_error = true; stream_global->seen_error = true;
stream_global->exceeded_metadata_size = true;
}
GRPC_MDELEM_UNREF(md); GRPC_MDELEM_UNREF(md);
} else { } else {
grpc_chttp2_incoming_metadata_buffer_add( grpc_chttp2_incoming_metadata_buffer_add(
@ -518,7 +524,8 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
GPR_TIMER_END("on_initial_header", 0); GPR_TIMER_END("on_initial_header", 0);
} }
static void on_trailing_header(void *tp, grpc_mdelem *md) { static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
grpc_mdelem *md) {
grpc_chttp2_transport_global *transport_global = tp; grpc_chttp2_transport_global *transport_global = tp;
grpc_chttp2_stream_global *stream_global = transport_global->incoming_stream; grpc_chttp2_stream_global *stream_global = transport_global->incoming_stream;
@ -542,14 +549,17 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
transport_global->settings[GRPC_ACKED_SETTINGS] transport_global->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (new_size > metadata_size_limit) { if (new_size > metadata_size_limit) {
if (!stream_global->exceeded_metadata_size) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"received trailing metadata size exceeds limit (%" PRIuPTR "received trailing metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR ")", " vs. %" PRIuPTR ")",
new_size, metadata_size_limit); new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
exec_ctx, transport_global, stream_global,
grpc_error_set_int(
GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_global);
stream_global->seen_error = true; stream_global->seen_error = true;
stream_global->exceeded_metadata_size = true;
}
GRPC_MDELEM_UNREF(md); GRPC_MDELEM_UNREF(md);
} else { } else {
grpc_chttp2_incoming_metadata_buffer_add(&stream_global->metadata_buffer[1], grpc_chttp2_incoming_metadata_buffer_add(&stream_global->metadata_buffer[1],

@ -43,7 +43,9 @@
bool squelch = true; bool squelch = true;
bool leak_check = true; bool leak_check = true;
static void onhdr(void *ud, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } static void onhdr(grpc_exec_ctx *exec_ctx, void *ud, grpc_mdelem *md) {
GRPC_MDELEM_UNREF(md);
}
static void dont_log(gpr_log_func_args *args) {} static void dont_log(gpr_log_func_args *args) {}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
@ -53,7 +55,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_chttp2_hpack_parser parser; grpc_chttp2_hpack_parser parser;
grpc_chttp2_hpack_parser_init(&parser); grpc_chttp2_hpack_parser_init(&parser);
parser.on_header = onhdr; parser.on_header = onhdr;
GRPC_ERROR_UNREF(grpc_chttp2_hpack_parser_parse(&parser, data, data + size)); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GRPC_ERROR_UNREF(
grpc_chttp2_hpack_parser_parse(&exec_ctx, &parser, data, data + size));
grpc_exec_ctx_finish(&exec_ctx);
grpc_chttp2_hpack_parser_destroy(&parser); grpc_chttp2_hpack_parser_destroy(&parser);
grpc_shutdown(); grpc_shutdown();
return 0; return 0;

@ -45,7 +45,7 @@
typedef struct { va_list args; } test_checker; typedef struct { va_list args; } test_checker;
static void onhdr(void *ud, grpc_mdelem *md) { static void onhdr(grpc_exec_ctx *exec_ctx, void *ud, grpc_mdelem *md) {
const char *ekey, *evalue; const char *ekey, *evalue;
test_checker *chk = ud; test_checker *chk = ud;
ekey = va_arg(chk->args, char *); ekey = va_arg(chk->args, char *);
@ -75,9 +75,11 @@ static void test_vector(grpc_chttp2_hpack_parser *parser,
gpr_slice_unref(input); gpr_slice_unref(input);
for (i = 0; i < nslices; i++) { for (i = 0; i < nslices; i++) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_ASSERT(grpc_chttp2_hpack_parser_parse( GPR_ASSERT(grpc_chttp2_hpack_parser_parse(
parser, GPR_SLICE_START_PTR(slices[i]), &exec_ctx, parser, GPR_SLICE_START_PTR(slices[i]),
GPR_SLICE_END_PTR(slices[i])) == GRPC_ERROR_NONE); GPR_SLICE_END_PTR(slices[i])) == GRPC_ERROR_NONE);
grpc_exec_ctx_finish(&exec_ctx);
} }
for (i = 0; i < nslices; i++) { for (i = 0; i < nslices; i++) {

Loading…
Cancel
Save