aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/transport/chttp2/transport/hpack_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/ext/transport/chttp2/transport/hpack_parser.c')
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c196
1 files changed, 70 insertions, 126 deletions
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 40f5120308..8b91cc760b 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -50,13 +50,9 @@
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
-#include "src/core/lib/transport/http2_errors.h"
-
-/* TODO(ctiller): remove before submission */
-#include "src/core/lib/slice/slice_string_helpers.h"
extern int grpc_http_trace;
@@ -672,22 +668,8 @@ static const uint8_t inverse_base64[256] = {
/* emission helpers */
static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
- grpc_mdelem md, int add_to_table) {
- if (grpc_http_trace && !GRPC_MDELEM_IS_INTERNED(md)) {
- char *k = grpc_slice_to_c_string(GRPC_MDKEY(md));
- char *v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
- gpr_log(
- GPR_DEBUG,
- "Decode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d",
- k, v, GRPC_MDELEM_IS_INTERNED(md), GRPC_MDELEM_STORAGE(md),
- grpc_slice_is_interned(GRPC_MDKEY(md)),
- grpc_slice_is_interned(GRPC_MDVALUE(md)));
- gpr_free(k);
- gpr_free(v);
- }
+ grpc_mdelem *md, int add_to_table) {
if (add_to_table) {
- GPR_ASSERT(GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_INTERNED ||
- GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC);
grpc_error *err = grpc_chttp2_hptbl_add(exec_ctx, &p->table, md);
if (err != GRPC_ERROR_NONE) return err;
}
@@ -699,28 +681,10 @@ static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
return GRPC_ERROR_NONE;
}
-static grpc_slice take_string(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_hpack_parser *p,
- grpc_chttp2_hpack_parser_string *str,
- bool intern) {
- grpc_slice s;
- if (!str->copied) {
- if (intern) {
- s = grpc_slice_intern(str->data.referenced);
- grpc_slice_unref_internal(exec_ctx, str->data.referenced);
- } else {
- s = str->data.referenced;
- }
- str->copied = true;
- str->data.referenced = grpc_empty_slice();
- } else if (intern) {
- s = grpc_slice_intern(grpc_slice_from_static_buffer(
- str->data.copied.str, str->data.copied.length));
- } else {
- s = grpc_slice_from_copied_buffer(str->data.copied.str,
- str->data.copied.length);
- }
- str->data.copied.length = 0;
+static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
+ grpc_chttp2_hpack_parser_string *str) {
+ grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length);
+ str->length = 0;
return s;
}
@@ -807,8 +771,8 @@ static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (GRPC_MDISNULL(md)) {
+ grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ if (md == NULL) {
return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
@@ -849,13 +813,12 @@ static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
- grpc_error *err = on_hdr(
- exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
- take_string(exec_ctx, p, &p->value, true)),
- 1);
+ grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ GPR_ASSERT(md != NULL); /* handled in string parsing */
+ grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+ exec_ctx, GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 1);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -865,11 +828,10 @@ static grpc_error *finish_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_error *err = on_hdr(
- exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true),
- take_string(exec_ctx, p, &p->value, true)),
- 1);
+ grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+ exec_ctx, take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 1);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -919,13 +881,12 @@ static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
- grpc_error *err = on_hdr(
- exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
- take_string(exec_ctx, p, &p->value, false)),
- 0);
+ grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ GPR_ASSERT(md != NULL); /* handled in string parsing */
+ grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+ exec_ctx, GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -935,11 +896,10 @@ static grpc_error *finish_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_error *err = on_hdr(
- exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true),
- take_string(exec_ctx, p, &p->value, false)),
- 0);
+ grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+ exec_ctx, take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -989,13 +949,12 @@ static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
- grpc_error *err = on_hdr(
- exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
- take_string(exec_ctx, p, &p->value, false)),
- 0);
+ grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ GPR_ASSERT(md != NULL); /* handled in string parsing */
+ grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+ exec_ctx, GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -1005,11 +964,10 @@ static grpc_error *finish_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
const uint8_t *cur,
const uint8_t *end) {
- grpc_error *err = on_hdr(
- exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true),
- take_string(exec_ctx, p, &p->value, false)),
- 0);
+ grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+ exec_ctx, take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -1303,15 +1261,14 @@ static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx,
static void append_bytes(grpc_chttp2_hpack_parser_string *str,
const uint8_t *data, size_t length) {
if (length == 0) return;
- if (length + str->data.copied.length > str->data.copied.capacity) {
- GPR_ASSERT(str->data.copied.length + length <= UINT32_MAX);
- str->data.copied.capacity = (uint32_t)(str->data.copied.length + length);
- str->data.copied.str =
- gpr_realloc(str->data.copied.str, str->data.copied.capacity);
+ if (length + str->length > str->capacity) {
+ GPR_ASSERT(str->length + length <= UINT32_MAX);
+ str->capacity = (uint32_t)(str->length + length);
+ str->str = gpr_realloc(str->str, str->capacity);
}
- memcpy(str->data.copied.str + str->data.copied.length, data, length);
- GPR_ASSERT(length <= UINT32_MAX - str->data.copied.length);
- str->data.copied.length += (uint32_t)length;
+ memcpy(str->str + str->length, data, length);
+ GPR_ASSERT(length <= UINT32_MAX - str->length);
+ str->length += (uint32_t)length;
}
static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
@@ -1394,9 +1351,11 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
}
+/* append a null terminator to a string */
static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end) {
+ uint8_t terminator = 0;
uint8_t decoded[2];
uint32_t bits;
grpc_chttp2_hpack_parser_string *str = p->parsing.str;
@@ -1437,6 +1396,8 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
append_bytes(str, decoded, 2);
break;
}
+ append_bytes(str, &terminator, 1);
+ p->parsing.str->length--; /* don't actually count the null terminator */
return GRPC_ERROR_NONE;
}
@@ -1511,18 +1472,8 @@ static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx,
const uint8_t *cur, const uint8_t *end,
uint8_t binary,
grpc_chttp2_hpack_parser_string *str) {
- if (!p->huff && binary == NOT_BINARY && (end - cur) >= (intptr_t)p->strlen &&
- p->current_slice_refcount != NULL) {
- str->copied = false;
- str->data.referenced.refcount = p->current_slice_refcount;
- str->data.referenced.data.refcounted.bytes = (uint8_t *)cur;
- str->data.referenced.data.refcounted.length = p->strlen;
- grpc_slice_ref_internal(str->data.referenced);
- return parse_next(exec_ctx, p, cur + p->strlen, end);
- }
p->strgot = 0;
- str->copied = true;
- str->data.copied.length = 0;
+ str->length = 0;
p->parsing.str = str;
p->huff_state = 0;
p->binary = binary;
@@ -1539,22 +1490,21 @@ static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx,
/* check if a key represents a binary header or not */
static bool is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
- return grpc_is_binary_header(
- p->key.copied ? grpc_slice_from_static_buffer(p->key.data.copied.str,
- p->key.data.copied.length)
- : p->key.data.referenced);
+ return grpc_is_binary_header(p->key.str, p->key.length);
}
static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
bool *is) {
- grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (GRPC_MDISNULL(elem)) {
+ grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+ if (!elem) {
return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
}
- *is = grpc_is_binary_header(GRPC_MDKEY(elem));
+ *is = grpc_is_binary_header(
+ (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
+ GRPC_SLICE_LENGTH(elem->key->slice));
return GRPC_ERROR_NONE;
}
@@ -1589,14 +1539,12 @@ void grpc_chttp2_hpack_parser_init(grpc_exec_ctx *exec_ctx,
p->on_header = NULL;
p->on_header_user_data = NULL;
p->state = parse_begin;
- p->key.data.referenced = grpc_empty_slice();
- p->key.data.copied.str = NULL;
- p->key.data.copied.capacity = 0;
- p->key.data.copied.length = 0;
- p->value.data.referenced = grpc_empty_slice();
- p->value.data.copied.str = NULL;
- p->value.data.copied.capacity = 0;
- p->value.data.copied.length = 0;
+ p->key.str = NULL;
+ p->key.capacity = 0;
+ p->key.length = 0;
+ p->value.str = NULL;
+ p->value.capacity = 0;
+ p->value.length = 0;
p->dynamic_table_update_allowed = 2;
p->last_error = GRPC_ERROR_NONE;
grpc_chttp2_hptbl_init(exec_ctx, &p->table);
@@ -1611,24 +1559,19 @@ void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p) {
grpc_chttp2_hptbl_destroy(exec_ctx, &p->table);
GRPC_ERROR_UNREF(p->last_error);
- grpc_slice_unref_internal(exec_ctx, p->key.data.referenced);
- grpc_slice_unref_internal(exec_ctx, p->value.data.referenced);
- gpr_free(p->key.data.copied.str);
- gpr_free(p->value.data.copied.str);
+ gpr_free(p->key.str);
+ gpr_free(p->value.str);
}
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p,
- grpc_slice slice) {
+ const uint8_t *beg,
+ const uint8_t *end) {
/* TODO(ctiller): limit the distance of end from beg, and perform multiple
steps in the event of a large chunk of data to limit
stack space usage when no tail call optimization is
available */
- p->current_slice_refcount = slice.refcount;
- grpc_error *error = p->state(exec_ctx, p, GRPC_SLICE_START_PTR(slice),
- GRPC_SLICE_END_PTR(slice));
- p->current_slice_refcount = NULL;
- return error;
+ return p->state(exec_ctx, p, beg, end);
}
typedef void (*maybe_complete_func_type)(grpc_exec_ctx *exec_ctx,
@@ -1644,7 +1587,7 @@ static void force_client_rst_stream(grpc_exec_ctx *exec_ctx, void *sp,
grpc_chttp2_transport *t = s->t;
if (!s->write_closed) {
grpc_slice_buffer_add(
- &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
+ &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR,
&s->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, t, false, "force_rst_stream");
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, GRPC_ERROR_NONE);
@@ -1662,7 +1605,8 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
if (s != NULL) {
s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice);
}
- grpc_error *error = grpc_chttp2_hpack_parser_parse(exec_ctx, parser, slice);
+ grpc_error *error = grpc_chttp2_hpack_parser_parse(
+ exec_ctx, parser, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_END_PTR(slice));
if (error != GRPC_ERROR_NONE) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return error;