diff --git a/src/BUILD b/src/BUILD index c654997..bb0975b 100644 --- a/src/BUILD +++ b/src/BUILD @@ -256,6 +256,7 @@ cc_library( ], deps = [ "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", "@com_google_protobuf//:protobuf", ], ) diff --git a/src/include/grpc_transcoding/type_helper.h b/src/include/grpc_transcoding/type_helper.h index 4f3763a..e9cecae 100644 --- a/src/include/grpc_transcoding/type_helper.h +++ b/src/include/grpc_transcoding/type_helper.h @@ -27,11 +27,10 @@ namespace grpc { namespace transcoding { -class SimpleTypeResolver; - // Provides ::google::protobuf::util::TypeResolver and // ::google::protobuf::util::converter::TypeInfo implementations based on a // collection of types and a collection of enums. +// This object is thread-safe class TypeHelper { public: template @@ -76,10 +75,6 @@ class TypeHelper { void AddType(const ::google::protobuf::Type& t); void AddEnum(const ::google::protobuf::Enum& e); - // We can't use a unique_ptr as the default deleter of - // unique_ptr requires the type to be defined when the unique_ptr destructor - // is called. In our case it's called from the template constructor below - // (most likely as a part of stack unwinding when an exception occurs). ::google::protobuf::util::TypeResolver* type_resolver_; std::unique_ptr<::google::protobuf::util::converter::TypeInfo> type_info_; diff --git a/src/type_helper.cc b/src/type_helper.cc index 52010e1..d4df3fb 100644 --- a/src/type_helper.cc +++ b/src/type_helper.cc @@ -16,15 +16,15 @@ // #include "grpc_transcoding/type_helper.h" -#include "absl/strings/str_split.h" +#include +#include +#include "absl/strings/str_split.h" +#include "absl/synchronization/mutex.h" #include "google/protobuf/type.pb.h" #include "google/protobuf/util/internal/type_info.h" #include "google/protobuf/util/type_resolver.h" -#include -#include - namespace pbutil = ::google::protobuf::util; namespace pbconv = ::google::protobuf::util::converter; @@ -32,6 +32,7 @@ namespace google { namespace grpc { namespace transcoding { +namespace { const char DEFAULT_URL_PREFIX[] = "type.googleapis.com/"; @@ -108,9 +109,46 @@ class SimpleTypeResolver : public pbutil::TypeResolver { SimpleTypeResolver& operator=(const SimpleTypeResolver&) = delete; }; +class LockedTypeInfo : public pbconv::TypeInfo { + public: + LockedTypeInfo(pbconv::TypeInfo* type_info) : type_info_(type_info) {} + + pbutil::StatusOr ResolveTypeUrl( + google::protobuf::StringPiece type_url) const override { + absl::MutexLock lock(&mutex_); + return type_info_->ResolveTypeUrl(type_url); + } + + const google::protobuf::Type* GetTypeByTypeUrl( + google::protobuf::StringPiece type_url) const override { + absl::MutexLock lock(&mutex_); + return type_info_->GetTypeByTypeUrl(type_url); + } + + const google::protobuf::Enum* GetEnumByTypeUrl( + google::protobuf::StringPiece type_url) const override { + absl::MutexLock lock(&mutex_); + return type_info_->GetEnumByTypeUrl(type_url); + } + + const google::protobuf::Field* FindField( + const google::protobuf::Type* type, + google::protobuf::StringPiece camel_case_name) const override { + absl::MutexLock lock(&mutex_); + return type_info_->FindField(type, camel_case_name); + } + + private: + mutable absl::Mutex mutex_; + std::unique_ptr type_info_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace + TypeHelper::TypeHelper(pbutil::TypeResolver* type_resolver) : type_resolver_(type_resolver), - type_info_(pbconv::TypeInfo::NewTypeInfo(type_resolver)) {} + type_info_( + new LockedTypeInfo(pbconv::TypeInfo::NewTypeInfo(type_resolver))) {} TypeHelper::~TypeHelper() { type_info_.reset(); @@ -123,7 +161,8 @@ pbconv::TypeInfo* TypeHelper::Info() const { return type_info_.get(); } void TypeHelper::Initialize() { type_resolver_ = new SimpleTypeResolver(); - type_info_.reset(pbconv::TypeInfo::NewTypeInfo(type_resolver_)); + type_info_.reset( + new LockedTypeInfo(pbconv::TypeInfo::NewTypeInfo(type_resolver_))); } void TypeHelper::AddType(const google::protobuf::Type& t) {