src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }