interceptor.go (11848B)
1 package http 2 3 import ( 4 "context" 5 ) 6 7 func icopy[T any](v []T) []T { 8 s := make([]T, len(v)) 9 copy(s, v) 10 return s 11 } 12 13 // InterceptorContext is all the information available in different 14 // interceptors. 15 // 16 // Not all information is available in each interceptor, see each interface 17 // definition for more details. 18 type InterceptorContext struct { 19 Input any 20 Request *Request 21 22 Output any 23 Response *Response 24 } 25 26 // InterceptorRegistry holds a list of operation interceptors. 27 // 28 // Interceptors allow callers to insert custom behavior at well-defined points 29 // within a client's operation lifecycle. 30 // 31 // # Interceptor context 32 // 33 // All interceptors are invoked with a context object that contains input and 34 // output containers for the operation. The individual fields that are 35 // available will depend on what the interceptor is and, in certain 36 // interceptors, how far the operation was able to progress. See the 37 // documentation for each interface definition for more information about field 38 // availability. 39 // 40 // Implementations MUST NOT directly mutate the values of the fields in the 41 // interceptor context. They are free to mutate the existing values _pointed 42 // to_ by those fields, however. 43 // 44 // # Returning errors 45 // 46 // All interceptors can return errors. If an interceptor returns an error 47 // _before_ the client's retry loop, the operation will fail immediately. If 48 // one returns an error _within_ the retry loop, the error WILL be considered 49 // according to the client's retry policy. 50 // 51 // # Adding interceptors 52 // 53 // Idiomatically you will simply use one of the Add() receiver methods to 54 // register interceptors as desired. However, the list for each interface is 55 // exported on the registry struct and the caller is free to manipulate it 56 // directly, for example, to register a number of interceptors all at once, or 57 // to remove one that was previously registered. 58 // 59 // The base SDK client WILL NOT add any interceptors. SDK operations and 60 // customizations are implemented in terms of middleware. 61 // 62 // Modifications to the registry will not persist across operation calls when 63 // using per-operation functional options. This means you can register 64 // interceptors on a per-operation basis without affecting other operations. 65 type InterceptorRegistry struct { 66 BeforeExecution []BeforeExecutionInterceptor 67 BeforeSerialization []BeforeSerializationInterceptor 68 AfterSerialization []AfterSerializationInterceptor 69 BeforeRetryLoop []BeforeRetryLoopInterceptor 70 BeforeAttempt []BeforeAttemptInterceptor 71 BeforeSigning []BeforeSigningInterceptor 72 AfterSigning []AfterSigningInterceptor 73 BeforeTransmit []BeforeTransmitInterceptor 74 AfterTransmit []AfterTransmitInterceptor 75 BeforeDeserialization []BeforeDeserializationInterceptor 76 AfterDeserialization []AfterDeserializationInterceptor 77 AfterAttempt []AfterAttemptInterceptor 78 AfterExecution []AfterExecutionInterceptor 79 } 80 81 // Copy returns a deep copy of the registry. This is used by SDK clients on 82 // each operation call in order to prevent per-op config mutation from 83 // persisting. 84 func (i *InterceptorRegistry) Copy() InterceptorRegistry { 85 return InterceptorRegistry{ 86 BeforeExecution: icopy(i.BeforeExecution), 87 BeforeSerialization: icopy(i.BeforeSerialization), 88 AfterSerialization: icopy(i.AfterSerialization), 89 BeforeRetryLoop: icopy(i.BeforeRetryLoop), 90 BeforeAttempt: icopy(i.BeforeAttempt), 91 BeforeSigning: icopy(i.BeforeSigning), 92 AfterSigning: icopy(i.AfterSigning), 93 BeforeTransmit: icopy(i.BeforeTransmit), 94 AfterTransmit: icopy(i.AfterTransmit), 95 BeforeDeserialization: icopy(i.BeforeDeserialization), 96 AfterDeserialization: icopy(i.AfterDeserialization), 97 AfterAttempt: icopy(i.AfterAttempt), 98 AfterExecution: icopy(i.AfterExecution), 99 } 100 } 101 102 // AddBeforeExecution registers the provided BeforeExecutionInterceptor. 103 func (i *InterceptorRegistry) AddBeforeExecution(v BeforeExecutionInterceptor) { 104 i.BeforeExecution = append(i.BeforeExecution, v) 105 } 106 107 // AddBeforeSerialization registers the provided BeforeSerializationInterceptor. 108 func (i *InterceptorRegistry) AddBeforeSerialization(v BeforeSerializationInterceptor) { 109 i.BeforeSerialization = append(i.BeforeSerialization, v) 110 } 111 112 // AddAfterSerialization registers the provided AfterSerializationInterceptor. 113 func (i *InterceptorRegistry) AddAfterSerialization(v AfterSerializationInterceptor) { 114 i.AfterSerialization = append(i.AfterSerialization, v) 115 } 116 117 // AddBeforeRetryLoop registers the provided BeforeRetryLoopInterceptor. 118 func (i *InterceptorRegistry) AddBeforeRetryLoop(v BeforeRetryLoopInterceptor) { 119 i.BeforeRetryLoop = append(i.BeforeRetryLoop, v) 120 } 121 122 // AddBeforeAttempt registers the provided BeforeAttemptInterceptor. 123 func (i *InterceptorRegistry) AddBeforeAttempt(v BeforeAttemptInterceptor) { 124 i.BeforeAttempt = append(i.BeforeAttempt, v) 125 } 126 127 // AddBeforeSigning registers the provided BeforeSigningInterceptor. 128 func (i *InterceptorRegistry) AddBeforeSigning(v BeforeSigningInterceptor) { 129 i.BeforeSigning = append(i.BeforeSigning, v) 130 } 131 132 // AddAfterSigning registers the provided AfterSigningInterceptor. 133 func (i *InterceptorRegistry) AddAfterSigning(v AfterSigningInterceptor) { 134 i.AfterSigning = append(i.AfterSigning, v) 135 } 136 137 // AddBeforeTransmit registers the provided BeforeTransmitInterceptor. 138 func (i *InterceptorRegistry) AddBeforeTransmit(v BeforeTransmitInterceptor) { 139 i.BeforeTransmit = append(i.BeforeTransmit, v) 140 } 141 142 // AddAfterTransmit registers the provided AfterTransmitInterceptor. 143 func (i *InterceptorRegistry) AddAfterTransmit(v AfterTransmitInterceptor) { 144 i.AfterTransmit = append(i.AfterTransmit, v) 145 } 146 147 // AddBeforeDeserialization registers the provided BeforeDeserializationInterceptor. 148 func (i *InterceptorRegistry) AddBeforeDeserialization(v BeforeDeserializationInterceptor) { 149 i.BeforeDeserialization = append(i.BeforeDeserialization, v) 150 } 151 152 // AddAfterDeserialization registers the provided AfterDeserializationInterceptor. 153 func (i *InterceptorRegistry) AddAfterDeserialization(v AfterDeserializationInterceptor) { 154 i.AfterDeserialization = append(i.AfterDeserialization, v) 155 } 156 157 // AddAfterAttempt registers the provided AfterAttemptInterceptor. 158 func (i *InterceptorRegistry) AddAfterAttempt(v AfterAttemptInterceptor) { 159 i.AfterAttempt = append(i.AfterAttempt, v) 160 } 161 162 // AddAfterExecution registers the provided AfterExecutionInterceptor. 163 func (i *InterceptorRegistry) AddAfterExecution(v AfterExecutionInterceptor) { 164 i.AfterExecution = append(i.AfterExecution, v) 165 } 166 167 // BeforeExecutionInterceptor runs before anything else in the operation 168 // lifecycle. 169 // 170 // Available InterceptorContext fields: 171 // - Input 172 type BeforeExecutionInterceptor interface { 173 BeforeExecution(ctx context.Context, in *InterceptorContext) error 174 } 175 176 // BeforeSerializationInterceptor runs before the operation input is serialized 177 // into its transport request. 178 // 179 // Serialization occurs before the operation's retry loop. 180 // 181 // Available InterceptorContext fields: 182 // - Input 183 type BeforeSerializationInterceptor interface { 184 BeforeSerialization(ctx context.Context, in *InterceptorContext) error 185 } 186 187 // AfterSerializationInterceptor runs after the operation input is serialized 188 // into its transport request. 189 // 190 // Available InterceptorContext fields: 191 // - Input 192 // - Request 193 type AfterSerializationInterceptor interface { 194 AfterSerialization(ctx context.Context, in *InterceptorContext) error 195 } 196 197 // BeforeRetryLoopInterceptor runs right before the operation enters the retry loop. 198 // 199 // Available InterceptorContext fields: 200 // - Input 201 // - Request 202 type BeforeRetryLoopInterceptor interface { 203 BeforeRetryLoop(ctx context.Context, in *InterceptorContext) error 204 } 205 206 // BeforeAttemptInterceptor runs right before every attempt in the retry loop. 207 // 208 // If this interceptor returns an error, AfterAttempt interceptors WILL NOT be 209 // invoked. 210 // 211 // Available InterceptorContext fields: 212 // - Input 213 // - Request 214 type BeforeAttemptInterceptor interface { 215 BeforeAttempt(ctx context.Context, in *InterceptorContext) error 216 } 217 218 // BeforeSigningInterceptor runs right before the request is signed. 219 // 220 // Signing occurs within the operation's retry loop. 221 // 222 // Available InterceptorContext fields: 223 // - Input 224 // - Request 225 type BeforeSigningInterceptor interface { 226 BeforeSigning(ctx context.Context, in *InterceptorContext) error 227 } 228 229 // AfterSigningInterceptor runs right after the request is signed. 230 // 231 // It is unsafe to modify the outgoing HTTP request at or past this hook, since 232 // doing so may invalidate the signature of the request. 233 // 234 // Available InterceptorContext fields: 235 // - Input 236 // - Request 237 type AfterSigningInterceptor interface { 238 AfterSigning(ctx context.Context, in *InterceptorContext) error 239 } 240 241 // BeforeTransmitInterceptor runs right before the HTTP request is sent. 242 // 243 // HTTP transmit occurs within the operation's retry loop. 244 // 245 // Available InterceptorContext fields: 246 // - Input 247 // - Request 248 type BeforeTransmitInterceptor interface { 249 BeforeTransmit(ctx context.Context, in *InterceptorContext) error 250 } 251 252 // AfterTransmitInterceptor runs right after the HTTP response is received. 253 // 254 // It will always be invoked when a response is received, regardless of its 255 // status code. Conversely, it WILL NOT be invoked if the HTTP round-trip was 256 // not successful, e.g. because of a DNS resolution error 257 // 258 // Available InterceptorContext fields: 259 // - Input 260 // - Request 261 // - Response 262 type AfterTransmitInterceptor interface { 263 AfterTransmit(ctx context.Context, in *InterceptorContext) error 264 } 265 266 // BeforeDeserializationInterceptor runs right before the incoming HTTP response 267 // is deserialized. 268 // 269 // This interceptor IS NOT invoked if the HTTP round-trip was not successful. 270 // 271 // Deserialization occurs within the operation's retry loop. 272 // 273 // Available InterceptorContext fields: 274 // - Input 275 // - Request 276 // - Response 277 type BeforeDeserializationInterceptor interface { 278 BeforeDeserialization(ctx context.Context, in *InterceptorContext) error 279 } 280 281 // AfterDeserializationInterceptor runs right after the incoming HTTP response 282 // is deserialized. This hook is invoked regardless of whether the deserialized 283 // result was an error. 284 // 285 // This interceptor IS NOT invoked if the HTTP round-trip was not successful. 286 // 287 // Available InterceptorContext fields: 288 // - Input 289 // - Output (IF the operation had a success-level response) 290 // - Request 291 // - Response 292 type AfterDeserializationInterceptor interface { 293 AfterDeserialization(ctx context.Context, in *InterceptorContext) error 294 } 295 296 // AfterAttemptInterceptor runs right after the incoming HTTP response 297 // is deserialized. This hook is invoked regardless of whether the deserialized 298 // result was an error, or if another interceptor within the retry loop 299 // returned an error. 300 // 301 // Available InterceptorContext fields: 302 // - Input 303 // - Output (IF the operation had a success-level response) 304 // - Request (IF the operation did not return an error during serialization) 305 // - Response (IF the operation was able to transmit the HTTP request) 306 type AfterAttemptInterceptor interface { 307 AfterAttempt(ctx context.Context, in *InterceptorContext) error 308 } 309 310 // AfterExecutionInterceptor runs after everything else. It runs regardless of 311 // how far the operation progressed in its lifecycle, and regardless of whether 312 // the operation succeeded or failed. 313 // 314 // Available InterceptorContext fields: 315 // - Input 316 // - Output (IF the operation had a success-level response) 317 // - Request (IF the operation did not return an error during serialization) 318 // - Response (IF the operation was able to transmit the HTTP request) 319 type AfterExecutionInterceptor interface { 320 AfterExecution(ctx context.Context, in *InterceptorContext) error 321 }