diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/ext/transport/chttp2/transport/chttp2_transport.c | 184 | ||||
-rw-r--r-- | src/core/ext/transport/chttp2/transport/frame_settings.c | 2 | ||||
-rw-r--r-- | src/core/ext/transport/chttp2/transport/hpack_parser.c | 2 | ||||
-rw-r--r-- | src/core/lib/iomgr/error.c | 116 | ||||
-rw-r--r-- | src/core/lib/iomgr/error.h | 6 | ||||
-rw-r--r-- | src/core/lib/iomgr/error_internal.h | 53 | ||||
-rw-r--r-- | src/core/lib/security/transport/server_auth_filter.c | 2 | ||||
-rw-r--r-- | src/core/lib/surface/call.c | 1 | ||||
-rw-r--r-- | src/core/lib/transport/error_utils.c | 90 | ||||
-rw-r--r-- | src/core/lib/transport/error_utils.h | 50 | ||||
-rw-r--r-- | src/core/lib/transport/http2_errors.h (renamed from src/core/ext/transport/chttp2/transport/http2_errors.h) | 0 | ||||
-rw-r--r-- | src/core/lib/transport/status_conversion.c (renamed from src/core/ext/transport/chttp2/transport/status_conversion.c) | 2 | ||||
-rw-r--r-- | src/core/lib/transport/status_conversion.h (renamed from src/core/ext/transport/chttp2/transport/status_conversion.h) | 2 |
13 files changed, 318 insertions, 192 deletions
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 858cb41ec8..3711e0cba1 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -44,9 +44,7 @@ #include <grpc/support/string_util.h> #include <grpc/support/useful.h> -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/ext/transport/chttp2/transport/internal.h" -#include "src/core/ext/transport/chttp2/transport/status_conversion.h" #include "src/core/ext/transport/chttp2/transport/varint.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/http/parser.h" @@ -55,7 +53,10 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/http2_errors.h" #include "src/core/lib/transport/static_metadata.h" +#include "src/core/lib/transport/status_conversion.h" #include "src/core/lib/transport/timeout_encoding.h" #include "src/core/lib/transport/transport_impl.h" @@ -1458,7 +1459,7 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *due_to_error) { if (!t->is_client && !s->sent_trailing_metadata && - grpc_error_get_int(due_to_error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { + grpc_error_has_clear_grpc_status(due_to_error)) { close_from_api(exec_ctx, t, s, due_to_error); return; } @@ -1634,112 +1635,97 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, uint8_t *p; uint32_t len = 0; grpc_status_code grpc_status; - grpc_chttp2_error_code http_error; - status_codes_from_error(error, s->deadline, &http_error, &grpc_status); + const char *msg; + grpc_error_get_status(error, &grpc_status, &msg); GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100); - if (s->id != 0 && !t->is_client) { - /* Hand roll a header block. - This is unnecessarily ugly - at some point we should find a more - elegant - solution. - It's complicated by the fact that our send machinery would be dead by - the - time we got around to sending this, so instead we ignore HPACK - compression - and just write the uncompressed bytes onto the wire. */ - status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10)); - p = GRPC_SLICE_START_PTR(status_hdr); - *p++ = 0x40; /* literal header */ - *p++ = 11; /* len(grpc-status) */ + /* Hand roll a header block. + This is unnecessarily ugly - at some point we should find a more + elegant solution. + It's complicated by the fact that our send machinery would be dead by + the time we got around to sending this, so instead we ignore HPACK + compression and just write the uncompressed bytes onto the wire. */ + status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10)); + p = GRPC_SLICE_START_PTR(status_hdr); + *p++ = 0x40; /* literal header */ + *p++ = 11; /* len(grpc-status) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 's'; + *p++ = 't'; + *p++ = 'a'; + *p++ = 't'; + *p++ = 'u'; + *p++ = 's'; + if (grpc_status < 10) { + *p++ = 1; + *p++ = (uint8_t)('0' + grpc_status); + } else { + *p++ = 2; + *p++ = (uint8_t)('0' + (grpc_status / 10)); + *p++ = (uint8_t)('0' + (grpc_status % 10)); + } + GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr)); + len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr); + + if (msg != NULL) { + size_t msg_len = strlen(msg); + GPR_ASSERT(msg_len <= UINT32_MAX); + uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0); + message_pfx = grpc_slice_malloc(14 + msg_len_len); + p = GRPC_SLICE_START_PTR(message_pfx); + *p++ = 0x40; + *p++ = 12; /* len(grpc-message) */ *p++ = 'g'; *p++ = 'r'; *p++ = 'p'; *p++ = 'c'; *p++ = '-'; + *p++ = 'm'; + *p++ = 'e'; *p++ = 's'; - *p++ = 't'; - *p++ = 'a'; - *p++ = 't'; - *p++ = 'u'; *p++ = 's'; - if (grpc_status < 10) { - *p++ = 1; - *p++ = (uint8_t)('0' + grpc_status); - } else { - *p++ = 2; - *p++ = (uint8_t)('0' + (grpc_status / 10)); - *p++ = (uint8_t)('0' + (grpc_status % 10)); - } - GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr)); - len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr); - - const char *optional_message = - grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE); - - if (optional_message != NULL) { - size_t msg_len = strlen(optional_message); - GPR_ASSERT(msg_len <= UINT32_MAX); - uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0); - message_pfx = grpc_slice_malloc(14 + msg_len_len); - p = GRPC_SLICE_START_PTR(message_pfx); - *p++ = 0x40; - *p++ = 12; /* len(grpc-message) */ - *p++ = 'g'; - *p++ = 'r'; - *p++ = 'p'; - *p++ = 'c'; - *p++ = '-'; - *p++ = 'm'; - *p++ = 'e'; - *p++ = 's'; - *p++ = 's'; - *p++ = 'a'; - *p++ = 'g'; - *p++ = 'e'; - GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, - (uint32_t)msg_len_len); - p += msg_len_len; - GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx)); - len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); - len += (uint32_t)msg_len; - } - - hdr = grpc_slice_malloc(9); - p = GRPC_SLICE_START_PTR(hdr); - *p++ = (uint8_t)(len >> 16); - *p++ = (uint8_t)(len >> 8); - *p++ = (uint8_t)(len); - *p++ = GRPC_CHTTP2_FRAME_HEADER; - *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; - *p++ = (uint8_t)(s->id >> 24); - *p++ = (uint8_t)(s->id >> 16); - *p++ = (uint8_t)(s->id >> 8); - *p++ = (uint8_t)(s->id); - GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr)); - - grpc_slice_buffer_add(&t->qbuf, hdr); - grpc_slice_buffer_add(&t->qbuf, status_hdr); - if (optional_message) { - grpc_slice_buffer_add(&t->qbuf, message_pfx); - grpc_slice_buffer_add(&t->qbuf, - grpc_slice_from_copied_string(optional_message)); - } - grpc_slice_buffer_add( - &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, - &s->stats.outgoing)); - } - - const char *msg = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE); - bool free_msg = false; - if (msg == NULL) { - free_msg = true; - msg = grpc_error_string(error); - } - grpc_slice msg_slice = grpc_slice_from_copied_string(msg); - grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice); - if (free_msg) grpc_error_free_string(msg); + *p++ = 'a'; + *p++ = 'g'; + *p++ = 'e'; + GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, (uint32_t)msg_len_len); + p += msg_len_len; + GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx)); + len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); + len += (uint32_t)msg_len; + } + + hdr = grpc_slice_malloc(9); + p = GRPC_SLICE_START_PTR(hdr); + *p++ = (uint8_t)(len >> 16); + *p++ = (uint8_t)(len >> 8); + *p++ = (uint8_t)(len); + *p++ = GRPC_CHTTP2_FRAME_HEADER; + *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; + *p++ = (uint8_t)(s->id >> 24); + *p++ = (uint8_t)(s->id >> 16); + *p++ = (uint8_t)(s->id >> 8); + *p++ = (uint8_t)(s->id); + GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr)); + + grpc_slice_buffer_add(&t->qbuf, hdr); + grpc_slice_buffer_add(&t->qbuf, status_hdr); + if (msg != NULL) { + grpc_slice_buffer_add(&t->qbuf, message_pfx); + grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg)); + } + grpc_slice_buffer_add( + &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, + &s->stats.outgoing)); + + grpc_slice msg_slice = + msg == NULL ? grpc_empty_slice() : grpc_slice_from_copied_string(msg); + grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, + msg == NULL ? NULL : &msg_slice); grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error); grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api"); diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c index 98facae87f..bfed41fadb 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.c +++ b/src/core/ext/transport/chttp2/transport/frame_settings.c @@ -43,8 +43,8 @@ #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/frame.h" -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/debug/trace.h" +#include "src/core/lib/transport/http2_errors.h" #define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024) diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c index 2a14167f67..6d6d0de742 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_parser.c +++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c @@ -50,10 +50,10 @@ #include <grpc/support/useful.h> #include "src/core/ext/transport/chttp2/transport/bin_encoder.h" -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" +#include "src/core/lib/transport/http2_errors.h" /* TODO(ctiller): remove before submission */ #include "src/core/lib/slice/slice_string_helpers.h" diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c index 227c94020f..3cf644f421 100644 --- a/src/core/lib/iomgr/error.c +++ b/src/core/lib/iomgr/error.c @@ -33,13 +33,10 @@ #include "src/core/lib/iomgr/error.h" -#include <inttypes.h> -#include <stdbool.h> #include <string.h> #include <grpc/status.h> #include <grpc/support/alloc.h> -#include <grpc/support/avl.h> #include <grpc/support/log.h> #include <grpc/support/string_util.h> #include <grpc/support/useful.h> @@ -48,6 +45,7 @@ #include <grpc/support/log_windows.h> #endif +#include "src/core/lib/iomgr/error_internal.h" #include "src/core/lib/profiling/timers.h" static void destroy_integer(void *key) {} @@ -164,16 +162,7 @@ static const char *error_time_name(grpc_error_times key) { GPR_UNREACHABLE_CODE(return "unknown"); } -struct grpc_error { - gpr_refcount refs; - gpr_avl ints; - gpr_avl strs; - gpr_avl times; - gpr_avl errs; - uintptr_t next_err; -}; - -static bool is_special(grpc_error *err) { +bool grpc_error_is_special(grpc_error *err) { return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM || err == GRPC_ERROR_CANCELLED; } @@ -189,14 +178,14 @@ grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line, } #else grpc_error *grpc_error_ref(grpc_error *err) { - if (is_special(err)) return err; + if (grpc_error_is_special(err)) return err; gpr_ref(&err->refs); return err; } #endif static void error_destroy(grpc_error *err) { - GPR_ASSERT(!is_special(err)); + GPR_ASSERT(!grpc_error_is_special(err)); gpr_avl_unref(err->ints); gpr_avl_unref(err->strs); gpr_avl_unref(err->errs); @@ -216,7 +205,7 @@ void grpc_error_unref(grpc_error *err, const char *file, int line, } #else void grpc_error_unref(grpc_error *err) { - if (is_special(err)) return; + if (grpc_error_is_special(err)) return; if (gpr_unref(&err->refs)) { error_destroy(err); } @@ -259,7 +248,7 @@ grpc_error *grpc_error_create(const char *file, int line, const char *desc, static grpc_error *copy_error_and_unref(grpc_error *in) { GPR_TIMER_BEGIN("copy_error_and_unref", 0); grpc_error *out; - if (is_special(in)) { + if (grpc_error_is_special(in)) { if (in == GRPC_ERROR_NONE) out = grpc_error_set_int(GRPC_ERROR_CREATE("no error"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK); @@ -297,14 +286,29 @@ grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which, return new; } +typedef struct { + grpc_error *error; + grpc_status_code code; + const char *msg; +} special_error_status_map; +static special_error_status_map error_status_map[] = { + {GRPC_ERROR_NONE, GRPC_STATUS_OK, NULL}, + {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"}, + {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, +}; + bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) { GPR_TIMER_BEGIN("grpc_error_get_int", 0); void *pp; - if (is_special(err)) { - if (err == GRPC_ERROR_CANCELLED && which == GRPC_ERROR_INT_GRPC_STATUS) { - *p = GRPC_STATUS_CANCELLED; - GPR_TIMER_END("grpc_error_get_int", 0); - return true; + if (grpc_error_is_special(err)) { + if (which == GRPC_ERROR_INT_GRPC_STATUS) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { + if (error_status_map[i].error == err) { + if (p != NULL) *p = error_status_map[i].code; + GPR_TIMER_END("grpc_error_get_int", 0); + return true; + } + } } GPR_TIMER_END("grpc_error_get_int", 0); return false; @@ -329,67 +333,17 @@ grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which, } const char *grpc_error_get_str(grpc_error *err, grpc_error_strs which) { - if (is_special(err)) return NULL; - return gpr_avl_get(err->strs, (void *)(uintptr_t)which); -} - -typedef struct { - grpc_error *error; - grpc_status_code code; - const char *msg; -} special_error_status_map; -static special_error_status_map error_status_map[] = { - {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""}, - {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "RPC cancelled"}, - {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, -}; - -static grpc_error *recursively_find_error_with_status(grpc_error *error, - intptr_t *status) { - // If the error itself has a status code, return it. - if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, status)) { - return error; - } - if (is_special(error)) return NULL; - // Otherwise, search through its children. - intptr_t key = 0; - while (true) { - grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++); - if (child_error == NULL) break; - grpc_error *result = - recursively_find_error_with_status(child_error, status); - if (result != NULL) return result; - } - return NULL; -} - -void grpc_error_get_status(grpc_error *error, grpc_status_code *code, - const char **msg) { - // Handle special errors via the static map. - for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); ++i) { - if (error == error_status_map[i].error) { - *code = error_status_map[i].code; - *msg = error_status_map[i].msg; - return; + if (grpc_error_is_special(err)) { + if (which == GRPC_ERROR_STR_GRPC_MESSAGE) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { + if (error_status_map[i].error == err) { + return error_status_map[i].msg; + } + } } + return NULL; } - // Populate code. - // Start with the parent error and recurse through the tree of children - // until we find the first one that has a status code. - intptr_t status = GRPC_STATUS_UNKNOWN; // Default in case we don't find one. - grpc_error *found_error = recursively_find_error_with_status(error, &status); - *code = (grpc_status_code)status; - // Now populate msg. - // If we found an error with a status code above, use that; otherwise, - // fall back to using the parent error. - if (found_error == NULL) found_error = error; - // If the error has a status message, use it. Otherwise, fall back to - // the error description. - *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE); - if (*msg == NULL && status != GRPC_STATUS_OK) { - *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION); - if (*msg == NULL) *msg = "unknown error"; // Just in case. - } + return gpr_avl_get(err->strs, (void *)(uintptr_t)which); } grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) { diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h index a2ba84deed..75ca9c4bf9 100644 --- a/src/core/lib/iomgr/error.h +++ b/src/core/lib/iomgr/error.h @@ -193,12 +193,6 @@ grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which, /// Caller does NOT own return value. const char *grpc_error_get_str(grpc_error *error, grpc_error_strs which); -/// A utility function to get the status code and message to be returned -/// to the application. If not set in the top-level message, looks -/// through child errors until it finds the first one with these attributes. -void grpc_error_get_status(grpc_error *error, grpc_status_code *code, - const char **msg); - /// Add a child error: an error that is believed to have contributed to this /// error occurring. Allows root causing high level errors from lower level /// errors that contributed to them. diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h new file mode 100644 index 0000000000..5afe9edc7f --- /dev/null +++ b/src/core/lib/iomgr/error_internal.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_ERROR_INTERNAL_H +#define GRPC_ERROR_INTERNAL_H + +#include <inttypes.h> +#include <stdbool.h> + +#include <grpc/support/avl.h> + +struct grpc_error { + gpr_refcount refs; + gpr_avl ints; + gpr_avl strs; + gpr_avl times; + gpr_avl errs; + uintptr_t next_err; +}; + +bool grpc_error_is_special(grpc_error *err); + +#endif diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c index 6b04ad2385..36e81d6501 100644 --- a/src/core/lib/security/transport/server_auth_filter.c +++ b/src/core/lib/security/transport/server_auth_filter.c @@ -130,7 +130,6 @@ static void on_md_processing_done( grpc_metadata_array_destroy(&calld->md); grpc_closure_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE); } else { - grpc_slice message; for (size_t i = 0; i < calld->md.count; i++) { grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].key); grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].value); @@ -139,7 +138,6 @@ static void on_md_processing_done( error_details = error_details != NULL ? error_details : "Authentication metadata processing failed."; - message = grpc_slice_from_copied_string(error_details); calld->transport_op->send_initial_metadata = NULL; if (calld->transport_op->send_message != NULL) { grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message); diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index 57603ca386..4abf981997 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -56,6 +56,7 @@ #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/transport.h" diff --git a/src/core/lib/transport/error_utils.c b/src/core/lib/transport/error_utils.c new file mode 100644 index 0000000000..6403cf80d8 --- /dev/null +++ b/src/core/lib/transport/error_utils.c @@ -0,0 +1,90 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/iomgr/error_internal.h" + +static grpc_error *recursively_find_error_with_status(grpc_error *error, + intptr_t *status) { + // If the error itself has a status code, return it. + if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, status)) { + return error; + } + if (grpc_error_is_special(error)) return NULL; + // Otherwise, search through its children. + intptr_t key = 0; + while (true) { + grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++); + if (child_error == NULL) break; + grpc_error *result = + recursively_find_error_with_status(child_error, status); + if (result != NULL) return result; + } + return NULL; +} + +void grpc_error_get_status(grpc_error *error, grpc_status_code *code, + const char **msg) { + // Populate code. + // Start with the parent error and recurse through the tree of children + // until we find the first one that has a status code. + intptr_t status = GRPC_STATUS_UNKNOWN; // Default in case we don't find one. + grpc_error *found_error = recursively_find_error_with_status(error, &status); + *code = (grpc_status_code)status; + // Now populate msg. + // If we found an error with a status code above, use that; otherwise, + // fall back to using the parent error. + if (found_error == NULL) found_error = error; + // If the error has a status message, use it. Otherwise, fall back to + // the error description. + *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE); + if (*msg == NULL && status != GRPC_STATUS_OK) { + *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION); + if (*msg == NULL) *msg = "unknown error"; // Just in case. + } +} + +bool grpc_error_has_clear_grpc_status(grpc_error *error) { + if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { + return true; + } + intptr_t key = 0; + while (true) { + grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++); + if (child_error == NULL) break; + if (grpc_error_has_clear_grpc_status(child_error)) { + return true; + } + } + return false; +} diff --git a/src/core/lib/transport/error_utils.h b/src/core/lib/transport/error_utils.h new file mode 100644 index 0000000000..541dba852f --- /dev/null +++ b/src/core/lib/transport/error_utils.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_ERROR_UTILS_H +#define GRPC_ERROR_UTILS_H + +#include "src/core/lib/iomgr/error.h" + +/// A utility function to get the status code and message to be returned +/// to the application. If not set in the top-level message, looks +/// through child errors until it finds the first one with these attributes. +void grpc_error_get_status(grpc_error *error, grpc_status_code *code, + const char **msg); +/// A utility function to check whether there is a clear status code that +/// doesn't need to be guessed in \a error. This means that \a error or some +/// child has GRPC_ERROR_INT_GRPC_STATUS set, or that it is GRPC_ERROR_NONE or +/// GRPC_ERROR_CANCELLED +bool grpc_error_has_clear_grpc_status(grpc_error *error); + +#endif diff --git a/src/core/ext/transport/chttp2/transport/http2_errors.h b/src/core/lib/transport/http2_errors.h index deab2b7e3e..deab2b7e3e 100644 --- a/src/core/ext/transport/chttp2/transport/http2_errors.h +++ b/src/core/lib/transport/http2_errors.h diff --git a/src/core/ext/transport/chttp2/transport/status_conversion.c b/src/core/lib/transport/status_conversion.c index 5dce2f2d0c..eb1d53c8d1 100644 --- a/src/core/ext/transport/chttp2/transport/status_conversion.c +++ b/src/core/lib/transport/status_conversion.c @@ -31,7 +31,7 @@ * */ -#include "src/core/ext/transport/chttp2/transport/status_conversion.h" +#include "src/core/lib/transport/status_conversion.h" int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) { switch (status) { diff --git a/src/core/ext/transport/chttp2/transport/status_conversion.h b/src/core/lib/transport/status_conversion.h index 953bc9f1e1..592411529d 100644 --- a/src/core/ext/transport/chttp2/transport/status_conversion.h +++ b/src/core/lib/transport/status_conversion.h @@ -35,7 +35,7 @@ #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H #include <grpc/grpc.h> -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" +#include "src/core/lib/transport/http2_errors.h" /* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error( |