From 3ba16e4f0562e32cfffb786c1d74e8e49bb5e6de Mon Sep 17 00:00:00 2001 From: Craig Tiller <ctiller@google.com> Date: Thu, 8 Dec 2016 16:46:18 -0800 Subject: [PATCH] Fix bug whereby errors on a call do not lead to cancellation --- src/core/lib/channel/http_client_filter.c | 13 +++-- src/core/lib/slice/slice.c | 2 + src/core/lib/surface/call.c | 59 ++++++++++++++--------- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c index 31e9bde9d3..33834adc1d 100644 --- a/src/core/lib/channel/http_client_filter.c +++ b/src/core/lib/channel/http_client_filter.c @@ -103,11 +103,18 @@ static grpc_error *client_filter_incoming_metadata(grpc_exec_ctx *exec_ctx, } else { char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.status->md), GPR_DUMP_ASCII); + char *msg; + gpr_asprintf(&msg, "Received http2 header with status: %s", val); grpc_error *e = grpc_error_set_str( - GRPC_ERROR_CREATE( - "Received http2 :status header with non-200 OK status"), - GRPC_ERROR_STR_VALUE, val); + grpc_error_set_int( + grpc_error_set_str( + GRPC_ERROR_CREATE( + "Received http2 :status header with non-200 OK status"), + GRPC_ERROR_STR_VALUE, val), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED), + GRPC_ERROR_STR_GRPC_MESSAGE, msg); gpr_free(val); + gpr_free(msg); return e; } } diff --git a/src/core/lib/slice/slice.c b/src/core/lib/slice/slice.c index f0ad9f4881..e77be6fc14 100644 --- a/src/core/lib/slice/slice.c +++ b/src/core/lib/slice/slice.c @@ -436,6 +436,8 @@ int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) { if (haystack_len == 0 || needle_len == 0) return -1; if (haystack_len < needle_len) return -1; + if (haystack_len == needle_len) + return grpc_slice_eq(haystack, needle) ? 0 : -1; if (needle_len == 1) return grpc_slice_chr(haystack, (char)*needle_bytes); const uint8_t *last = haystack_bytes + haystack_len - needle_len; diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index acfa03384a..439d17b3db 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -219,6 +219,8 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, grpc_status_code status, const char *description); +static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c, + grpc_error *error); static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, grpc_status_code status, const char *description); @@ -698,11 +700,13 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c, return r; } +typedef enum { TC_CANCEL, TC_CLOSE } termination_closure_type; + typedef struct termination_closure { grpc_closure closure; grpc_call *call; grpc_error *error; - enum { TC_CANCEL, TC_CLOSE } type; + termination_closure_type type; grpc_transport_stream_op op; } termination_closure; @@ -757,36 +761,43 @@ static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx, return GRPC_CALL_OK; } -static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, - grpc_status_code status, - const char *description) { - GPR_ASSERT(status != GRPC_STATUS_OK); +static grpc_call_error terminate_with_error(grpc_exec_ctx *exec_ctx, + grpc_call *c, + termination_closure_type tc_type, + grpc_error *error) { termination_closure *tc = gpr_malloc(sizeof(*tc)); - memset(tc, 0, sizeof(termination_closure)); - tc->type = TC_CANCEL; + memset(tc, 0, sizeof(*tc)); + tc->type = tc_type; tc->call = c; - tc->error = grpc_error_set_int( + tc->error = error; + return terminate_with_status(exec_ctx, tc); +} + +static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c, + grpc_error *error) { + terminate_with_error(exec_ctx, c, TC_CANCEL, error); +} + +static grpc_error *error_from_status(grpc_status_code status, + const char *description) { + return grpc_error_set_int( grpc_error_set_str(GRPC_ERROR_CREATE(description), GRPC_ERROR_STR_GRPC_MESSAGE, description), GRPC_ERROR_INT_GRPC_STATUS, status); +} - return terminate_with_status(exec_ctx, tc); +static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, + grpc_status_code status, + const char *description) { + return terminate_with_error(exec_ctx, c, TC_CANCEL, + error_from_status(status, description)); } static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, grpc_status_code status, const char *description) { - GPR_ASSERT(status != GRPC_STATUS_OK); - termination_closure *tc = gpr_malloc(sizeof(*tc)); - memset(tc, 0, sizeof(termination_closure)); - tc->type = TC_CLOSE; - tc->call = c; - tc->error = grpc_error_set_int( - grpc_error_set_str(GRPC_ERROR_CREATE(description), - GRPC_ERROR_STR_GRPC_MESSAGE, description), - GRPC_ERROR_INT_GRPC_STATUS, status); - - return terminate_with_status(exec_ctx, tc); + return terminate_with_error(exec_ctx, c, TC_CLOSE, + error_from_status(status, description)); } static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, @@ -1155,8 +1166,10 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx, } } -static void add_batch_error(batch_control *bctl, grpc_error *error) { +static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl, + grpc_error *error) { if (error == GRPC_ERROR_NONE) return; + cancel_with_error(exec_ctx, bctl->call, GRPC_ERROR_REF(error)); if (bctl->error == GRPC_ERROR_NONE) { bctl->error = GRPC_ERROR_CREATE("Call batch operation failed"); } @@ -1170,7 +1183,7 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&call->mu); - add_batch_error(bctl, GRPC_ERROR_REF(error)); + add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error)); if (error == GRPC_ERROR_NONE) { grpc_metadata_batch *md = &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; @@ -1270,7 +1283,7 @@ static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } - add_batch_error(bctl, GRPC_ERROR_REF(error)); + add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error)); gpr_mu_unlock(&call->mu); if (gpr_unref(&bctl->steps_to_complete)) { post_batch_completion(exec_ctx, bctl); -- GitLab