| 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: |
| 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<grpc::string, grpc::string>* |
| 161 | GetSendInitialMetadata() = 0; |
| 162 | |
| 163 | /// Returns the status to be sent. Valid for PRE_SEND_STATUS interceptions. |
| 164 | virtual Status GetSendStatus() = 0; |
| 165 | |
| 166 | /// Overwrites the status with \a status. Valid for PRE_SEND_STATUS |
| 167 | /// interceptions. |
| 168 | virtual void ModifySendStatus(const Status& status) = 0; |
| 169 | |
| 170 | /// Returns a modifiable multimap of the trailing metadata to be sent. Valid |
| 171 | /// for PRE_SEND_STATUS interceptions. A value of nullptr indicates |
| 172 | /// that this field is not valid. |
| 173 | virtual std::multimap<grpc::string, grpc::string>* |
| 174 | GetSendTrailingMetadata() = 0; |
| 175 | |
| 176 | /// Returns a pointer to the modifiable received message. Note that the |
| 177 | /// message is already deserialized but the type is not set; the interceptor |
| 178 | /// should static_cast to the appropriate type before using it. This is valid |
| 179 | /// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not |
| 180 | /// valid |
| 181 | virtual void* GetRecvMessage() = 0; |
| 182 | |
| 183 | /// Returns a modifiable multimap of the received initial metadata. |
| 184 | /// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA |
| 185 | /// interceptions; nullptr if not valid |
| 186 | virtual std::multimap<grpc::string_ref, grpc::string_ref>* |
| 187 | GetRecvInitialMetadata() = 0; |
| 188 | |
| 189 | /// Returns a modifiable view of the received status on PRE_RECV_STATUS and |
| 190 | /// POST_RECV_STATUS interceptions; nullptr if not valid. |
| 191 | virtual Status* GetRecvStatus() = 0; |
| 192 | |
| 193 | /// Returns a modifiable multimap of the received trailing metadata on |
| 194 | /// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid |
| 195 | virtual std::multimap<grpc::string_ref, grpc::string_ref>* |
| 196 | GetRecvTrailingMetadata() = 0; |
| 197 | |
| 198 | /// Gets an intercepted channel. When a call is started on this interceptor, |
| 199 | /// only interceptors after the current interceptor are created from the |
| 200 | /// factory objects registered with the channel. This allows calls to be |
| 201 | /// started from interceptors without infinite regress through the interceptor |
| 202 | /// list. |
| 203 | virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0; |
| 204 | |
| 205 | /// On a hijacked RPC, an interceptor can decide to fail a PRE_RECV_MESSAGE |
| 206 | /// op. This would be a signal to the reader that there will be no more |
| 207 | /// messages, or the stream has failed or been cancelled. |
| 208 | virtual void FailHijackedRecvMessage() = 0; |
| 209 | |
| 210 | /// On a hijacked RPC/ to-be hijacked RPC, this can be called to fail a SEND |
| 211 | /// MESSAGE op |
| 212 | virtual void FailHijackedSendMessage() = 0; |
| 213 | }; |
| 214 | |
| 215 | /// Interface for an interceptor. Interceptor authors must create a class |
| 216 | /// that derives from this parent class. |
| 217 | class Interceptor { |
| 218 | public: |
| 219 | virtual ~Interceptor() {} |
| 220 | |
| 221 | /// The one public method of an Interceptor interface. Override this to |
| 222 | /// trigger the desired actions at the hook points described above. |
| 223 | virtual void Intercept(InterceptorBatchMethods* methods) = 0; |
| 224 | }; |
| 225 | |
| 226 | } // namespace experimental |
| 227 | } // namespace grpc |
| 228 | |
| 229 | #endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H |
| 230 | |