client_interceptor.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. *
  3. * Copyright 2018 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
  19. #define GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
  20. // IWYU pragma: private, include <grpcpp/support/client_interceptor.h>
  21. #include <memory>
  22. #include <vector>
  23. #include <grpcpp/impl/codegen/interceptor.h>
  24. #include <grpcpp/impl/codegen/rpc_method.h>
  25. #include <grpcpp/impl/codegen/string_ref.h>
  26. namespace grpc {
  27. class Channel;
  28. class ClientContext;
  29. namespace internal {
  30. class InterceptorBatchMethodsImpl;
  31. }
  32. namespace experimental {
  33. class ClientRpcInfo;
  34. // A factory interface for creation of client interceptors. A vector of
  35. // factories can be provided at channel creation which will be used to create a
  36. // new vector of client interceptors per RPC. Client interceptor authors should
  37. // create a subclass of ClientInterceptorFactorInterface which creates objects
  38. // of their interceptors.
  39. class ClientInterceptorFactoryInterface {
  40. public:
  41. virtual ~ClientInterceptorFactoryInterface() {}
  42. // Returns a pointer to an Interceptor object on successful creation, nullptr
  43. // otherwise. If nullptr is returned, this server interceptor factory is
  44. // ignored for the purposes of that RPC.
  45. virtual Interceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0;
  46. };
  47. } // namespace experimental
  48. namespace internal {
  49. extern experimental::ClientInterceptorFactoryInterface*
  50. g_global_client_interceptor_factory;
  51. }
  52. /// ClientRpcInfo represents the state of a particular RPC as it
  53. /// appears to an interceptor. It is created and owned by the library and
  54. /// passed to the CreateClientInterceptor method of the application's
  55. /// ClientInterceptorFactoryInterface implementation
  56. namespace experimental {
  57. class ClientRpcInfo {
  58. public:
  59. // TODO(yashykt): Stop default-constructing ClientRpcInfo and remove UNKNOWN
  60. // from the list of possible Types.
  61. /// Type categorizes RPCs by unary or streaming type
  62. enum class Type {
  63. UNARY,
  64. CLIENT_STREAMING,
  65. SERVER_STREAMING,
  66. BIDI_STREAMING,
  67. UNKNOWN // UNKNOWN is not API and will be removed later
  68. };
  69. ~ClientRpcInfo() {}
  70. // Delete copy constructor but allow default move constructor
  71. ClientRpcInfo(const ClientRpcInfo&) = delete;
  72. ClientRpcInfo(ClientRpcInfo&&) = default;
  73. // Getter methods
  74. /// Return the fully-specified method name
  75. const char* method() const { return method_; }
  76. /// Return an identifying suffix for the client stub, or nullptr if one wasn't
  77. /// specified.
  78. const char* suffix_for_stats() const { return suffix_for_stats_; }
  79. /// Return a pointer to the channel on which the RPC is being sent
  80. ChannelInterface* channel() { return channel_; }
  81. /// Return a pointer to the underlying ClientContext structure associated
  82. /// with the RPC to support features that apply to it
  83. grpc::ClientContext* client_context() { return ctx_; }
  84. /// Return the type of the RPC (unary or a streaming flavor)
  85. Type type() const { return type_; }
  86. private:
  87. static_assert(Type::UNARY ==
  88. static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
  89. "violated expectation about Type enum");
  90. static_assert(Type::CLIENT_STREAMING ==
  91. static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
  92. "violated expectation about Type enum");
  93. static_assert(Type::SERVER_STREAMING ==
  94. static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
  95. "violated expectation about Type enum");
  96. static_assert(Type::BIDI_STREAMING ==
  97. static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
  98. "violated expectation about Type enum");
  99. // Default constructor should only be used by ClientContext
  100. ClientRpcInfo() = default;
  101. // Constructor will only be called from ClientContext
  102. ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
  103. const char* method, const char* suffix_for_stats,
  104. grpc::ChannelInterface* channel)
  105. : ctx_(ctx),
  106. type_(static_cast<Type>(type)),
  107. method_(method),
  108. suffix_for_stats_(suffix_for_stats),
  109. channel_(channel) {}
  110. // Move assignment should only be used by ClientContext
  111. // TODO(yashykt): Delete move assignment
  112. ClientRpcInfo& operator=(ClientRpcInfo&&) = default;
  113. // Runs interceptor at pos \a pos.
  114. void RunInterceptor(
  115. experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
  116. GPR_CODEGEN_ASSERT(pos < interceptors_.size());
  117. interceptors_[pos]->Intercept(interceptor_methods);
  118. }
  119. void RegisterInterceptors(
  120. const std::vector<std::unique_ptr<
  121. experimental::ClientInterceptorFactoryInterface>>& creators,
  122. size_t interceptor_pos) {
  123. if (interceptor_pos > creators.size()) {
  124. // No interceptors to register
  125. return;
  126. }
  127. // NOTE: The following is not a range-based for loop because it will only
  128. // iterate over a portion of the creators vector.
  129. for (auto it = creators.begin() + interceptor_pos; it != creators.end();
  130. ++it) {
  131. auto* interceptor = (*it)->CreateClientInterceptor(this);
  132. if (interceptor != nullptr) {
  133. interceptors_.push_back(
  134. std::unique_ptr<experimental::Interceptor>(interceptor));
  135. }
  136. }
  137. if (internal::g_global_client_interceptor_factory != nullptr) {
  138. interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
  139. internal::g_global_client_interceptor_factory
  140. ->CreateClientInterceptor(this)));
  141. }
  142. }
  143. grpc::ClientContext* ctx_ = nullptr;
  144. // TODO(yashykt): make type_ const once move-assignment is deleted
  145. Type type_{Type::UNKNOWN};
  146. const char* method_ = nullptr;
  147. const char* suffix_for_stats_ = nullptr;
  148. grpc::ChannelInterface* channel_ = nullptr;
  149. std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
  150. bool hijacked_ = false;
  151. size_t hijacked_interceptor_ = 0;
  152. friend class internal::InterceptorBatchMethodsImpl;
  153. friend class grpc::ClientContext;
  154. };
  155. // PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL
  156. // INTERCEPTOR. IF USAGE IS ABSOLUTELY NECESSARY, PLEASE READ THE SAFETY NOTES.
  157. // Registers a global client interceptor factory object, which is used for all
  158. // RPCs made in this process. The application is responsible for maintaining the
  159. // life of the object while gRPC operations are in progress. The global
  160. // interceptor factory should only be registered once at the start of the
  161. // process before any gRPC operations have begun.
  162. void RegisterGlobalClientInterceptorFactory(
  163. ClientInterceptorFactoryInterface* factory);
  164. // For testing purposes only
  165. void TestOnlyResetGlobalClientInterceptorFactory();
  166. } // namespace experimental
  167. } // namespace grpc
  168. #endif // GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H