aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/transport
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/ext/transport')
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create.c8
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.c26
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2.c63
-rw-r--r--src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c91
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c373
-rw-r--r--src/core/ext/transport/chttp2/transport/frame.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.c71
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.h11
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.c37
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.c19
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.h6
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.c30
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.c44
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.c26
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c650
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.h14
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.c44
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h39
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c437
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c17
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.c4
26 files changed, 1174 insertions, 869 deletions
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
index c5d3d8d9cc..85f9efb3b6 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -79,11 +79,11 @@ static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
connector_unref(exec_ctx, arg);
}
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg;
grpc_closure *notify;
grpc_endpoint *tcp = c->tcp;
@@ -103,13 +103,13 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
GPR_ASSERT(c->result->transport);
- c->result->channel_args = c->args.channel_args;
+ c->result->channel_args = grpc_channel_args_copy(c->args.channel_args);
} else {
memset(c->result, 0, sizeof(*c->result));
}
notify = c->notify;
c->notify = NULL;
- notify->cb(exec_ctx, notify->cb_arg, 1);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
}
static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index a262306085..721ba82d8f 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -90,7 +90,6 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_auth_context *auth_context) {
connector *c = arg;
grpc_closure *notify;
- grpc_channel_args *args_copy = NULL;
gpr_mu_lock(&c->mu);
if (c->connecting_endpoint == NULL) {
memset(c->result, 0, sizeof(*c->result));
@@ -109,26 +108,23 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
auth_context_arg = grpc_auth_context_to_arg(auth_context);
- args_copy = grpc_channel_args_copy_and_add(c->args.channel_args,
- &auth_context_arg, 1);
- c->result->channel_args = args_copy;
+ c->result->channel_args = grpc_channel_args_copy_and_add(
+ c->args.channel_args, &auth_context_arg, 1);
}
notify = c->notify;
c->notify = NULL;
- /* look at c->args which are connector args. */
- notify->cb(exec_ctx, notify->cb_arg, 1);
- if (args_copy != NULL) grpc_channel_args_destroy(args_copy);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_NONE, NULL);
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
connector *c = arg;
- grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector,
- c->connecting_endpoint,
- on_secure_handshake_done, c);
+ grpc_channel_security_connector_do_handshake(
+ exec_ctx, c->security_connector, c->connecting_endpoint, c->args.deadline,
+ on_secure_handshake_done, c);
}
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg;
grpc_closure *notify;
grpc_endpoint *tcp = c->newly_connecting_endpoint;
@@ -147,13 +143,14 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
&c->initial_string_sent);
} else {
grpc_channel_security_connector_do_handshake(
- exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c);
+ exec_ctx, c->security_connector, tcp, c->args.deadline,
+ on_secure_handshake_done, c);
}
} else {
memset(c->result, 0, sizeof(*c->result));
notify = c->notify;
c->notify = NULL;
- notify->cb(exec_ctx, notify->cb_arg, 1);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
}
}
@@ -175,7 +172,6 @@ static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
grpc_closure *notify) {
connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL);
- GPR_ASSERT(notify->cb);
c->notify = notify;
c->args = *args;
c->result = result;
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index c95dd20d1d..9bae3a94f9 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -35,6 +35,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/http_server_filter.h"
@@ -74,34 +75,40 @@ static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
grpc_closure *destroy_done) {
grpc_tcp_server *tcp = tcpp;
grpc_tcp_server_unref(exec_ctx, tcp);
- grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_NONE, NULL);
}
int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp = NULL;
size_t i;
- unsigned count = 0;
+ size_t count = 0;
int port_num = -1;
int port_temp;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_error *err = GRPC_ERROR_NONE;
GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
(server, addr));
- resolved = grpc_blocking_resolve_address(addr, "http");
- if (!resolved) {
+ grpc_error **errors = NULL;
+ err = grpc_blocking_resolve_address(addr, "https", &resolved);
+ if (err != GRPC_ERROR_NONE) {
goto error;
}
- tcp = grpc_tcp_server_create(NULL);
- GPR_ASSERT(tcp);
+ err = grpc_tcp_server_create(NULL, &tcp);
+ if (err != GRPC_ERROR_NONE) {
+ goto error;
+ }
- for (i = 0; i < resolved->naddrs; i++) {
- port_temp = grpc_tcp_server_add_port(
+ const size_t naddrs = resolved->naddrs;
+ errors = gpr_malloc(sizeof(*errors) * naddrs);
+ for (i = 0; i < naddrs; i++) {
+ errors[i] = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
- resolved->addrs[i].len);
- if (port_temp > 0) {
+ resolved->addrs[i].len, &port_temp);
+ if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) {
port_num = port_temp;
} else {
@@ -111,14 +118,24 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
}
}
if (count == 0) {
- gpr_log(GPR_ERROR, "No address added out of total %" PRIuPTR " resolved",
- resolved->naddrs);
+ char *msg;
+ gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
+ naddrs);
+ err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
+ gpr_free(msg);
goto error;
- }
- if (count != resolved->naddrs) {
- gpr_log(GPR_ERROR,
- "Only %d addresses added out of total %" PRIuPTR " resolved", count,
- resolved->naddrs);
+ } else if (count != naddrs) {
+ char *msg;
+ gpr_asprintf(&msg, "Only %" PRIuPTR
+ " addresses added out of total %" PRIuPTR " resolved",
+ count, naddrs);
+ err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
+ gpr_free(msg);
+
+ const char *warning_message = grpc_error_string(err);
+ gpr_log(GPR_INFO, "WARNING: %s", warning_message);
+ grpc_error_free_string(warning_message);
+ /* we managed to bind some addresses: continue */
}
grpc_resolved_addresses_destroy(resolved);
@@ -128,6 +145,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
/* Error path: cleanup and return */
error:
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
@@ -136,7 +154,18 @@ error:
}
port_num = 0;
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "%s", msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(err);
+
done:
grpc_exec_ctx_finish(&exec_ctx);
+ if (errors != NULL) {
+ for (i = 0; i < naddrs; i++) {
+ GRPC_ERROR_UNREF(errors[i]);
+ }
+ }
+ gpr_free(errors);
return port_num;
}
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index e3437e5ed3..ead8a4d566 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -37,6 +37,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@@ -128,9 +129,11 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
state->state = statep;
state_ref(state->state);
state->accepting_pollset = accepting_pollset;
- grpc_server_security_connector_do_handshake(exec_ctx, state->state->sc,
- acceptor, tcp,
- on_secure_handshake_done, state);
+ grpc_server_security_connector_do_handshake(
+ exec_ctx, state->state->sc, acceptor, tcp,
+ gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_seconds(120, GPR_TIMESPAN)),
+ on_secure_handshake_done, state);
}
/* Server callback: start listening on our ports */
@@ -141,11 +144,12 @@ static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
on_accept, state);
}
-static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) {
+static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep,
+ grpc_error *error) {
server_secure_state *state = statep;
if (state->destroy_callback != NULL) {
state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
- success);
+ GRPC_ERROR_REF(error));
}
grpc_server_security_connector_shutdown(exec_ctx, state->sc);
state_unref(state);
@@ -171,12 +175,14 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_tcp_server *tcp = NULL;
server_secure_state *state = NULL;
size_t i;
- unsigned count = 0;
+ size_t count = 0;
int port_num = -1;
int port_temp;
grpc_security_status status = GRPC_SECURITY_ERROR;
grpc_server_security_connector *sc = NULL;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_error *err = GRPC_ERROR_NONE;
+ grpc_error **errors = NULL;
GRPC_API_TRACE(
"grpc_server_add_secure_http2_port("
@@ -184,26 +190,34 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
3, (server, addr, creds));
/* create security context */
- if (creds == NULL) goto error;
+ if (creds == NULL) {
+ err = GRPC_ERROR_CREATE(
+ "No credentials specified for secure server port (creds==NULL)");
+ goto error;
+ }
status = grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) {
- gpr_log(GPR_ERROR,
- "Unable to create secure server with credentials of type %s.",
- creds->type);
+ char *msg;
+ gpr_asprintf(&msg,
+ "Unable to create secure server with credentials of type %s.",
+ creds->type);
+ err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
+ GRPC_ERROR_INT_SECURITY_STATUS, status);
+ gpr_free(msg);
goto error;
}
sc->channel_args = grpc_server_get_channel_args(server);
/* resolve address */
- resolved = grpc_blocking_resolve_address(addr, "https");
- if (!resolved) {
+ err = grpc_blocking_resolve_address(addr, "https", &resolved);
+ if (err != GRPC_ERROR_NONE) {
goto error;
}
state = gpr_malloc(sizeof(*state));
memset(state, 0, sizeof(*state));
grpc_closure_init(&state->destroy_closure, destroy_done, state);
- tcp = grpc_tcp_server_create(&state->destroy_closure);
- if (!tcp) {
+ err = grpc_tcp_server_create(&state->destroy_closure, &tcp);
+ if (err != GRPC_ERROR_NONE) {
goto error;
}
@@ -215,11 +229,12 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
gpr_mu_init(&state->mu);
gpr_ref_init(&state->refcount, 1);
+ errors = gpr_malloc(sizeof(*errors) * resolved->naddrs);
for (i = 0; i < resolved->naddrs; i++) {
- port_temp = grpc_tcp_server_add_port(
+ errors[i] = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
- resolved->addrs[i].len);
- if (port_temp > 0) {
+ resolved->addrs[i].len, &port_temp);
+ if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) {
port_num = port_temp;
} else {
@@ -229,16 +244,31 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
}
}
if (count == 0) {
- gpr_log(GPR_ERROR, "No address added out of total %" PRIuPTR " resolved",
- resolved->naddrs);
+ char *msg;
+ gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
+ resolved->naddrs);
+ err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
+ gpr_free(msg);
goto error;
+ } else if (count != resolved->naddrs) {
+ char *msg;
+ gpr_asprintf(&msg, "Only %" PRIuPTR
+ " addresses added out of total %" PRIuPTR " resolved",
+ count, resolved->naddrs);
+ err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
+ gpr_free(msg);
+
+ const char *warning_message = grpc_error_string(err);
+ gpr_log(GPR_INFO, "WARNING: %s", warning_message);
+ grpc_error_free_string(warning_message);
+ /* we managed to bind some addresses: continue */
+ } else {
+ for (i = 0; i < resolved->naddrs; i++) {
+ GRPC_ERROR_UNREF(errors[i]);
+ }
}
- if (count != resolved->naddrs) {
- gpr_log(GPR_ERROR,
- "Only %d addresses added out of total %" PRIuPTR " resolved", count,
- resolved->naddrs);
- /* if it's an error, don't we want to goto error; here ? */
- }
+ gpr_free(errors);
+ errors = NULL;
grpc_resolved_addresses_destroy(resolved);
/* Register with the server only upon success */
@@ -249,6 +279,13 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
/* Error path: cleanup and return */
error:
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
+ if (errors != NULL) {
+ for (i = 0; i < resolved->naddrs; i++) {
+ GRPC_ERROR_UNREF(errors[i]);
+ }
+ gpr_free(errors);
+ }
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
@@ -263,5 +300,9 @@ error:
}
}
grpc_exec_ctx_finish(&exec_ctx);
+ const char *msg = grpc_error_string(err);
+ GRPC_ERROR_UNREF(err);
+ gpr_log(GPR_ERROR, "%s", msg);
+ grpc_error_free_string(msg);
return 0;
}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 6e8640f1b3..9aa39ba26c 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -85,19 +85,17 @@ int grpc_flowctl_trace = 0;
static const grpc_transport_vtable vtable;
/* forward declarations of various callbacks that we'll build closures around */
-static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
- bool iomgr_success_ignored);
-static void reading_action(grpc_exec_ctx *exec_ctx, void *t,
- bool iomgr_success_ignored);
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *t,
- bool iomgr_success_ignored);
+static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
+static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
/** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value);
/** Start disconnection chain */
-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);
/** Perform a transport_op */
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
@@ -135,7 +133,7 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_connectivity_state state, const char *reason);
+ grpc_connectivity_state state, grpc_error *error, const char *reason);
static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global);
@@ -149,7 +147,9 @@ static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s,
void *byte_stream);
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global);
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global,
+ grpc_error *error);
/*******************************************************************************
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
@@ -194,7 +194,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
and maybe they hold resources that need to be freed */
while (t->global.pings.next != &t->global.pings) {
grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
- grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, ping->on_recv,
+ GRPC_ERROR_CREATE("Transport closed"), NULL);
ping->next->prev = ping->prev;
ping->prev->next = ping->next;
gpr_free(ping);
@@ -409,7 +410,7 @@ static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_ignored,
void *arg_ignored) {
t->destroying = 1;
- drop_connection(exec_ctx, t);
+ drop_connection(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed"));
}
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
@@ -445,12 +446,11 @@ static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_ignored,
- void *arg_ignored) {
+ grpc_error *error) {
if (!t->closed) {
t->closed = 1;
connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
- "close_transport");
+ GRPC_ERROR_REF(error), "close_transport");
if (t->ep) {
allow_endpoint_shutdown_locked(exec_ctx, t);
}
@@ -463,6 +463,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
}
+ GRPC_ERROR_UNREF(error);
}
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
@@ -551,7 +552,9 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
s->global.id == 0);
GPR_ASSERT(!s->global.in_stream_map);
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+ close_transport_locked(
+ exec_ctx, t,
+ GRPC_ERROR_CREATE("Last stream closed after sending goaway"));
}
if (!t->executor.parsing_active && s->global.id) {
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
@@ -645,7 +648,7 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
t->executor.writing_active = 1;
REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t);
- grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
}
check_read_ops(exec_ctx, &t->global);
@@ -756,12 +759,12 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_ignored,
void *a) {
- bool success = (bool)(uintptr_t)a;
+ grpc_error *error = a;
allow_endpoint_shutdown_locked(exec_ctx, t);
- if (!success) {
- drop_connection(exec_ctx, t);
+ if (error != GRPC_ERROR_NONE) {
+ drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
}
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
@@ -769,7 +772,8 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) {
- fail_pending_writes(exec_ctx, stream_global);
+ fail_pending_writes(exec_ctx, &t->global, stream_global,
+ GRPC_ERROR_REF(error));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
}
@@ -782,18 +786,18 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
}
UNREF_TRANSPORT(exec_ctx, t, "writing");
+ GRPC_ERROR_UNREF(error);
}
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
- void *transport_writing, bool success) {
+ void *transport_writing, grpc_error *error) {
grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
- grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL,
- terminate_writing_with_lock,
- (void *)(uintptr_t)success, 0);
+ grpc_chttp2_run_with_global_lock(
+ exec_ctx, t, NULL, terminate_writing_with_lock, GRPC_ERROR_REF(error), 0);
}
static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
- bool iomgr_success_ignored) {
+ grpc_error *error) {
grpc_chttp2_transport *t = gt;
GPR_TIMER_BEGIN("writing_action", 0);
grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
@@ -806,13 +810,19 @@ void grpc_chttp2_add_incoming_goaway(
char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
- gpr_free(msg);
gpr_slice_unref(goaway_text);
transport_global->seen_goaway = 1;
/* lie: use transient failure from the transport to indicate goaway has been
* received */
- connectivity_state_set(exec_ctx, transport_global,
- GRPC_CHANNEL_TRANSIENT_FAILURE, "got_goaway");
+ connectivity_state_set(
+ exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ grpc_error_set_str(
+ grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"),
+ GRPC_ERROR_INT_HTTP2_ERROR,
+ (intptr_t)goaway_error),
+ GRPC_ERROR_STR_RAW_BYTES, msg),
+ "got_goaway");
+ gpr_free(msg);
}
static void maybe_start_some_streams(
@@ -841,9 +851,9 @@ static void maybe_start_some_streams(
transport_global->next_stream_id += 2;
if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
- connectivity_state_set(exec_ctx, transport_global,
- GRPC_CHANNEL_TRANSIENT_FAILURE,
- "no_more_stream_ids");
+ connectivity_state_set(
+ exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_CREATE("Stream IDs exhausted"), "no_more_stream_ids");
}
stream_global->outgoing_window =
@@ -871,34 +881,40 @@ static void maybe_start_some_streams(
}
#define CLOSURE_BARRIER_STATS_BIT (1 << 0)
-#define CLOSURE_BARRIER_FAILURE_BIT (1 << 1)
#define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16)
static grpc_closure *add_closure_barrier(grpc_closure *closure) {
- closure->final_data += CLOSURE_BARRIER_FIRST_REF_BIT;
+ closure->next_data.scratch += CLOSURE_BARRIER_FIRST_REF_BIT;
return closure;
}
-void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global,
- grpc_closure **pclosure, int success) {
+void grpc_chttp2_complete_closure_step(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
+ grpc_error *error) {
grpc_closure *closure = *pclosure;
if (closure == NULL) {
+ GRPC_ERROR_UNREF(error);
return;
}
- closure->final_data -= CLOSURE_BARRIER_FIRST_REF_BIT;
- if (!success) {
- closure->final_data |= CLOSURE_BARRIER_FAILURE_BIT;
+ closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
+ if (error != GRPC_ERROR_NONE) {
+ if (closure->error == GRPC_ERROR_NONE) {
+ closure->error =
+ GRPC_ERROR_CREATE("Error in HTTP transport completing operation");
+ closure->error = grpc_error_set_str(
+ closure->error, GRPC_ERROR_STR_TARGET_ADDRESS,
+ TRANSPORT_FROM_GLOBAL(transport_global)->peer_string);
+ }
+ closure->error = grpc_error_add_child(closure->error, error);
}
- if (closure->final_data < CLOSURE_BARRIER_FIRST_REF_BIT) {
- if (closure->final_data & CLOSURE_BARRIER_STATS_BIT) {
+ if (closure->next_data.scratch < CLOSURE_BARRIER_FIRST_REF_BIT) {
+ if (closure->next_data.scratch & CLOSURE_BARRIER_STATS_BIT) {
grpc_transport_move_stats(&stream_global->stats,
stream_global->collecting_stats);
stream_global->collecting_stats = NULL;
}
- grpc_exec_ctx_enqueue(
- exec_ctx, closure,
- (closure->final_data & CLOSURE_BARRIER_FAILURE_BIT) == 0, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, closure->error, NULL);
}
*pclosure = NULL;
}
@@ -916,7 +932,7 @@ static int contains_non_ok_status(
return 0;
}
-static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
@@ -933,12 +949,13 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
}
/* use final_data as a barrier until enqueue time; the inital counter is
dropped at the end of this function */
- on_complete->final_data = CLOSURE_BARRIER_FIRST_REF_BIT;
+ on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT;
+ on_complete->error = GRPC_ERROR_NONE;
if (op->collect_stats != NULL) {
GPR_ASSERT(stream_global->collecting_stats == NULL);
stream_global->collecting_stats = op->collect_stats;
- on_complete->final_data |= CLOSURE_BARRIER_STATS_BIT;
+ on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT;
}
if (op->cancel_with_status != GRPC_STATUS_OK) {
@@ -985,8 +1002,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
}
} else {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_initial_metadata_finished, 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_initial_metadata_finished,
+ GRPC_ERROR_CREATE(
+ "Attempt to send initial metadata after stream was closed"));
}
}
}
@@ -997,7 +1016,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
stream_global->send_message_finished = add_closure_barrier(on_complete);
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_message_finished, 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_message_finished,
+ GRPC_ERROR_CREATE("Attempt to send message after stream was closed"));
} else {
stream_global->send_message = op->send_message;
if (stream_global->id != 0) {
@@ -1031,9 +1052,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
}
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
+ exec_ctx, transport_global, stream_global,
&stream_global->send_trailing_metadata_finished,
- grpc_metadata_batch_is_empty(op->send_trailing_metadata));
+ grpc_metadata_batch_is_empty(op->send_trailing_metadata)
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE("Attempt to send trailing metadata after "
+ "stream was closed"));
} else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */
@@ -1072,7 +1096,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
- grpc_chttp2_complete_closure_step(exec_ctx, stream_global, &on_complete, 1);
+ grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
+ &on_complete, GRPC_ERROR_NONE);
GPR_TIMER_END("perform_stream_op_locked", 0);
}
@@ -1109,7 +1134,7 @@ static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
for (ping = transport_global->pings.next; ping != &transport_global->pings;
ping = ping->next) {
if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
- grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL);
ping->next->prev = ping->prev;
ping->prev->next = ping->next;
gpr_free(ping);
@@ -1131,7 +1156,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_unused,
void *stream_op) {
grpc_transport_op *op = stream_op;
- bool close_transport = op->disconnect;
+ grpc_error *close_transport = op->disconnect_with_error;
/* If there's a set_accept_stream ensure that we're not parsing
to avoid changing things out from underneath */
@@ -1142,7 +1167,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
return;
}
- grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change(
@@ -1156,7 +1181,9 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
t->global.last_incoming_stream_id,
(uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
- close_transport = !grpc_chttp2_has_streams(t);
+ close_transport = grpc_chttp2_has_streams(t)
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE("GOAWAY sent");
}
if (op->set_accept_stream) {
@@ -1177,8 +1204,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
send_ping_locked(t, op->send_ping);
}
- if (close_transport) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+ if (close_transport != GRPC_ERROR_NONE) {
+ close_transport_locked(exec_ctx, t, close_transport);
}
}
@@ -1214,8 +1241,8 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_metadata_buffer_publish(
&stream_global->received_initial_metadata,
stream_global->recv_initial_metadata);
- grpc_exec_ctx_enqueue(
- exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, stream_global->recv_initial_metadata_ready,
+ GRPC_ERROR_NONE, NULL);
stream_global->recv_initial_metadata_ready = NULL;
}
if (stream_global->recv_message_ready != NULL) {
@@ -1228,13 +1255,13 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
*stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
&stream_global->incoming_frames);
GPR_ASSERT(*stream_global->recv_message != NULL);
- grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
- NULL);
+ grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
+ GRPC_ERROR_NONE, NULL);
stream_global->recv_message_ready = NULL;
} else if (stream_global->published_trailing_metadata) {
*stream_global->recv_message = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
- NULL);
+ grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
+ GRPC_ERROR_NONE, NULL);
stream_global->recv_message_ready = NULL;
}
}
@@ -1255,8 +1282,8 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
&stream_global->received_trailing_metadata,
stream_global->recv_trailing_metadata);
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->recv_trailing_metadata_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->recv_trailing_metadata_finished, GRPC_ERROR_NONE);
}
}
}
@@ -1272,7 +1299,7 @@ static void decrement_active_streams_locked(
}
static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- uint32_t id) {
+ uint32_t id, grpc_error *error) {
size_t new_stream_count;
grpc_chttp2_stream *s =
grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
@@ -1287,12 +1314,15 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
if (s->parsing.data_parser.parsing_frame != NULL) {
grpc_chttp2_incoming_byte_stream_finished(
- exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0);
+ exec_ctx, s->parsing.data_parser.parsing_frame,
+ GRPC_ERROR_CREATE_REFERENCING("Stream removed", &error, 1), 0);
s->parsing.data_parser.parsing_frame = NULL;
}
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+ close_transport_locked(
+ exec_ctx, t,
+ GRPC_ERROR_CREATE("Last stream closed after sending GOAWAY"));
}
if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
@@ -1305,6 +1335,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->global.concurrent_stream_count = (uint32_t)new_stream_count;
maybe_start_some_streams(exec_ctx, &t->global);
}
+ GRPC_ERROR_UNREF(error);
}
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
@@ -1332,8 +1363,10 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
stream_global->seen_error = true;
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
- grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
- 1);
+ grpc_chttp2_mark_stream_closed(
+ exec_ctx, transport_global, stream_global, 1, 1,
+ grpc_error_set_int(GRPC_ERROR_CREATE("Cancelled"),
+ GRPC_ERROR_INT_GRPC_STATUS, status));
}
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
@@ -1374,23 +1407,27 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
}
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global) {
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global,
+ grpc_error *error) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_initial_metadata_finished,
- 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_trailing_metadata_finished,
- 0);
- grpc_chttp2_complete_closure_step(exec_ctx, stream_global,
- &stream_global->send_message_finished, 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_trailing_metadata_finished, GRPC_ERROR_REF(error));
+ grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
+ &stream_global->send_message_finished,
+ error);
}
void grpc_chttp2_mark_stream_closed(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global, int close_reads,
- int close_writes) {
+ grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
+ grpc_error *error) {
if (stream_global->read_closed && stream_global->write_closed) {
/* already closed */
+ GRPC_ERROR_UNREF(error);
return;
}
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
@@ -1407,7 +1444,8 @@ void grpc_chttp2_mark_stream_closed(
grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
stream_global);
} else {
- fail_pending_writes(exec_ctx, stream_global);
+ fail_pending_writes(exec_ctx, transport_global, stream_global,
+ GRPC_ERROR_REF(error));
}
}
if (stream_global->read_closed && stream_global->write_closed) {
@@ -1418,11 +1456,12 @@ void grpc_chttp2_mark_stream_closed(
} else {
if (stream_global->id != 0) {
remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
- stream_global->id);
+ stream_global->id, GRPC_ERROR_REF(error));
}
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
}
+ GRPC_ERROR_UNREF(error);
}
static void close_from_api(grpc_exec_ctx *exec_ctx,
@@ -1529,8 +1568,16 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
optional_message);
+ grpc_error *err = GRPC_ERROR_CREATE("Stream closed");
+ err = grpc_error_set_int(err, GRPC_ERROR_INT_GRPC_STATUS, status);
+ if (optional_message) {
+ char *str =
+ gpr_dump_slice(*optional_message, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ err = grpc_error_set_str(err, GRPC_ERROR_STR_GRPC_MESSAGE, str);
+ gpr_free(str);
+ }
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
- 1);
+ 1, err);
}
static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
@@ -1549,8 +1596,9 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb);
}
-static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_error *error) {
+ close_transport_locked(exec_ctx, t, error);
end_all_the_calls(exec_ctx, t);
}
@@ -1581,20 +1629,22 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg);
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error);
static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg);
static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg);
-static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
+static void reading_action(grpc_exec_ctx *exec_ctx, void *tp,
+ grpc_error *error) {
/* Control flow:
reading_action_locked ->
(parse_unlocked -> post_parse_locked)? ->
post_reading_action_locked */
grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
- (void *)(uintptr_t)success, 0);
+ GRPC_ERROR_REF(error), 0);
}
static void reading_action_locked(grpc_exec_ctx *exec_ctx,
@@ -1602,7 +1652,7 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_unused, void *arg) {
grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
- bool success = (bool)(uintptr_t)arg;
+ grpc_error *error = arg;
GPR_ASSERT(!t->executor.parsing_active);
if (!t->closed) {
@@ -1611,48 +1661,54 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_map_move_into(&t->new_stream_map,
&t->parsing_stream_map);
grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
- grpc_exec_ctx_enqueue(exec_ctx, &t->parsing_action, success, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, error, NULL);
} else {
post_reading_action_locked(exec_ctx, t, s_unused, arg);
}
}
-static bool try_http_parsing(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t) {
+static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
grpc_http_parser parser;
size_t i = 0;
- bool success = false;
+ grpc_error *error = GRPC_ERROR_NONE;
+ grpc_http_response response;
+ memset(&response, 0, sizeof(response));
- grpc_http_parser_init(&parser);
+ grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
- for (; i < t->read_buffer.count &&
- grpc_http_parser_parse(&parser, t->read_buffer.slices[i]);
- i++)
- ;
- if (grpc_http_parser_eof(&parser) && parser.type == GRPC_HTTP_RESPONSE) {
- success = true;
- GRPC_CHTTP2_IF_TRACING(gpr_log(
- GPR_DEBUG, "Trying to connect an http1.x server, received status:%d",
- parser.http.response.status));
+ grpc_error *parse_error = GRPC_ERROR_NONE;
+ for (; i < t->read_buffer.count && parse_error == GRPC_ERROR_NONE; i++) {
+ parse_error = grpc_http_parser_parse(&parser, t->read_buffer.slices[i]);
+ }
+ if (parse_error == GRPC_ERROR_NONE &&
+ (parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
+ error = grpc_error_set_int(
+ GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
+ GRPC_ERROR_INT_HTTP_STATUS, response.status);
}
+ GRPC_ERROR_UNREF(parse_error);
grpc_http_parser_destroy(&parser);
- return success;
+ grpc_http_response_destroy(&response);
+ return error;
}
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
grpc_chttp2_transport *t = arg;
GPR_TIMER_BEGIN("reading_action.parse", 0);
size_t i = 0;
- for (; i < t->read_buffer.count &&
- grpc_chttp2_perform_read(exec_ctx, &t->parsing,
- t->read_buffer.slices[i]);
- i++)
- ;
+ grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
+ GRPC_ERROR_NONE};
+ for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
+ errors[1] = grpc_chttp2_perform_read(exec_ctx, &t->parsing,
+ t->read_buffer.slices[i]);
+ };
if (i != t->read_buffer.count) {
- success = false;
gpr_slice_unref(t->optional_drop_message);
- if (try_http_parsing(exec_ctx, t)) {
+ errors[2] = try_http_parsing(exec_ctx, t);
+ if (errors[2] != GRPC_ERROR_NONE) {
t->optional_drop_message = gpr_slice_from_copied_string(
"Connection dropped: received http1.x response");
} else {
@@ -1660,9 +1716,18 @@ static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
"Connection dropped: received unparseable response");
}
}
+ grpc_error *err =
+ errors[0] == GRPC_ERROR_NONE && errors[1] == GRPC_ERROR_NONE &&
+ errors[2] == GRPC_ERROR_NONE
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors,
+ GPR_ARRAY_SIZE(errors));
+ for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
+ GRPC_ERROR_UNREF(errors[i]);
+ }
GPR_TIMER_END("reading_action.parse", 0);
- grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked,
- (void *)(uintptr_t)success, 0);
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, err,
+ 0);
}
static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -1699,7 +1764,8 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(stream_global->in_stream_map);
GPR_ASSERT(stream_global->write_closed);
GPR_ASSERT(stream_global->read_closed);
- remove_stream(exec_ctx, t, stream_global->id);
+ remove_stream(exec_ctx, t, stream_global->id,
+ GRPC_ERROR_CREATE("Stream removed"));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
@@ -1710,10 +1776,13 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused,
void *arg) {
- bool success = (bool)(uintptr_t)arg;
+ grpc_error *error = arg;
bool keep_reading = false;
- if (!success || t->closed) {
- drop_connection(exec_ctx, t);
+ if (error == GRPC_ERROR_NONE && t->closed) {
+ error = GRPC_ERROR_CREATE("Transport closed");
+ }
+ if (error != GRPC_ERROR_NONE) {
+ drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0;
if (!t->executor.writing_active && t->ep) {
grpc_endpoint_destroy(exec_ctx, t->ep);
@@ -1735,6 +1804,8 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
} else {
UNREF_TRANSPORT(exec_ctx, t, "reading_action");
}
+
+ GRPC_ERROR_UNREF(error);
}
/*******************************************************************************
@@ -1743,13 +1814,13 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_connectivity_state state, const char *reason) {
+ grpc_connectivity_state state, grpc_error *error, const char *reason) {
GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
grpc_connectivity_state_set(
exec_ctx,
&TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
- state, reason);
+ state, error, reason);
}
/*******************************************************************************
@@ -1795,6 +1866,7 @@ static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs) {
if (gpr_unref(&bs->refs)) {
+ GRPC_ERROR_UNREF(bs->error);
gpr_slice_buffer_destroy(&bs->slices);
gpr_free(bs);
}
@@ -1863,9 +1935,10 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
}
if (bs->slices.count > 0) {
*arg->slice = gpr_slice_buffer_take_first(&bs->slices);
- grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, true, NULL);
- } else if (bs->failed) {
- grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_NONE, NULL);
+ } else if (bs->error != GRPC_ERROR_NONE) {
+ grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_REF(bs->error),
+ NULL);
} else {
bs->on_next = arg->on_complete;
bs->next = arg->slice;
@@ -1922,7 +1995,7 @@ static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
if (bs->on_next != NULL) {
*bs->next = arg->slice;
- grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
bs->on_next = NULL;
} else {
gpr_slice_buffer_add(&bs->slices, arg->slice);
@@ -1940,13 +2013,30 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
sizeof(arg));
}
+typedef struct {
+ grpc_chttp2_incoming_byte_stream *bs;
+ grpc_error *error;
+} bs_fail_args;
+
+static bs_fail_args *make_bs_fail_args(grpc_chttp2_incoming_byte_stream *bs,
+ grpc_error *error) {
+ bs_fail_args *a = gpr_malloc(sizeof(*a));
+ a->bs = bs;
+ a->error = error;
+ return a;
+}
+
static void incoming_byte_stream_finished_failed_locked(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
void *argp) {
- grpc_chttp2_incoming_byte_stream *bs = argp;
- grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
+ bs_fail_args *a = argp;
+ grpc_chttp2_incoming_byte_stream *bs = a->bs;
+ grpc_error *error = a->error;
+ gpr_free(a);
+ grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL);
bs->on_next = NULL;
- bs->failed = 1;
+ GRPC_ERROR_UNREF(bs->error);
+ bs->error = error;
incoming_byte_stream_unref(exec_ctx, bs);
}
@@ -1959,25 +2049,26 @@ static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
}
void grpc_chttp2_incoming_byte_stream_finished(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
- int from_parsing_thread) {
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+ grpc_error *error, int from_parsing_thread) {
if (from_parsing_thread) {
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
incoming_byte_stream_finished_ok_locked,
bs, 0);
} else {
- incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
- bs->stream, bs);
- }
- } else {
- if (success) {
grpc_chttp2_run_with_global_lock(
exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_finished_failed_locked, bs, 0);
+ incoming_byte_stream_finished_failed_locked,
+ make_bs_fail_args(bs, error), 0);
+ }
+ } else {
+ if (error == GRPC_ERROR_NONE) {
+ incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
+ bs->stream, bs);
} else {
- incoming_byte_stream_finished_failed_locked(exec_ctx, bs->transport,
- bs->stream, bs);
+ incoming_byte_stream_finished_failed_locked(
+ exec_ctx, bs->transport, bs->stream, make_bs_fail_args(bs, error));
}
}
}
@@ -2000,7 +2091,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
gpr_slice_buffer_init(&incoming_byte_stream->slices);
incoming_byte_stream->on_next = NULL;
incoming_byte_stream->is_tail = 1;
- incoming_byte_stream->failed = 0;
+ incoming_byte_stream->error = GRPC_ERROR_NONE;
if (add_to_queue->head == NULL) {
add_to_queue->head = incoming_byte_stream;
} else {
@@ -2141,5 +2232,5 @@ void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
- reading_action(exec_ctx, t, 1);
+ reading_action(exec_ctx, t, GRPC_ERROR_NONE);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index 5c72d91c2a..7776609367 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -37,13 +37,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/slice.h>
-/* Common definitions for frame handling in the chttp2 transport */
-
-typedef enum {
- GRPC_CHTTP2_PARSE_OK,
- GRPC_CHTTP2_STREAM_ERROR,
- GRPC_CHTTP2_CONNECTION_ERROR
-} grpc_chttp2_parse_error;
+#include "src/core/lib/iomgr/error.h"
/* defined in internal.h */
typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing;
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c
index 3a6d80e0a3..9046fbc453 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.c
+++ b/src/core/ext/transport/chttp2/transport/frame_data.c
@@ -37,24 +37,25 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport.h"
-grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
- grpc_chttp2_data_parser *parser) {
+grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser) {
parser->state = GRPC_CHTTP2_DATA_FH_0;
parser->parsing_frame = NULL;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser) {
grpc_byte_stream *bs;
if (parser->parsing_frame) {
- grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame,
- 0, 1);
+ grpc_chttp2_incoming_byte_stream_finished(
+ exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed"),
+ 1);
}
while (
(bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
@@ -62,11 +63,16 @@ void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
}
}
-grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
- grpc_chttp2_data_parser *parser, uint8_t flags) {
+grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
+ uint8_t flags,
+ uint32_t stream_id) {
if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
- gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags);
- return GRPC_CHTTP2_STREAM_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
+ grpc_error *err = grpc_error_set_int(
+ GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
+ gpr_free(msg);
+ return err;
}
if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
@@ -75,7 +81,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
parser->is_last_frame = 0;
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
void grpc_chttp2_incoming_frame_queue_merge(
@@ -139,7 +145,7 @@ void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
stats->data_bytes += write_bytes;
}
-grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+grpc_error *grpc_chttp2_data_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -149,19 +155,20 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_data_parser *p = parser;
uint32_t message_flags;
grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
+ char *msg;
if (is_last && p->is_last_frame) {
stream_parsing->received_close = 1;
}
if (cur == end) {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
switch (p->state) {
case GRPC_CHTTP2_DATA_ERROR:
p->state = GRPC_CHTTP2_DATA_ERROR;
- return GRPC_CHTTP2_STREAM_ERROR;
+ return GRPC_ERROR_REF(p->error);
fh_0:
case GRPC_CHTTP2_DATA_FH_0:
stream_parsing->stats.incoming.framing_bytes++;
@@ -174,13 +181,23 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->is_frame_compressed = 1; /* GPR_TRUE */
break;
default:
- gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
+ gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
+ p->error = GRPC_ERROR_CREATE(msg);
+ p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
+ (intptr_t)stream_parsing->id);
+ gpr_free(msg);
+ msg = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ p->error =
+ grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg);
+ gpr_free(msg);
+ p->error =
+ grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
p->state = GRPC_CHTTP2_DATA_ERROR;
- return GRPC_CHTTP2_STREAM_ERROR;
+ return GRPC_ERROR_REF(p->error);
}
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_1:
@@ -188,7 +205,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size = ((uint32_t)*cur) << 24;
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_2:
@@ -196,7 +213,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size |= ((uint32_t)*cur) << 16;
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_3:
@@ -204,7 +221,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size |= ((uint32_t)*cur) << 8;
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_4;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_4:
@@ -225,7 +242,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
stream_parsing);
if (cur == end) {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
uint32_t remaining = (uint32_t)(end - cur);
if (remaining == p->frame_size) {
@@ -233,19 +250,19 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame,
gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
- grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
- 1);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
+ GRPC_ERROR_NONE, 1);
p->parsing_frame = NULL;
p->state = GRPC_CHTTP2_DATA_FH_0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
} else if (remaining > p->frame_size) {
stream_parsing->stats.incoming.data_bytes += p->frame_size;
grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame,
gpr_slice_sub(slice, (size_t)(cur - beg),
(size_t)(cur + p->frame_size - beg)));
- grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
- 1);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
+ GRPC_ERROR_NONE, 1);
p->parsing_frame = NULL;
cur += p->frame_size;
goto fh_0; /* loop */
@@ -256,9 +273,9 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
p->frame_size -= remaining;
stream_parsing->stats.incoming.data_bytes += remaining;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
}
- GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index af71f483a2..a21a7942b9 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -66,6 +66,7 @@ typedef struct {
uint8_t is_last_frame;
uint8_t frame_type;
uint32_t frame_size;
+ grpc_error *error;
int is_frame_compressed;
grpc_chttp2_incoming_frame_queue incoming_frames;
@@ -79,19 +80,19 @@ grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
grpc_chttp2_incoming_frame_queue *q);
/* initialize per-stream state for data frame parsing */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
- grpc_chttp2_data_parser *parser);
+grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser);
void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser);
/* start processing a new data frame */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
- grpc_chttp2_data_parser *parser, uint8_t flags);
+grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
+ uint8_t flags,
+ uint32_t stream_id);
/* handle a slice of a data frame - is_last indicates the last slice of a
frame */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+grpc_error *grpc_chttp2_data_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c
index 827e7a6977..299e27ad70 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.c
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) {
p->debug_data = NULL;
@@ -47,11 +48,15 @@ void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) {
gpr_free(p->debug_data);
}
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
- grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) {
+grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p,
+ uint32_t length,
+ uint8_t flags) {
if (length < 8) {
- gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
gpr_free(p->debug_data);
@@ -59,10 +64,10 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
p->debug_data = gpr_malloc(p->debug_length);
p->debug_pos = 0;
p->state = GRPC_CHTTP2_GOAWAY_LSI0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
+grpc_error *grpc_chttp2_goaway_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -75,7 +80,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI0:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id = ((uint32_t)*cur) << 24;
++cur;
@@ -83,7 +88,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI1:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id |= ((uint32_t)*cur) << 16;
++cur;
@@ -91,7 +96,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI2:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id |= ((uint32_t)*cur) << 8;
++cur;
@@ -99,7 +104,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI3:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id |= ((uint32_t)*cur);
++cur;
@@ -107,7 +112,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR0:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code = ((uint32_t)*cur) << 24;
++cur;
@@ -115,7 +120,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR1:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code |= ((uint32_t)*cur) << 16;
++cur;
@@ -123,7 +128,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR2:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code |= ((uint32_t)*cur) << 8;
++cur;
@@ -131,7 +136,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR3:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code |= ((uint32_t)*cur);
++cur;
@@ -151,9 +156,9 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
p->debug_data = NULL;
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
- GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
index 7c38b26a39..eb4303405a 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -63,9 +63,9 @@ typedef struct {
void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p);
void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p);
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
+grpc_error *grpc_chttp2_goaway_parser_begin_frame(
grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
+grpc_error *grpc_chttp2_goaway_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 7e1815f0fe..1f814ab1bd 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
gpr_slice slice = gpr_slice_malloc(9 + 8);
@@ -57,18 +58,22 @@ gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
return slice;
}
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
- grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) {
+grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
+ uint32_t length,
+ uint8_t flags) {
if (flags & 0xfe || length != 8) {
- gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags);
+ grpc_error *error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return error;
}
parser->byte = 0;
parser->is_ack = flags;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+grpc_error *grpc_chttp2_ping_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -93,5 +98,5 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
}
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index 4f7fcc1305..5a8723421c 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -46,9 +46,9 @@ typedef struct {
gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
- grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
+ uint32_t length, uint8_t flags);
+grpc_error *grpc_chttp2_ping_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
index 7f01105e3e..a7aefb9915 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -34,7 +34,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
@@ -67,18 +69,21 @@ gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
return slice;
}
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) {
if (length != 4) {
- gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length,
- flags);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid rst_stream: length=%d, flags=%02x", length,
+ flags);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
parser->byte = 0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
+grpc_error *grpc_chttp2_rst_stream_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -97,12 +102,13 @@ grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
if (p->byte == 4) {
GPR_ASSERT(is_last);
stream_parsing->received_close = 1;
- stream_parsing->saw_rst_stream = 1;
- stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) |
- (((uint32_t)p->reason_bytes[1]) << 16) |
- (((uint32_t)p->reason_bytes[2]) << 8) |
- (((uint32_t)p->reason_bytes[3]));
+ stream_parsing->forced_close_error = grpc_error_set_int(
+ GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR,
+ (intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) |
+ (((uint32_t)p->reason_bytes[1]) << 16) |
+ (((uint32_t)p->reason_bytes[2]) << 8) |
+ (((uint32_t)p->reason_bytes[3]))));
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
index 9c1e756a94..11cf94f3ea 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -47,9 +47,9 @@ typedef struct {
gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code,
grpc_transport_one_way_stats *stats);
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
+grpc_error *grpc_chttp2_rst_stream_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index a3c1e15f35..04b96c4cd9 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.c
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -36,7 +36,9 @@
#include <string.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@@ -118,7 +120,7 @@ gpr_slice grpc_chttp2_settings_ack_create(void) {
return output;
}
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
uint32_t *settings) {
parser->target_settings = settings;
@@ -129,31 +131,29 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
if (flags == GRPC_CHTTP2_FLAG_ACK) {
parser->is_ack = 1;
if (length != 0) {
- gpr_log(GPR_ERROR, "non-empty settings ack frame received");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("non-empty settings ack frame received");
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
} else if (flags != 0) {
- gpr_log(GPR_ERROR, "invalid flags on settings frame");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("invalid flags on settings frame");
} else if (length % 6 != 0) {
- gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes");
} else {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
}
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+grpc_error *grpc_chttp2_settings_parser_parse(
grpc_exec_ctx *exec_ctx, void *p,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
grpc_chttp2_settings_parser *parser = p;
const uint8_t *cur = GPR_SLICE_START_PTR(slice);
const uint8_t *end = GPR_SLICE_END_PTR(slice);
+ char *msg;
if (parser->is_ack) {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
for (;;) {
@@ -168,7 +168,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
gpr_slice_buffer_add(&transport_parsing->qbuf,
grpc_chttp2_settings_ack_create());
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->id = (uint16_t)(((uint16_t)*cur) << 8);
cur++;
@@ -176,7 +176,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_ID1:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_ID1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->id = (uint16_t)(parser->id | (*cur));
cur++;
@@ -184,7 +184,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL0:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->value = ((uint32_t)*cur) << 24;
cur++;
@@ -192,7 +192,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL1:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->value |= ((uint32_t)*cur) << 16;
cur++;
@@ -200,7 +200,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL2:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->value |= ((uint32_t)*cur) << 8;
cur++;
@@ -208,7 +208,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL3:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
} else {
parser->state = GRPC_CHTTP2_SPS_ID0;
}
@@ -229,9 +229,11 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
transport_parsing->last_incoming_stream_id, sp->error_value,
gpr_slice_from_static_string("HTTP2 settings error"),
&transport_parsing->qbuf);
- gpr_log(GPR_ERROR, "invalid value %u passed for %s",
- parser->value, sp->name);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ gpr_asprintf(&msg, "invalid value %u passed for %s",
+ parser->value, sp->name);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
}
if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
@@ -249,7 +251,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
transport_parsing->is_client ? "CLI" : "SVR", parser->id,
parser->value);
}
- } else {
+ } else if (grpc_http_trace) {
gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
parser->id, parser->value);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index d9e30f1ed0..f654c598c8 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -92,10 +92,10 @@ gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
/* Create an ack settings frame */
gpr_slice grpc_chttp2_settings_ack_create(void);
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
uint32_t *settings);
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+grpc_error *grpc_chttp2_settings_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c
index 90243418bd..3cf848fd5c 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.c
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c
@@ -34,7 +34,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
gpr_slice grpc_chttp2_window_update_create(
uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) {
@@ -62,19 +64,22 @@ gpr_slice grpc_chttp2_window_update_create(
return slice;
}
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) {
if (flags || length != 4) {
- gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length,
- flags);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length,
+ flags);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
parser->byte = 0;
parser->amount = 0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -96,8 +101,11 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
if (p->byte == 4) {
uint32_t received_update = p->amount;
if (received_update == 0 || (received_update & 0x80000000u)) {
- gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
GPR_ASSERT(is_last);
@@ -115,5 +123,5 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
}
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.h b/src/core/ext/transport/chttp2/transport/frame_window_update.h
index d6e87b9329..1bcbbf9247 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -48,9 +48,9 @@ typedef struct {
gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta,
grpc_transport_one_way_stats *stats);
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index ed45bc9cb3..522455f7dc 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -46,6 +46,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
@@ -77,63 +78,70 @@ typedef enum {
a set of indirect jumps, and so not waste stack space. */
/* forward declarations for parsing states */
-static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-
-static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end);
-static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end);
-static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end);
-
-static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-
-static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end, grpc_error *error);
+static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+
+static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_value_string_with_indexed_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_value_string_with_literal_key(
+ 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,
+ const uint8_t *end);
+static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end);
+static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+
+static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
/* we translate the first byte of a hpack field into one of these decoding
cases, then use a lookup table to jump directly to the appropriate parser.
@@ -631,19 +639,18 @@ static const uint8_t inverse_base64[256] = {
};
/* emission helpers */
-static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
- int add_to_table) {
+static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
+ int add_to_table) {
if (add_to_table) {
- if (!grpc_chttp2_hptbl_add(&p->table, md)) {
- return 0;
- }
+ grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md);
+ if (err != GRPC_ERROR_NONE) return err;
}
if (p->on_header == NULL) {
GRPC_MDELEM_UNREF(md);
- return 0;
+ return GRPC_ERROR_CREATE("on_header callback not set");
}
p->on_header(p->on_header_user_data, md);
- return 1;
+ return GRPC_ERROR_NONE;
}
static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
@@ -654,70 +661,70 @@ static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
}
/* jump to the next state */
-static int parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
p->state = *p->next_state++;
return p->state(p, cur, end);
}
/* begin parsing a header: all functionality is encoded into lookup tables
above */
-static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_begin;
- return 1;
+ return GRPC_ERROR_NONE;
}
return first_byte_action[first_byte_lut[*cur]](p, cur, end);
}
/* stream dependency and prioritization data: we just skip it */
-static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_weight(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_weight;
- return 1;
+ return GRPC_ERROR_NONE;
}
return p->after_prioritization(p, cur + 1, end);
}
-static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep3(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep3;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_weight(p, cur + 1, end);
}
-static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep2(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep2;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_dep3(p, cur + 1, end);
}
-static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep1(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep1;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_dep2(p, cur + 1, end);
}
-static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep0(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep0;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_dep1(p, cur + 1, end);
@@ -725,30 +732,34 @@ static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* emit an indexed field; for now just logs it to console; jumps to
begin the next field on completion */
-static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_indexed_field(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 (md == NULL) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
- }
- return 0;
+ 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);
}
GRPC_MDELEM_REF(md);
- return on_hdr(p, md, 0) && parse_begin(p, cur, end);
+ grpc_error *err = on_hdr(p, md, 0);
+ if (err != GRPC_ERROR_NONE) return err;
+ return parse_begin(p, cur, end);
}
/* parse an indexed field with index < 127 */
-static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
p->dynamic_table_update_allowed = 0;
p->index = (*cur) & 0x7f;
return finish_indexed_field(p, cur + 1, end);
}
/* parse an indexed field with index >= 127 */
-static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_indexed_field};
p->dynamic_table_update_allowed = 0;
@@ -760,28 +771,34 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
/* finish a literal header with incremental indexing: just log, and jump to '
begin */
-static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_lithdr_incidx(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(md != NULL); /* handled in string parsing */
- return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 1) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 1);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* finish a literal header with incremental indexing with no index */
-static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
- return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
- take_string(p, &p->value)),
- 1) &&
- parse_begin(p, cur, end);
+static grpc_error *finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 1);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a literal header with incremental indexing; index < 63 */
-static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_incidx};
p->dynamic_table_update_allowed = 0;
@@ -791,8 +808,9 @@ static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a literal header with incremental indexing; index >= 63 */
-static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_incidx};
@@ -804,8 +822,9 @@ static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
}
/* parse a literal header with incremental indexing; index = 0 */
-static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_key_string, parse_string_prefix,
parse_value_string_with_literal_key, finish_lithdr_incidx_v};
@@ -815,28 +834,34 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
}
/* finish a literal header without incremental indexing */
-static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_lithdr_notidx(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(md != NULL); /* handled in string parsing */
- return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* finish a literal header without incremental indexing with index = 0 */
-static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
- return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+static grpc_error *finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a literal header without incremental indexing; index < 15 */
-static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_notidx};
p->dynamic_table_update_allowed = 0;
@@ -846,8 +871,9 @@ static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a literal header without incremental indexing; index >= 15 */
-static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_notidx};
@@ -859,8 +885,9 @@ static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
}
/* parse a literal header without incremental indexing; index == 0 */
-static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_key_string, parse_string_prefix,
parse_value_string_with_literal_key, finish_lithdr_notidx_v};
@@ -870,28 +897,34 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
}
/* finish a literal header that is never indexed */
-static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_lithdr_nvridx(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(md != NULL); /* handled in string parsing */
- return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* finish a literal header that is never indexed with an extra value */
-static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
- return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+static grpc_error *finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a literal header that is never indexed; index < 15 */
-static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_nvridx};
p->dynamic_table_update_allowed = 0;
@@ -901,8 +934,9 @@ static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a literal header that is never indexed; index >= 15 */
-static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_nvridx};
@@ -914,8 +948,9 @@ static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
}
/* parse a literal header that is never indexed; index == 0 */
-static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_key_string, parse_string_prefix,
parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
@@ -925,20 +960,25 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
}
/* finish parsing a max table size change */
-static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (grpc_http_trace) {
gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
}
- return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a max table size change, max size < 15 */
-static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (p->dynamic_table_update_allowed == 0) {
- return 0;
+ return parse_error(
+ p, cur, end,
+ GRPC_ERROR_CREATE(
+ "More than two max table size changes in a single frame"));
}
p->dynamic_table_update_allowed--;
p->index = (*cur) & 0x1f;
@@ -946,12 +986,16 @@ static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a max table size change, max size >= 15 */
-static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_max_tbl_size};
if (p->dynamic_table_update_allowed == 0) {
- return 0;
+ return parse_error(
+ p, cur, end,
+ GRPC_ERROR_CREATE(
+ "More than two max table size changes in a single frame"));
}
p->dynamic_table_update_allowed--;
p->next_state = and_then;
@@ -961,28 +1005,38 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* a parse error: jam the parse state into parse_error, and return error */
-static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
- p->state = parse_error;
- return 0;
+static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end, grpc_error *err) {
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
+ if (p->last_error == GRPC_ERROR_NONE) {
+ p->last_error = GRPC_ERROR_REF(err);
+ }
+ p->state = still_parse_error;
+ return err;
+}
+
+static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
+ return GRPC_ERROR_REF(p->last_error);
}
-static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
GPR_ASSERT(cur != end);
- if (grpc_http_trace) {
- gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
- }
- return parse_error(p, cur, end);
+ char *msg;
+ gpr_asprintf(&msg, "Illegal hpack op code %d", *cur);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
/* parse the 1st byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value0(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,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value0;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (*cur) & 0x7f;
@@ -996,11 +1050,11 @@ static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 2nd byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value1;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
@@ -1014,11 +1068,11 @@ static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 3rd byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value2;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
@@ -1032,11 +1086,11 @@ static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 4th byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value3;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
@@ -1050,15 +1104,16 @@ static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 5th byte of a varint into p->parsing.value
depending on the byte, we may overflow, and care must be taken */
-static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
uint8_t c;
uint32_t cur_value;
uint32_t add_value;
+ char *msg;
if (cur == end) {
p->state = parse_value4;
- return 1;
+ return GRPC_ERROR_NONE;
}
c = (*cur) & 0x7f;
@@ -1081,48 +1136,49 @@ static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
error:
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "integer overflow in hpack integer decoding: have 0x%08x, "
- "got byte 0x%02x on byte 5",
- *p->parsing.value, *cur);
- }
- return parse_error(p, cur, end);
+ gpr_asprintf(&msg,
+ "integer overflow in hpack integer decoding: have 0x%08x, "
+ "got byte 0x%02x on byte 5",
+ *p->parsing.value, *cur);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
/* 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
anything else will overflow */
-static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
while (cur != end && *cur == 0x80) {
++cur;
}
if (cur == end) {
p->state = parse_value5up;
- return 1;
+ return GRPC_ERROR_NONE;
}
if (*cur == 0) {
return parse_next(p, cur + 1, end);
}
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "integer overflow in hpack integer decoding: have 0x%08x, "
- "got byte 0x%02x sometime after byte 5",
- *p->parsing.value, *cur);
- }
- return parse_error(p, cur, end);
+ char *msg;
+ gpr_asprintf(&msg,
+ "integer overflow in hpack integer decoding: have 0x%08x, "
+ "got byte 0x%02x sometime after byte 5",
+ *p->parsing.value, *cur);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
/* parse a string prefix */
-static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_string_prefix;
- return 1;
+ return GRPC_ERROR_NONE;
}
p->strlen = (*cur) & 0x7f;
@@ -1149,25 +1205,26 @@ static void append_bytes(grpc_chttp2_hpack_parser_string *str,
str->length += (uint32_t)length;
}
-static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
grpc_chttp2_hpack_parser_string *str = p->parsing.str;
uint32_t bits;
uint8_t decoded[3];
switch ((binary_state)p->binary) {
case NOT_BINARY:
append_bytes(str, cur, (size_t)(end - cur));
- return 1;
+ return GRPC_ERROR_NONE;
b64_byte0:
case B64_BYTE0:
if (cur == end) {
p->binary = B64_BYTE0;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte0;
p->base64_buffer = bits << 18;
@@ -1176,12 +1233,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
case B64_BYTE1:
if (cur == end) {
p->binary = B64_BYTE1;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte1;
p->base64_buffer |= bits << 12;
@@ -1190,12 +1248,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
case B64_BYTE2:
if (cur == end) {
p->binary = B64_BYTE2;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte2;
p->base64_buffer |= bits << 6;
@@ -1204,12 +1263,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
case B64_BYTE3:
if (cur == end) {
p->binary = B64_BYTE3;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte3;
p->base64_buffer |= bits;
@@ -1220,11 +1280,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
append_bytes(str, decoded, 3);
goto b64_byte0;
}
- GPR_UNREACHABLE_CODE(return 1);
+ GPR_UNREACHABLE_CODE(return parse_error(
+ p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
}
/* append a null terminator to a string */
-static int finish_str(grpc_chttp2_hpack_parser *p) {
+static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
uint8_t terminator = 0;
uint8_t decoded[2];
uint32_t bits;
@@ -1235,14 +1297,18 @@ static int finish_str(grpc_chttp2_hpack_parser *p) {
case B64_BYTE0:
break;
case B64_BYTE1:
- gpr_log(GPR_ERROR, "illegal base64 encoding");
- return 0; /* illegal encoding */
+ return parse_error(
+ p, cur, end,
+ GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */
case B64_BYTE2:
bits = p->base64_buffer;
if (bits & 0xffff) {
- gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x",
- bits & 0xffff);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%04x",
+ bits & 0xffff);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
decoded[0] = (uint8_t)(bits >> 16);
append_bytes(str, decoded, 1);
@@ -1250,9 +1316,12 @@ static int finish_str(grpc_chttp2_hpack_parser *p) {
case B64_BYTE3:
bits = p->base64_buffer;
if (bits & 0xff) {
- gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x",
- bits & 0xff);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%02x",
+ bits & 0xff);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
decoded[0] = (uint8_t)(bits >> 16);
decoded[1] = (uint8_t)(bits >> 8);
@@ -1261,38 +1330,42 @@ static int finish_str(grpc_chttp2_hpack_parser *p) {
}
append_bytes(str, &terminator, 1);
p->parsing.str->length--; /* don't actually count the null terminator */
- return 1;
+ return GRPC_ERROR_NONE;
}
/* decode a nibble from a huffman encoded stream */
-static int huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
+static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t 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];
if (emit != -1) {
if (emit >= 0 && emit < 256) {
uint8_t c = (uint8_t)emit;
- if (!append_string(p, &c, (&c) + 1)) return 0;
+ grpc_error *err = append_string(p, &c, (&c) + 1);
+ if (err != GRPC_ERROR_NONE) return err;
} else {
assert(emit == 256);
}
}
p->huff_state = next;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* decode full bytes from a huffman encoded stream */
-static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *add_huff_bytes(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
for (; cur != end; ++cur) {
- if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0;
+ grpc_error *err = huff_nibble(p, *cur >> 4);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ err = huff_nibble(p, *cur & 0xf);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
}
- return 1;
+ return GRPC_ERROR_NONE;
}
/* decode some string bytes based on the current decoding mode
(huffman or not) */
-static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *add_str_bytes(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (p->huff) {
return add_huff_bytes(p, cur, end);
} else {
@@ -1301,26 +1374,31 @@ static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a string - tries to do large chunks at a time */
-static int parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
size_t remaining = p->strlen - p->strgot;
size_t given = (size_t)(end - cur);
if (remaining <= given) {
- return add_str_bytes(p, cur, cur + remaining) && finish_str(p) &&
- parse_next(p, cur + remaining, end);
+ grpc_error *err = add_str_bytes(p, cur, cur + remaining);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ err = finish_str(p, cur + remaining, end);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_next(p, cur + remaining, end);
} else {
- if (!add_str_bytes(p, cur, cur + given)) return 0;
+ grpc_error *err = add_str_bytes(p, cur, cur + given);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
GPR_ASSERT(given <= UINT32_MAX - p->strgot);
p->strgot += (uint32_t)given;
p->state = parse_string;
- return 1;
+ return GRPC_ERROR_NONE;
}
}
/* begin parsing a string - performs setup, calls parse_string */
-static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end, uint8_t binary,
- grpc_chttp2_hpack_parser_string *str) {
+static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end,
+ uint8_t binary,
+ grpc_chttp2_hpack_parser_string *str) {
p->strgot = 0;
str->length = 0;
p->parsing.str = str;
@@ -1330,58 +1408,50 @@ static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse the key string */
-static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
}
/* check if a key represents a binary header or not */
-typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header;
-static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
- return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER
- : PLAINTEXT_HEADER;
+static bool is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
+ return grpc_is_binary_header(p->key.str, p->key.length);
}
-static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) {
+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 (!elem) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
- }
- return ERROR_HEADER;
+ 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);
}
- return grpc_is_binary_header(
- (const char *)GPR_SLICE_START_PTR(elem->key->slice),
- GPR_SLICE_LENGTH(elem->key->slice))
- ? BINARY_HEADER
- : PLAINTEXT_HEADER;
+ *is =
+ grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
+ GPR_SLICE_LENGTH(elem->key->slice));
+ return GRPC_ERROR_NONE;
}
/* parse the value string */
-static int parse_value_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end, is_binary_header type) {
- switch (type) {
- case BINARY_HEADER:
- return begin_parse_string(p, cur, end, B64_BYTE0, &p->value);
- case PLAINTEXT_HEADER:
- return begin_parse_string(p, cur, end, NOT_BINARY, &p->value);
- case ERROR_HEADER:
- return 0;
- }
- /* Add code to prevent return without value error */
- GPR_UNREACHABLE_CODE(return 0);
+static grpc_error *parse_value_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end,
+ bool is_binary) {
+ return begin_parse_string(p, cur, end, is_binary ? B64_BYTE0 : NOT_BINARY,
+ &p->value);
}
-static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end) {
- return parse_value_string(p, cur, end, is_binary_indexed_header(p));
+static grpc_error *parse_value_string_with_indexed_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) {
+ bool is_binary = false;
+ grpc_error *err = is_binary_indexed_header(p, &is_binary);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_value_string(p, cur, end, is_binary);
}
-static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value_string_with_literal_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) {
return parse_value_string(p, cur, end, is_binary_literal_header(p));
}
@@ -1398,6 +1468,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
p->value.capacity = 0;
p->value.length = 0;
p->dynamic_table_update_allowed = 2;
+ p->last_error = GRPC_ERROR_NONE;
grpc_chttp2_hptbl_init(&p->table);
}
@@ -1408,12 +1479,14 @@ void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
grpc_chttp2_hptbl_destroy(&p->table);
+ GRPC_ERROR_UNREF(p->last_error);
gpr_free(p->key.str);
gpr_free(p->value.str);
}
-int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
- const uint8_t *beg, const uint8_t *end) {
+grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+ 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
@@ -1421,7 +1494,7 @@ int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
return p->state(p, beg, end);
}
-grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+grpc_error *grpc_chttp2_header_parser_parse(
grpc_exec_ctx *exec_ctx, void *hpack_parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -1430,17 +1503,17 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
if (stream_parsing != NULL) {
stream_parsing->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice);
}
- if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
- GPR_SLICE_END_PTR(slice))) {
+ grpc_error *error = grpc_chttp2_hpack_parser_parse(
+ parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice));
+ if (error != GRPC_ERROR_NONE) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return error;
}
if (is_last) {
if (parser->is_boundary && parser->state != parse_begin) {
- gpr_log(GPR_ERROR,
- "end of header frame not aligned with a hpack record boundary");
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE(
+ "end of header frame not aligned with a hpack record boundary");
}
/* need to check for null stream: this can occur if we receive an invalid
stream id on a header */
@@ -1448,8 +1521,7 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
if (parser->is_boundary) {
if (stream_parsing->header_frames_received ==
GPR_ARRAY_SIZE(stream_parsing->got_metadata_on_parse)) {
- gpr_log(GPR_ERROR, "too many trailer frames");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("Too many trailer frames");
}
stream_parsing
->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
@@ -1468,5 +1540,5 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
parser->dynamic_table_update_allowed = 2;
}
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 855d6c5d52..78eb38db5e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -44,9 +44,8 @@
typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
-typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p,
- const uint8_t *beg,
- const uint8_t *end);
+typedef grpc_error *(*grpc_chttp2_hpack_parser_state)(
+ grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end);
typedef struct {
char *str;
@@ -59,6 +58,8 @@ struct grpc_chttp2_hpack_parser {
void (*on_header)(void *user_data, grpc_mdelem *md);
void *on_header_user_data;
+ grpc_error *last_error;
+
/* current parse state - or a function that implements it */
grpc_chttp2_hpack_parser_state state;
/* future states dependent on the opening op code */
@@ -103,12 +104,13 @@ void grpc_chttp2_hpack_parser_destroy(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 */
-int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
- const uint8_t *beg, const uint8_t *end);
+grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+ const uint8_t *beg,
+ const uint8_t *end);
/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
the transport */
-grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+grpc_error *grpc_chttp2_header_parser_parse(
grpc_exec_ctx *exec_ctx, void *hpack_parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 295f31c44f..2b73ec969e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include "src/core/lib/support/murmur_hash.h"
@@ -262,18 +263,19 @@ void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
tbl->max_bytes = max_bytes;
}
-int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
- uint32_t bytes) {
+grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+ uint32_t bytes) {
if (tbl->current_table_bytes == bytes) {
- return 1;
+ return GRPC_ERROR_NONE;
}
if (bytes > tbl->max_bytes) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "Attempt to make hpack table %d bytes when max is %d bytes",
- bytes, tbl->max_bytes);
- }
- return 0;
+ char *msg;
+ gpr_asprintf(&msg,
+ "Attempt to make hpack table %d bytes when max is %d bytes",
+ bytes, tbl->max_bytes);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
@@ -291,23 +293,25 @@ int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
rebuild_ents(tbl, new_cap);
}
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
GPR_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "HPACK max table size reduced to %d but not reflected by hpack "
- "stream (still at %d)",
- tbl->max_bytes, tbl->current_table_bytes);
- }
- return 0;
+ char *msg;
+ gpr_asprintf(
+ &msg,
+ "HPACK max table size reduced to %d but not reflected by hpack "
+ "stream (still at %d)",
+ tbl->max_bytes, tbl->current_table_bytes);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
/* we can't add elements bigger than the max table size */
@@ -324,7 +328,7 @@ int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
while (tbl->num_ents) {
evict1(tbl);
}
- return 1;
+ return GRPC_ERROR_NONE;
}
/* evict entries to ensure no overflow */
@@ -339,7 +343,7 @@ int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* update accounting values */
tbl->num_ents++;
tbl->mem_used += (uint32_t)elem_bytes;
- return 1;
+ return GRPC_ERROR_NONE;
}
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 074fea36d8..45bd9255bf 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -36,6 +36,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/slice.h>
+#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/metadata.h"
/* HPACK header table */
@@ -87,15 +88,15 @@ void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
uint32_t max_bytes);
-int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
- uint32_t bytes);
+grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+ uint32_t bytes);
/* lookup a table entry based on its hpack index */
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
uint32_t index);
/* add a table entry to the index */
-int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
- grpc_mdelem *md) GRPC_MUST_USE_RESULT;
+grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
+ grpc_mdelem *md) GRPC_MUST_USE_RESULT;
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 7f3339a620..54e72ebd24 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -156,7 +156,7 @@ struct grpc_chttp2_incoming_byte_stream {
grpc_byte_stream base;
gpr_refcount refs;
struct grpc_chttp2_incoming_byte_stream *next_message;
- int failed;
+ grpc_error *error;
grpc_chttp2_transport *transport;
grpc_chttp2_stream *stream;
@@ -275,10 +275,10 @@ struct grpc_chttp2_transport_parsing {
/* active parser */
void *parser_data;
grpc_chttp2_stream_parsing *incoming_stream;
- grpc_chttp2_parse_error (*parser)(
- grpc_exec_ctx *exec_ctx, void *parser_user_data,
- grpc_chttp2_transport_parsing *transport_parsing,
- grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+ grpc_error *(*parser)(grpc_exec_ctx *exec_ctx, void *parser_user_data,
+ grpc_chttp2_transport_parsing *transport_parsing,
+ grpc_chttp2_stream_parsing *stream_parsing,
+ gpr_slice slice, int is_last);
/* received settings */
uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
@@ -471,12 +471,12 @@ typedef struct {
} grpc_chttp2_stream_writing;
struct grpc_chttp2_stream_parsing {
+ /** saw some stream level error */
+ grpc_error *forced_close_error;
/** HTTP2 stream id for this stream, or zero if one has not been assigned */
uint32_t id;
/** has this stream received a close */
uint8_t received_close;
- /** saw a rst_stream */
- uint8_t saw_rst_stream;
/** how many header frames have we received? */
uint8_t header_frames_received;
/** which metadata did we get (on this parse) */
@@ -488,8 +488,6 @@ struct grpc_chttp2_stream_parsing {
int64_t incoming_window;
/** parsing state for data frames */
grpc_chttp2_data_parser data_parser;
- /** reason give to rst_stream */
- uint32_t rst_stream_reason;
/** amount of window given */
int64_t outgoing_window;
/** number of bytes received - reset at end of parse thread execution */
@@ -532,7 +530,7 @@ void grpc_chttp2_perform_writes(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
grpc_endpoint *endpoint);
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
- void *transport_writing, bool success);
+ void *transport_writing, grpc_error *error);
void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global,
grpc_chttp2_transport_writing *writing);
@@ -541,9 +539,9 @@ void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing);
/** Process one slice of incoming data; return 1 if the connection is still
viable after reading, or 0 if the connection should be torn down */
-int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice);
+grpc_error *grpc_chttp2_perform_read(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice);
void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing);
@@ -673,9 +671,10 @@ void grpc_chttp2_for_all_streams(
void grpc_chttp2_parsing_become_skip_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global,
- grpc_closure **pclosure, int success);
+void grpc_chttp2_complete_closure_step(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
+ grpc_error *error);
void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *transport,
@@ -778,8 +777,8 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
grpc_status_code status, gpr_slice *details);
void grpc_chttp2_mark_stream_closed(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global, int close_reads,
- int close_writes);
+ grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
+ grpc_error *error);
void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global);
@@ -811,8 +810,8 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs,
gpr_slice slice);
void grpc_chttp2_incoming_byte_stream_finished(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
- int from_parsing_thread);
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+ grpc_error *error, int from_parsing_thread);
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *parsing,
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 3c74258352..785134091f 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -49,30 +49,30 @@
((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
parsing)))
-static int init_frame_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing);
-static int init_header_frame_parser(
+static grpc_error *init_frame_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static grpc_error *init_header_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_continuation);
-static int init_data_frame_parser(
+static grpc_error *init_data_frame_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static grpc_error *init_rst_stream_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static grpc_error *init_settings_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_rst_stream_parser(
+static grpc_error *init_window_update_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_settings_frame_parser(
+static grpc_error *init_ping_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_window_update_frame_parser(
+static grpc_error *init_goaway_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_ping_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing);
-static int init_goaway_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing);
-static int init_skip_frame_parser(
+static grpc_error *init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_header);
-static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice, int is_last);
+static grpc_error *parse_frame_slice(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice, int is_last);
void grpc_chttp2_prepare_to_read(
grpc_chttp2_transport_global *transport_global,
@@ -230,38 +230,42 @@ void grpc_chttp2_publish_reads(
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
- if (stream_parsing->saw_rst_stream) {
- if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) {
- grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
- (grpc_chttp2_error_code)stream_parsing->rst_stream_reason);
- char *status_details;
- gpr_slice slice_details;
- gpr_asprintf(&status_details, "Received RST_STREAM err=%d",
- stream_parsing->rst_stream_reason);
- slice_details = gpr_slice_from_copied_string(status_details);
- gpr_free(status_details);
+ if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) {
+ intptr_t reason;
+ bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error,
+ GRPC_ERROR_INT_HTTP2_ERROR, &reason);
+ if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) {
+ grpc_status_code status_code =
+ has_reason ? grpc_chttp2_http2_error_to_grpc_status(
+ (grpc_chttp2_error_code)reason)
+ : GRPC_STATUS_INTERNAL;
+ const char *status_details =
+ grpc_error_string(stream_parsing->forced_close_error);
+ gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
+ grpc_error_free_string(status_details);
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
status_code, &slice_details);
}
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- 1, 1);
+ 1, 1, stream_parsing->forced_close_error);
}
if (stream_parsing->received_close) {
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- 1, 0);
+ 1, 0, GRPC_ERROR_NONE);
}
}
}
-int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice) {
+grpc_error *grpc_chttp2_perform_read(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice) {
uint8_t *beg = GPR_SLICE_START_PTR(slice);
uint8_t *end = GPR_SLICE_END_PTR(slice);
uint8_t *cur = beg;
+ grpc_error *err;
- if (cur == end) return 1;
+ if (cur == end) return GRPC_ERROR_NONE;
switch (transport_parsing->deframe_state) {
case GRPC_DTS_CLIENT_PREFIX_0:
@@ -291,21 +295,25 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
->deframe_state]) {
- gpr_log(GPR_INFO,
- "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
- "at byte %d",
- GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
- ->deframe_state],
- (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
- [transport_parsing->deframe_state],
- *cur, (int)*cur, transport_parsing->deframe_state);
- return 0;
+ char *msg;
+ gpr_asprintf(
+ &msg,
+ "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
+ "at byte %d",
+ GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
+ ->deframe_state],
+ (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
+ [transport_parsing->deframe_state],
+ *cur, (int)*cur, transport_parsing->deframe_state);
+ err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
++cur;
++transport_parsing->deframe_state;
}
if (cur == end) {
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
dts_fh_0:
@@ -314,7 +322,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_1;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_1:
@@ -322,7 +330,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_2;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_2:
@@ -330,7 +338,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size |= *cur;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_3;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_3:
@@ -338,7 +346,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_type = *cur;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_4;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_4:
@@ -346,7 +354,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_flags = *cur;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_5;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_5:
@@ -354,7 +362,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_6;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_6:
@@ -362,7 +370,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_7;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_7:
@@ -370,15 +378,16 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_8;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_8:
GPR_ASSERT(cur < end);
transport_parsing->incoming_stream_id |= ((uint32_t)*cur);
transport_parsing->deframe_state = GRPC_DTS_FRAME;
- if (!init_frame_parser(exec_ctx, transport_parsing)) {
- return 0;
+ err = init_frame_parser(exec_ctx, transport_parsing);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
if (transport_parsing->incoming_stream_id != 0 &&
transport_parsing->incoming_stream_id >
@@ -387,62 +396,69 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id;
}
if (transport_parsing->incoming_frame_size == 0) {
- if (!parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
- 1)) {
- return 0;
+ err = parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
+ 1);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
transport_parsing->incoming_stream = NULL;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_0;
- return 1;
+ return GRPC_ERROR_NONE;
}
goto dts_fh_0; /* loop */
} else if (transport_parsing->incoming_frame_size >
transport_parsing->max_frame_size) {
- gpr_log(GPR_DEBUG, "Frame size %d is larger than max frame size %d",
- transport_parsing->incoming_frame_size,
- transport_parsing->max_frame_size);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d",
+ transport_parsing->incoming_frame_size,
+ transport_parsing->max_frame_size);
+ err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (++cur == end) {
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FRAME:
GPR_ASSERT(cur < end);
if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) {
- if (!parse_frame_slice(exec_ctx, transport_parsing,
- gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
- (size_t)(end - beg)),
- 1)) {
- return 0;
+ err = parse_frame_slice(exec_ctx, transport_parsing,
+ gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
+ (size_t)(end - beg)),
+ 1);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
transport_parsing->deframe_state = GRPC_DTS_FH_0;
transport_parsing->incoming_stream = NULL;
- return 1;
+ return GRPC_ERROR_NONE;
} else if ((uint32_t)(end - cur) >
transport_parsing->incoming_frame_size) {
size_t cur_offset = (size_t)(cur - beg);
- if (!parse_frame_slice(
- exec_ctx, transport_parsing,
- gpr_slice_sub_no_ref(
- slice, cur_offset,
- cur_offset + transport_parsing->incoming_frame_size),
- 1)) {
- return 0;
+ err = parse_frame_slice(
+ exec_ctx, transport_parsing,
+ gpr_slice_sub_no_ref(
+ slice, cur_offset,
+ cur_offset + transport_parsing->incoming_frame_size),
+ 1);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
cur += transport_parsing->incoming_frame_size;
transport_parsing->incoming_stream = NULL;
goto dts_fh_0; /* loop */
} else {
- if (!parse_frame_slice(exec_ctx, transport_parsing,
- gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
- (size_t)(end - beg)),
- 0)) {
- return 0;
+ err = parse_frame_slice(exec_ctx, transport_parsing,
+ gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
+ (size_t)(end - beg)),
+ 0);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
- return 1;
+ return GRPC_ERROR_NONE;
}
GPR_UNREACHABLE_CODE(return 0);
}
@@ -450,23 +466,30 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
GPR_UNREACHABLE_CODE(return 0);
}
-static int init_frame_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing) {
+static grpc_error *init_frame_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
if (transport_parsing->expect_continuation_stream_id != 0) {
if (transport_parsing->incoming_frame_type !=
GRPC_CHTTP2_FRAME_CONTINUATION) {
- gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x",
- transport_parsing->incoming_frame_type);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x",
+ transport_parsing->incoming_frame_type);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (transport_parsing->expect_continuation_stream_id !=
transport_parsing->incoming_stream_id) {
- gpr_log(GPR_ERROR,
- "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
- "grpc_chttp2_stream %08x",
- transport_parsing->expect_continuation_stream_id,
- transport_parsing->incoming_stream_id);
- return 0;
+ char *msg;
+ gpr_asprintf(
+ &msg,
+ "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
+ "grpc_chttp2_stream %08x",
+ transport_parsing->expect_continuation_stream_id,
+ transport_parsing->incoming_stream_id);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
return init_header_frame_parser(exec_ctx, transport_parsing, 1);
}
@@ -476,8 +499,7 @@ static int init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_HEADER:
return init_header_frame_parser(exec_ctx, transport_parsing, 0);
case GRPC_CHTTP2_FRAME_CONTINUATION:
- gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame");
- return 0;
+ return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame");
case GRPC_CHTTP2_FRAME_RST_STREAM:
return init_rst_stream_parser(exec_ctx, transport_parsing);
case GRPC_CHTTP2_FRAME_SETTINGS:
@@ -489,22 +511,24 @@ static int init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_GOAWAY:
return init_goaway_parser(exec_ctx, transport_parsing);
default:
- gpr_log(GPR_ERROR, "Unknown frame type %02x",
- transport_parsing->incoming_frame_type);
+ if (grpc_http_trace) {
+ gpr_log(GPR_ERROR, "Unknown frame type %02x",
+ transport_parsing->incoming_frame_type);
+ }
return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
}
}
-static grpc_chttp2_parse_error skip_parser(
- grpc_exec_ctx *exec_ctx, void *parser,
- grpc_chttp2_transport_parsing *transport_parsing,
- grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
- return GRPC_CHTTP2_PARSE_OK;
+static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
+ grpc_chttp2_transport_parsing *transport_parsing,
+ grpc_chttp2_stream_parsing *stream_parsing,
+ gpr_slice slice, int is_last) {
+ return GRPC_ERROR_NONE;
}
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
-static int init_skip_frame_parser(
+static grpc_error *init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_header) {
if (is_header) {
@@ -519,7 +543,7 @@ static int init_skip_frame_parser(
} else {
transport_parsing->parser = skip_parser;
}
- return 1;
+ return GRPC_ERROR_NONE;
}
void grpc_chttp2_parsing_become_skip_parser(
@@ -529,22 +553,28 @@ void grpc_chttp2_parsing_become_skip_parser(
transport_parsing->parser == grpc_chttp2_header_parser_parse);
}
-static grpc_chttp2_parse_error update_incoming_window(
+static grpc_error *update_incoming_window(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing) {
uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
if (incoming_frame_size > transport_parsing->incoming_window) {
- gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %" PRId64,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_window);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_window);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (incoming_frame_size > stream_parsing->incoming_window) {
- gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %" PRId64,
- transport_parsing->incoming_frame_size,
- stream_parsing->incoming_window);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
+ transport_parsing->incoming_frame_size,
+ stream_parsing->incoming_window);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window,
@@ -555,15 +585,15 @@ static grpc_chttp2_parse_error update_incoming_window(
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-static int init_data_frame_parser(
+static grpc_error *init_data_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
grpc_chttp2_stream_parsing *stream_parsing =
grpc_chttp2_parsing_lookup_stream(transport_parsing,
transport_parsing->incoming_stream_id);
- grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK;
+ grpc_error *err = GRPC_ERROR_NONE;
if (stream_parsing == NULL) {
return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
}
@@ -571,33 +601,32 @@ static int init_data_frame_parser(
if (stream_parsing->received_close) {
return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
}
- if (err == GRPC_CHTTP2_PARSE_OK) {
+ if (err == GRPC_ERROR_NONE) {
err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing);
}
- if (err == GRPC_CHTTP2_PARSE_OK) {
+ if (err == GRPC_ERROR_NONE) {
err = grpc_chttp2_data_parser_begin_frame(
- &stream_parsing->data_parser, transport_parsing->incoming_frame_flags);
- }
- switch (err) {
- case GRPC_CHTTP2_PARSE_OK:
- transport_parsing->incoming_stream = stream_parsing;
- transport_parsing->parser = grpc_chttp2_data_parser_parse;
- transport_parsing->parser_data = &stream_parsing->data_parser;
- return 1;
- case GRPC_CHTTP2_STREAM_ERROR:
- stream_parsing->received_close = 1;
- stream_parsing->saw_rst_stream = 1;
- stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
- gpr_slice_buffer_add(
- &transport_parsing->qbuf,
- grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
- GRPC_CHTTP2_PROTOCOL_ERROR,
- &stream_parsing->stats.outgoing));
- return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
- case GRPC_CHTTP2_CONNECTION_ERROR:
- return 0;
+ &stream_parsing->data_parser, transport_parsing->incoming_frame_flags,
+ stream_parsing->id);
+ }
+ if (err == GRPC_ERROR_NONE) {
+ transport_parsing->incoming_stream = stream_parsing;
+ transport_parsing->parser = grpc_chttp2_data_parser_parse;
+ transport_parsing->parser_data = &stream_parsing->data_parser;
+ return GRPC_ERROR_NONE;
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
+ /* handle stream errors by closing the stream */
+ stream_parsing->received_close = 1;
+ stream_parsing->forced_close_error = err;
+ gpr_slice_buffer_add(
+ &transport_parsing->qbuf,
+ grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
+ GRPC_CHTTP2_PROTOCOL_ERROR,
+ &stream_parsing->stats.outgoing));
+ return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+ } else {
+ return err;
}
- GPR_UNREACHABLE_CODE(return 0);
}
static void free_timeout(void *p) { gpr_free(p); }
@@ -713,7 +742,7 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
GPR_TIMER_END("on_trailing_header", 0);
}
-static int init_header_frame_parser(
+static grpc_error *init_header_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_continuation) {
uint8_t is_eoh = (transport_parsing->incoming_frame_flags &
@@ -808,15 +837,16 @@ static int init_header_frame_parser(
GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser);
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-static int init_window_update_frame_parser(
+static grpc_error *init_window_update_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame(
- &transport_parsing->simple.window_update,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+ grpc_error *err = grpc_chttp2_window_update_parser_begin_frame(
+ &transport_parsing->simple.window_update,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
if (transport_parsing->incoming_stream_id != 0) {
grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
@@ -828,26 +858,27 @@ static int init_window_update_frame_parser(
}
transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.window_update;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_ping_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame(
- &transport_parsing->simple.ping,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+static grpc_error *init_ping_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+ grpc_error *err = grpc_chttp2_ping_parser_begin_frame(
+ &transport_parsing->simple.ping, transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
transport_parsing->parser = grpc_chttp2_ping_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.ping;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_rst_stream_parser(
+static grpc_error *init_rst_stream_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame(
- &transport_parsing->simple.rst_stream,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+ grpc_error *err = grpc_chttp2_rst_stream_parser_begin_frame(
+ &transport_parsing->simple.rst_stream,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
transport_parsing, transport_parsing->incoming_stream_id);
@@ -857,37 +888,32 @@ static int init_rst_stream_parser(
stream_parsing->stats.incoming.framing_bytes += 9;
transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_goaway_parser(
+static grpc_error *init_goaway_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame(
- &transport_parsing->goaway_parser,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+ grpc_error *err = grpc_chttp2_goaway_parser_begin_frame(
+ &transport_parsing->goaway_parser, transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
transport_parsing->parser = grpc_chttp2_goaway_parser_parse;
transport_parsing->parser_data = &transport_parsing->goaway_parser;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_settings_frame_parser(
+static grpc_error *init_settings_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok;
-
if (transport_parsing->incoming_stream_id != 0) {
- gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d",
- transport_parsing->incoming_stream_id);
- return 0;
+ return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream");
}
- ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame(
- &transport_parsing->simple.settings,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags,
- transport_parsing->settings);
- if (!ok) {
- return 0;
+ grpc_error *err = grpc_chttp2_settings_parser_begin_frame(
+ &transport_parsing->simple.settings,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags, transport_parsing->settings);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
transport_parsing->settings_ack_received = 1;
@@ -901,7 +927,7 @@ static int init_settings_frame_parser(
}
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.settings;
- return ok;
+ return GRPC_ERROR_NONE;
}
/*
@@ -910,34 +936,37 @@ static int is_window_update_legal(int64_t window_update, int64_t window) {
}
*/
-static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice, int is_last) {
+static grpc_error *parse_frame_slice(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice, int is_last) {
grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream;
- switch (transport_parsing->parser(exec_ctx, transport_parsing->parser_data,
- transport_parsing, stream_parsing, slice,
- is_last)) {
- case GRPC_CHTTP2_PARSE_OK:
- if (stream_parsing) {
- grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
- stream_parsing);
- }
- return 1;
- case GRPC_CHTTP2_STREAM_ERROR:
- grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing);
- if (stream_parsing) {
- stream_parsing->saw_rst_stream = 1;
- stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
- gpr_slice_buffer_add(
- &transport_parsing->qbuf,
- grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
- GRPC_CHTTP2_PROTOCOL_ERROR,
- &stream_parsing->stats.outgoing));
- }
- return 1;
- case GRPC_CHTTP2_CONNECTION_ERROR:
- return 0;
+ grpc_error *err = transport_parsing->parser(
+ exec_ctx, transport_parsing->parser_data, transport_parsing,
+ stream_parsing, slice, is_last);
+ if (err == GRPC_ERROR_NONE) {
+ if (stream_parsing) {
+ grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+ stream_parsing);
+ }
+ return GRPC_ERROR_NONE;
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
+ if (grpc_http_trace) {
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "%s", msg);
+ grpc_error_free_string(msg);
+ }
+ grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing);
+ if (stream_parsing) {
+ stream_parsing->forced_close_error = err;
+ gpr_slice_buffer_add(
+ &transport_parsing->qbuf,
+ grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
+ GRPC_CHTTP2_PROTOCOL_ERROR,
+ &stream_parsing->stats.outgoing));
+ } else {
+ GRPC_ERROR_UNREF(err);
+ }
}
- GPR_UNREACHABLE_CODE(return 0);
+ return err;
}
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index a8fb463939..add7678182 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -187,7 +187,8 @@ void grpc_chttp2_perform_writes(
grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
&transport_writing->done_cb);
} else {
- grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &transport_writing->done_cb, GRPC_ERROR_NONE,
+ NULL);
}
}
@@ -334,25 +335,27 @@ void grpc_chttp2_cleanup_writing(
transport_global, transport_writing, &stream_global, &stream_writing)) {
if (stream_writing->sent_initial_metadata) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_initial_metadata_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_initial_metadata_finished, GRPC_ERROR_NONE);
}
grpc_transport_move_one_way_stats(&stream_writing->stats,
&stream_global->stats.outgoing);
if (stream_writing->sent_message) {
GPR_ASSERT(stream_writing->send_message == NULL);
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_message_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_message_finished, GRPC_ERROR_NONE);
stream_writing->sent_message = 0;
}
if (stream_writing->sent_trailing_metadata) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_trailing_metadata_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_trailing_metadata_finished, GRPC_ERROR_NONE);
}
if (stream_writing->sent_trailing_metadata) {
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- !transport_global->is_client, 1);
+ !transport_global->is_client, 1,
+ GRPC_ERROR_NONE);
}
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 1bb53b756c..25d8aca250 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -159,11 +159,11 @@ static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
static void enqueue_callbacks(grpc_closure *callback_list[]) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
if (callback_list[0]) {
- grpc_exec_ctx_enqueue(&exec_ctx, callback_list[0], true, NULL);
+ grpc_exec_ctx_sched(&exec_ctx, callback_list[0], GRPC_ERROR_NONE, NULL);
callback_list[0] = NULL;
}
if (callback_list[1]) {
- grpc_exec_ctx_enqueue(&exec_ctx, callback_list[1], true, NULL);
+ grpc_exec_ctx_sched(&exec_ctx, callback_list[1], GRPC_ERROR_NONE, NULL);
callback_list[1] = NULL;
}
grpc_exec_ctx_finish(&exec_ctx);