diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/ext/transport/chttp2/transport/chttp2_transport.c | 78 | ||||
-rw-r--r-- | src/core/ext/transport/chttp2/transport/internal.h | 3 | ||||
-rw-r--r-- | src/core/lib/iomgr/error.c | 2 | ||||
-rw-r--r-- | src/core/lib/iomgr/error.h | 2 |
4 files changed, 73 insertions, 12 deletions
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 31a32f4aaa..7fd2b0bfb9 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -47,6 +47,7 @@ #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/timeout_encoding.h" +#include "src/core/lib/http/parser.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/support/string.h" #include "src/core/lib/transport/static_metadata.h" @@ -105,7 +106,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, static void cancel_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, - grpc_status_code status); + grpc_status_code status, + gpr_slice *optional_message); static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, @@ -161,6 +163,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, GPR_ASSERT(t->ep == NULL); + gpr_slice_unref(t->optional_drop_message); + gpr_slice_buffer_destroy(&t->global.qbuf); gpr_slice_buffer_destroy(&t->writing.outbuf); @@ -261,6 +265,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->parsing.deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->writing.is_client = is_client; + t->optional_drop_message = gpr_empty_slice(); grpc_connectivity_state_init( &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, is_client ? "client_transport" : "server_transport"); @@ -869,7 +874,7 @@ static void maybe_start_some_streams( grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, &stream_global)) { cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_STATUS_UNAVAILABLE); + GRPC_STATUS_UNAVAILABLE, NULL); } } @@ -953,7 +958,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, if (op->cancel_with_status != GRPC_STATUS_OK) { cancel_from_api(exec_ctx, transport_global, stream_global, - op->cancel_with_status); + op->cancel_with_status, op->optional_close_message); } if (op->close_with_status != GRPC_STATUS_OK) { @@ -977,7 +982,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, "(%lu vs. %lu)", metadata_size, metadata_peer_limit); cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_STATUS_RESOURCE_EXHAUSTED); + GRPC_STATUS_RESOURCE_EXHAUSTED, NULL); } else { if (contains_non_ok_status(transport_global, op->send_initial_metadata)) { stream_global->seen_error = true; @@ -1036,7 +1041,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, "(%lu vs. %lu)", metadata_size, metadata_peer_limit); cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_STATUS_RESOURCE_EXHAUSTED); + GRPC_STATUS_RESOURCE_EXHAUSTED, NULL); } else { if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) { @@ -1228,7 +1233,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx, } if (stream_global->exceeded_metadata_size) { cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_STATUS_RESOURCE_EXHAUSTED); + GRPC_STATUS_RESOURCE_EXHAUSTED, NULL); } } grpc_chttp2_incoming_metadata_buffer_publish( @@ -1267,7 +1272,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx, } if (stream_global->exceeded_metadata_size) { cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_STATUS_RESOURCE_EXHAUSTED); + GRPC_STATUS_RESOURCE_EXHAUSTED, NULL); } } if (stream_global->all_incoming_byte_streams_finished) { @@ -1334,7 +1339,8 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void cancel_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, - grpc_status_code status) { + grpc_status_code status, + gpr_slice *optional_message) { if (!stream_global->read_closed || !stream_global->write_closed) { if (stream_global->id != 0) { gpr_slice_buffer_add( @@ -1344,8 +1350,12 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx, (uint32_t)grpc_chttp2_grpc_status_to_http2_error(status), &stream_global->stats.outgoing)); } + + if (optional_message) { + gpr_slice_ref(*optional_message); + } grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status, - NULL); + optional_message); } if (status != GRPC_STATUS_OK && !stream_global->seen_error) { stream_global->seen_error = true; @@ -1571,8 +1581,12 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, void *user_data, grpc_chttp2_stream_global *stream_global) { + grpc_chttp2_transport *transport = TRANSPORT_FROM_GLOBAL(transport_global); cancel_from_api(user_data, transport_global, stream_global, - GRPC_STATUS_UNAVAILABLE); + GRPC_STATUS_UNAVAILABLE, + GPR_SLICE_IS_EMPTY(transport->optional_drop_message) + ? NULL + : &transport->optional_drop_message); } static void end_all_the_calls(grpc_exec_ctx *exec_ctx, @@ -1651,18 +1665,58 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx, } } +static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + grpc_http_parser parser; + size_t i = 0; + grpc_error *error = GRPC_ERROR_NONE; + grpc_http_response response; + memset(&response, 0, sizeof(response)); + + grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response); + + 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); + grpc_http_response_destroy(&response); + return error; +} + 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; - grpc_error *errors[2] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE}; + 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) { + gpr_slice_unref(t->optional_drop_message); + 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 { + t->optional_drop_message = gpr_slice_from_copied_string( + "Connection dropped: received unparseable response"); + } + } grpc_error *err = - errors[0] == GRPC_ERROR_NONE && errors[1] == GRPC_ERROR_NONE + 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)); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 7e5d58380e..54e72ebd24 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -383,6 +383,9 @@ struct grpc_chttp2_transport { /** Transport op to be applied post-parsing */ grpc_transport_op *post_parsing_op; + + /** Message explaining the reason of dropping connection */ + gpr_slice optional_drop_message; }; typedef struct { diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c index edf71b2038..68b44667e5 100644 --- a/src/core/lib/iomgr/error.c +++ b/src/core/lib/iomgr/error.c @@ -113,6 +113,8 @@ static const char *error_int_name(grpc_error_ints key) { return "fd"; case GRPC_ERROR_INT_WSA_ERROR: return "wsa_error"; + case GRPC_ERROR_INT_HTTP_STATUS: + return "http_status"; } GPR_UNREACHABLE_CODE(return "unknown"); } diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h index 02c8cbe115..69cdf3028e 100644 --- a/src/core/lib/iomgr/error.h +++ b/src/core/lib/iomgr/error.h @@ -90,6 +90,8 @@ typedef enum { GRPC_ERROR_INT_WSA_ERROR, /// File descriptor associated with this error GRPC_ERROR_INT_FD, + /// HTTP status (i.e. 404) + GRPC_ERROR_INT_HTTP_STATUS, } grpc_error_ints; typedef enum { |