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 }
322