|
|
@ -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; |
|
|
|