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 19 #ifndef GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H 20 #define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H 21 22 #include <memory> 23 24 #include <grpc/impl/codegen/grpc_types.h> 25 #include <grpcpp/impl/codegen/byte_buffer.h> 26 #include <grpcpp/impl/codegen/config.h> 27 #include <grpcpp/impl/codegen/core_codegen_interface.h> 28 #include <grpcpp/impl/codegen/metadata_map.h> 29 30 namespace grpc { 31 32 class ChannelInterface; 33 class Status; 34 35 namespace experimental { 36 37 /// An enumeration of different possible points at which the \a Intercept 38 /// method of the \a Interceptor interface may be called. Any given call 39 /// to \a Intercept will include one or more of these hook points, and 40 /// each hook point makes certain types of information available to the 41 /// interceptor. 42 /// In these enumeration names, PRE_SEND means that an interception has taken 43 /// place between the time the application provided a certain type of data 44 /// (e.g., initial metadata, status) and the time that that data goes to the 45 /// other side. POST_SEND means that the data has been committed for going to 46 /// the other side (even if it has not yet been received at the other side). 47 /// PRE_RECV means an interception between the time that a certain 48 /// operation has been requested and it is available. POST_RECV means that a 49 /// result is available but has not yet been passed back to the application. 50 /// A batch of interception points will only contain either PRE or POST hooks 51 /// but not both types. For example, a batch with PRE_SEND hook points will not 52 /// contain POST_RECV or POST_SEND ops. Likewise, a batch with POST_* ops can 53 /// not contain PRE_* ops. 54 enum class InterceptionHookPoints { 55 /// The first three in this list are for clients and servers 56 PRE_SEND_INITIAL_METADATA, 57 PRE_SEND_MESSAGE, 58 POST_SEND_MESSAGE, 59 PRE_SEND_STATUS, // server only 60 PRE_SEND_CLOSE, // client only: WritesDone for stream; after write in unary 61 /// The following three are for hijacked clients only. A batch with PRE_RECV_* 62 /// hook points will never contain hook points of other types. 63 PRE_RECV_INITIAL_METADATA, 64 PRE_RECV_MESSAGE, 65 PRE_RECV_STATUS, 66 /// The following two are for all clients and servers 67 POST_RECV_INITIAL_METADATA, 68 POST_RECV_MESSAGE, 69 POST_RECV_STATUS, // client only 70 POST_RECV_CLOSE, // server only 71 /// This is a special hook point available to both clients and servers when 72 /// TryCancel() is performed. 73 /// - No other hook points will be present along with this. 74 /// - It is illegal for an interceptor to block/delay this operation. 75 /// - ALL interceptors see this hook point irrespective of whether the 76 /// RPC was hijacked or not. 77 PRE_SEND_CANCEL, 78 NUM_INTERCEPTION_HOOKS 79 }; 80 81 /// Class that is passed as an argument to the \a Intercept method 82 /// of the application's \a Interceptor interface implementation. It has five 83 /// purposes: 84 /// 1. Indicate which hook points are present at a specific interception 85 /// 2. Allow an interceptor to inform the library that an RPC should 86 /// continue to the next stage of its processing (which may be another 87 /// interceptor or the main path of the library) 88 /// 3. Allow an interceptor to hijack the processing of the RPC (only for 89 /// client-side RPCs with PRE_SEND_INITIAL_METADATA) so that it does not 90 /// proceed with normal processing beyond that stage 91 /// 4. Access the relevant fields of an RPC at each interception point 92 /// 5. Set some fields of an RPC at each interception point, when possible 93 class InterceptorBatchMethods { 94 public: ~InterceptorBatchMethods()95 virtual ~InterceptorBatchMethods() {} 96 /// Determine whether the current batch has an interception hook point 97 /// of type \a type 98 virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0; 99 /// Signal that the interceptor is done intercepting the current batch of the 100 /// RPC. Every interceptor must either call Proceed or Hijack on each 101 /// interception. In most cases, only Proceed will be used. Explicit use of 102 /// Proceed is what enables interceptors to delay the processing of RPCs 103 /// while they perform other work. 104 /// Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning 105 /// from the Intercept method does the job of continuing the RPC in this case. 106 /// This is because PRE_SEND_CANCEL is always in a separate batch and is not 107 /// allowed to be delayed. 108 virtual void Proceed() = 0; 109 /// Indicate that the interceptor has hijacked the RPC (only valid if the 110 /// batch contains send_initial_metadata on the client side). Later 111 /// interceptors in the interceptor list will not be called. Later batches 112 /// on the same RPC will go through interception, but only up to the point 113 /// of the hijacking interceptor. 114 virtual void Hijack() = 0; 115 116 /// Send Message Methods 117 /// GetSerializedSendMessage and GetSendMessage/ModifySendMessage are the 118 /// available methods to view and modify the request payload. An interceptor 119 /// can access the payload in either serialized form or non-serialized form 120 /// but not both at the same time. 121 /// gRPC performs serialization in a lazy manner, which means 122 /// that a call to GetSerializedSendMessage will result in a serialization 123 /// operation if the payload stored is not in the serialized form already; the 124 /// non-serialized form will be lost and GetSendMessage will no longer return 125 /// a valid pointer, and this will remain true for later interceptors too. 126 /// This can change however if ModifySendMessage is used to replace the 127 /// current payload. Note that ModifySendMessage requires a new payload 128 /// message in the non-serialized form. This will overwrite the existing 129 /// payload irrespective of whether it had been serialized earlier. Also note 130 /// that gRPC Async API requires early serialization of the payload which 131 /// means that the payload would be available in the serialized form only 132 /// unless an interceptor replaces the payload with ModifySendMessage. 133 134 /// Returns a modifable ByteBuffer holding the serialized form of the message 135 /// that is going to be sent. Valid for PRE_SEND_MESSAGE interceptions. 136 /// A return value of nullptr indicates that this ByteBuffer is not valid. 137 virtual ByteBuffer* GetSerializedSendMessage() = 0; 138 139 /// Returns a non-modifiable pointer to the non-serialized form of the message 140 /// to be sent. Valid for PRE_SEND_MESSAGE interceptions. A return value of 141 /// nullptr indicates that this field is not valid. 142 virtual const void* GetSendMessage() = 0; 143 144 /// Overwrites the message to be sent with \a message. \a message should be in 145 /// the non-serialized form expected by the method. Valid for PRE_SEND_MESSAGE 146 /// interceptions. Note that the interceptor is responsible for maintaining 147 /// the life of the message till it is serialized or it receives the 148 /// POST_SEND_MESSAGE interception point, whichever happens earlier. The 149 /// modifying interceptor may itself force early serialization by calling 150 /// GetSerializedSendMessage. 151 virtual void ModifySendMessage(const void* message) = 0; 152 153 /// Checks whether the SEND MESSAGE op succeeded. Valid for POST_SEND_MESSAGE 154 /// interceptions. 155 virtual bool GetSendMessageStatus() = 0; 156 157 /// Returns a modifiable multimap of the initial metadata to be sent. Valid 158 /// for PRE_SEND_INITIAL_METADATA interceptions. A value of nullptr indicates 159 /// that this field is not valid. 160 virtual std::multimap<std::string, std::string>* GetSendInitialMetadata() = 0; 161 162 /// Returns the status to be sent. Valid for PRE_SEND_STATUS interceptions. 163 virtual Status GetSendStatus() = 0; 164 165 /// Overwrites the status with \a status. Valid for PRE_SEND_STATUS 166 /// interceptions. 167 virtual void ModifySendStatus(const Status& status) = 0; 168 169 /// Returns a modifiable multimap of the trailing metadata to be sent. Valid 170 /// for PRE_SEND_STATUS interceptions. A value of nullptr indicates 171 /// that this field is not valid. 172 virtual std::multimap<std::string, std::string>* 173 GetSendTrailingMetadata() = 0; 174 175 /// Returns a pointer to the modifiable received message. Note that the 176 /// message is already deserialized but the type is not set; the interceptor 177 /// should static_cast to the appropriate type before using it. This is valid 178 /// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not 179 /// valid 180 virtual void* GetRecvMessage() = 0; 181 182 /// Returns a modifiable multimap of the received initial metadata. 183 /// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA 184 /// interceptions; nullptr if not valid 185 virtual std::multimap<grpc::string_ref, grpc::string_ref>* 186 GetRecvInitialMetadata() = 0; 187 188 /// Returns a modifiable view of the received status on PRE_RECV_STATUS and 189 /// POST_RECV_STATUS interceptions; nullptr if not valid. 190 virtual Status* GetRecvStatus() = 0; 191 192 /// Returns a modifiable multimap of the received trailing metadata on 193 /// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid 194 virtual std::multimap<grpc::string_ref, grpc::string_ref>* 195 GetRecvTrailingMetadata() = 0; 196 197 /// Gets an intercepted channel. When a call is started on this interceptor, 198 /// only interceptors after the current interceptor are created from the 199 /// factory objects registered with the channel. This allows calls to be 200 /// started from interceptors without infinite regress through the interceptor 201 /// list. 202 virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0; 203 204 /// On a hijacked RPC, an interceptor can decide to fail a PRE_RECV_MESSAGE 205 /// op. This would be a signal to the reader that there will be no more 206 /// messages, or the stream has failed or been cancelled. 207 virtual void FailHijackedRecvMessage() = 0; 208 209 /// On a hijacked RPC/ to-be hijacked RPC, this can be called to fail a SEND 210 /// MESSAGE op 211 virtual void FailHijackedSendMessage() = 0; 212 }; 213 214 /// Interface for an interceptor. Interceptor authors must create a class 215 /// that derives from this parent class. 216 class Interceptor { 217 public: ~Interceptor()218 virtual ~Interceptor() {} 219 220 /// The one public method of an Interceptor interface. Override this to 221 /// trigger the desired actions at the hook points described above. 222 virtual void Intercept(InterceptorBatchMethods* methods) = 0; 223 }; 224 225 } // namespace experimental 226 } // namespace grpc 227 228 #endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H 229