diff options
author | Vijay Pai <vpai@google.com> | 2017-12-18 14:33:51 -0800 |
---|---|---|
committer | Vijay Pai <vpai@google.com> | 2018-01-08 15:12:55 -0800 |
commit | 8fc3715a17a1b764143d0b37652a07a45d1cdf01 (patch) | |
tree | 4000f1689f130222871eb275e17be5d908b14afe /include/grpc++ | |
parent | e3756b9cf1ee583688bbef3795900422cc1451d5 (diff) |
Catch exceptions from sync method handlers without crashing server
Diffstat (limited to 'include/grpc++')
-rw-r--r-- | include/grpc++/impl/codegen/method_handler_impl.h | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h index c0af4ca130..b72dceb1b4 100644 --- a/include/grpc++/impl/codegen/method_handler_impl.h +++ b/include/grpc++/impl/codegen/method_handler_impl.h @@ -27,6 +27,25 @@ namespace grpc { namespace internal { + +// Invoke the method handler, fill in the status, and +// return whether or not we finished safely (without an exception). +// Note that exception handling is 0-cost in most compiler/library +// implementations (except when an exception is actually thrown), +// so this process doesn't require additional overhead in the common case. +// Additionally, we don't need to return if we caught an exception or not; +// the handling is the same in either case. +template <class F> +Status CatchingFunctionHandler(F&& callable) { + try { + return callable(); + } catch (const std::exception& e) { + return Status(StatusCode::UNKNOWN, e.what()); + } catch (...) { + return Status(StatusCode::UNKNOWN, "Exception in method handler"); + } +} + /// A wrapper class of an application provided rpc method handler. template <class ServiceType, class RequestType, class ResponseType> class RpcMethodHandler : public MethodHandler { @@ -43,7 +62,9 @@ class RpcMethodHandler : public MethodHandler { param.request.bbuf_ptr(), &req); ResponseType rsp; if (status.ok()) { - status = func_(service_, param.server_context, &req, &rsp); + status = CatchingFunctionHandler([this, ¶m, &req, &rsp] { + return func_(service_, param.server_context, &req, &rsp); + }); } GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_); @@ -86,7 +107,9 @@ class ClientStreamingHandler : public MethodHandler { void RunHandler(const HandlerParameter& param) final { ServerReader<RequestType> reader(param.call, param.server_context); ResponseType rsp; - Status status = func_(service_, param.server_context, &reader, &rsp); + Status status = CatchingFunctionHandler([this, ¶m, &reader, &rsp] { + return func_(service_, param.server_context, &reader, &rsp); + }); GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_); CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, @@ -130,7 +153,9 @@ class ServerStreamingHandler : public MethodHandler { if (status.ok()) { ServerWriter<ResponseType> writer(param.call, param.server_context); - status = func_(service_, param.server_context, &req, &writer); + status = CatchingFunctionHandler([this, ¶m, &req, &writer] { + return func_(service_, param.server_context, &req, &writer); + }); } CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops; @@ -172,7 +197,9 @@ class TemplatedBidiStreamingHandler : public MethodHandler { void RunHandler(const HandlerParameter& param) final { Streamer stream(param.call, param.server_context); - Status status = func_(param.server_context, &stream); + Status status = CatchingFunctionHandler([this, ¶m, &stream] { + return func_(param.server_context, &stream); + }); CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops; if (!param.server_context->sent_initial_metadata_) { |