aws_smithy_runtime_api/client/
interceptors.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Interceptors for clients.
7//!
8//! Interceptors are operation lifecycle hooks that can read/modify requests and responses.
9
10use crate::box_error::BoxError;
11use crate::client::interceptors::context::{
12    AfterDeserializationInterceptorContextRef, BeforeDeserializationInterceptorContextMut,
13    BeforeDeserializationInterceptorContextRef, BeforeSerializationInterceptorContextMut,
14    BeforeSerializationInterceptorContextRef, BeforeTransmitInterceptorContextMut,
15    BeforeTransmitInterceptorContextRef, FinalizerInterceptorContextMut,
16    FinalizerInterceptorContextRef,
17};
18use crate::client::runtime_components::sealed::ValidateConfig;
19use crate::client::runtime_components::RuntimeComponents;
20use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
21use std::fmt;
22use std::marker::PhantomData;
23use std::sync::Arc;
24
25pub mod context;
26pub mod error;
27
28use crate::impl_shared_conversions;
29pub use error::InterceptorError;
30
31macro_rules! interceptor_trait_fn {
32    ($name:ident, $phase:ident, $docs:tt) => {
33        #[doc = $docs]
34        fn $name(
35            &self,
36            context: &$phase<'_>,
37            runtime_components: &RuntimeComponents,
38            cfg: &mut ConfigBag,
39        ) -> Result<(), BoxError> {
40            let (_ctx, _rc, _cfg) = (context, runtime_components, cfg);
41            Ok(())
42        }
43    };
44    (mut $name:ident, $phase:ident, $docs:tt) => {
45        #[doc = $docs]
46        fn $name(
47            &self,
48            context: &mut $phase<'_>,
49            runtime_components: &RuntimeComponents,
50            cfg: &mut ConfigBag,
51        ) -> Result<(), BoxError> {
52            let (_ctx, _rc, _cfg) = (context, runtime_components, cfg);
53            Ok(())
54        }
55    };
56}
57
58/// An interceptor allows injecting code into the SDK ’s request execution pipeline.
59///
60/// ## Terminology:
61/// - An execution is one end-to-end invocation against an SDK client.
62/// - An attempt is an attempt at performing an execution. By default executions are retried multiple
63///   times based on the client ’s retry strategy.
64/// - A hook is a single method on the interceptor, allowing injection of code into a specific part
65///   of the SDK ’s request execution pipeline. Hooks are either "read" hooks, which make it possible
66///   to read in-flight request or response messages, or "read/write" hooks, which make it possible
67///   to modify in-flight request or output messages.
68pub trait Intercept: fmt::Debug + Send + Sync {
69    /// The name of this interceptor, used in error messages for debugging.
70    fn name(&self) -> &'static str;
71
72    /// A hook called at the start of an execution, before the SDK
73    /// does anything else.
74    ///
75    /// **When:** This will **ALWAYS** be called once per execution. The duration
76    /// between invocation of this hook and `after_execution` is very close
77    /// to full duration of the execution.
78    ///
79    /// **Available Information:** The [`InterceptorContext::input`](context::InterceptorContext::input)
80    /// is **ALWAYS** available. Other information **WILL NOT** be available.
81    ///
82    /// **Error Behavior:** Errors raised by this hook will be stored
83    /// until all interceptors have had their `before_execution` invoked.
84    /// Other hooks will then be skipped and execution will jump to
85    /// `modify_before_completion` with the raised error as the
86    /// [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error). If multiple
87    /// `before_execution` methods raise errors, the latest
88    /// will be used and earlier ones will be logged and dropped.
89    fn read_before_execution(
90        &self,
91        context: &BeforeSerializationInterceptorContextRef<'_>,
92        cfg: &mut ConfigBag,
93    ) -> Result<(), BoxError> {
94        let (_ctx, _cfg) = (context, cfg);
95        Ok(())
96    }
97
98    interceptor_trait_fn!(
99        mut modify_before_serialization,
100        BeforeSerializationInterceptorContextMut,
101        "
102        A hook called before the input message is marshalled into a
103        transport message.
104        This method has the ability to modify and return a new
105        request message of the same type.
106
107        **When:** This will **ALWAYS** be called once per execution, except when a
108        failure occurs earlier in the request pipeline.
109
110        **Available Information:** The [`InterceptorContext::input`](context::InterceptorContext::input) is
111        **ALWAYS** available. This request may have been modified by earlier
112        `modify_before_serialization` hooks, and may be modified further by
113        later hooks. Other information **WILL NOT** be available.
114
115        **Error Behavior:** If errors are raised by this hook,
116        execution will jump to `modify_before_completion` with the raised
117        error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
118
119        **Return Constraints:** The input message returned by this hook
120        MUST be the same type of input message passed into this hook.
121        If not, an error will immediately be raised.
122        "
123    );
124
125    interceptor_trait_fn!(
126        read_before_serialization,
127        BeforeSerializationInterceptorContextRef,
128        "
129        A hook called before the input message is marshalled
130        into a transport
131        message.
132
133        **When:** This will **ALWAYS** be called once per execution, except when a
134        failure occurs earlier in the request pipeline. The
135        duration between invocation of this hook and `after_serialization` is
136        very close to the amount of time spent marshalling the request.
137
138        **Available Information:** The [`InterceptorContext::input`](context::InterceptorContext::input) is
139        **ALWAYS** available. Other information **WILL NOT** be available.
140
141        **Error Behavior:** If errors are raised by this hook,
142        execution will jump to `modify_before_completion` with the raised
143        error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
144        "
145    );
146
147    interceptor_trait_fn!(
148        read_after_serialization,
149        BeforeTransmitInterceptorContextRef,
150        "
151        A hook called after the input message is marshalled into
152        a transport message.
153
154        **When:** This will **ALWAYS** be called once per execution, except when a
155        failure occurs earlier in the request pipeline. The duration
156        between invocation of this hook and `before_serialization` is very
157        close to the amount of time spent marshalling the request.
158
159        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request)
160        is **ALWAYS** available. Other information **WILL NOT** be available.
161
162        **Error Behavior:** If errors are raised by this hook,
163        execution will jump to `modify_before_completion` with the raised
164        error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
165        "
166    );
167
168    interceptor_trait_fn!(
169        mut modify_before_retry_loop,
170        BeforeTransmitInterceptorContextMut,
171        "
172        A hook called before the retry loop is entered. This method
173        has the ability to modify and return a new transport request
174        message of the same type, except when a failure occurs earlier in the request pipeline.
175
176        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request)
177        is **ALWAYS** available. Other information **WILL NOT** be available.
178
179        **Error Behavior:** If errors are raised by this hook,
180        execution will jump to `modify_before_completion` with the raised
181        error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
182
183        **Return Constraints:** The transport request message returned by this
184        hook MUST be the same type of request message passed into this hook
185        If not, an error will immediately be raised.
186        "
187    );
188
189    interceptor_trait_fn!(
190        read_before_attempt,
191        BeforeTransmitInterceptorContextRef,
192        "
193        A hook called before each attempt at sending the transmission
194        request message to the service.
195
196        **When:** This will **ALWAYS** be called once per attempt, except when a
197        failure occurs earlier in the request pipeline. This method will be
198        called multiple times in the event of retries.
199
200        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request)
201        is **ALWAYS** available. Other information **WILL NOT** be available. In the event of retries,
202        the `InterceptorContext` will not include changes made in previous
203        attempts (e.g. by request signers or other interceptors).
204
205        **Error Behavior:** Errors raised by this hook will be stored
206        until all interceptors have had their `before_attempt` invoked.
207        Other hooks will then be skipped and execution will jump to
208        `modify_before_attempt_completion` with the raised error as the
209        [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error). If multiple
210        `before_attempt` methods raise errors, the latest will be used
211        and earlier ones will be logged and dropped.
212        "
213    );
214
215    interceptor_trait_fn!(
216        mut modify_before_signing,
217        BeforeTransmitInterceptorContextMut,
218        "
219        A hook called before the transport request message is signed.
220        This method has the ability to modify and return a new transport
221        request message of the same type.
222
223        **When:** This will **ALWAYS** be called once per attempt, except when a
224        failure occurs earlier in the request pipeline. This method may be
225        called multiple times in the event of retries.
226
227        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request)
228        is **ALWAYS** available. The `http::Request` may have been modified by earlier
229        `modify_before_signing` hooks, and may be modified further by later
230        hooks. Other information **WILL NOT** be available. In the event of
231        retries, the `InterceptorContext` will not include changes made
232        in previous attempts (e.g. by request signers or other interceptors).
233
234        **Error Behavior:** If errors are raised by this
235        hook, execution will jump to `modify_before_attempt_completion` with
236        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
237
238        **Return Constraints:** The transport request message returned by this
239        hook MUST be the same type of request message passed into this hook
240
241        If not, an error will immediately be raised.
242        "
243    );
244
245    interceptor_trait_fn!(
246        read_before_signing,
247        BeforeTransmitInterceptorContextRef,
248        "
249        A hook called before the transport request message is signed.
250
251        **When:** This will **ALWAYS** be called once per attempt, except when a
252        failure occurs earlier in the request pipeline. This method may be
253        called multiple times in the event of retries. The duration between
254        invocation of this hook and `after_signing` is very close to
255        the amount of time spent signing the request.
256
257        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request) is **ALWAYS** available.
258        Other information **WILL NOT** be available. In the event of retries,
259        the `InterceptorContext` will not include changes made in previous
260        attempts (e.g. by request signers or other interceptors).
261
262        **Error Behavior:** If errors are raised by this
263        hook, execution will jump to `modify_before_attempt_completion` with
264        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
265        "
266    );
267
268    interceptor_trait_fn!(
269        read_after_signing,
270        BeforeTransmitInterceptorContextRef,
271        "
272        A hook called after the transport request message is signed.
273
274        **When:** This will **ALWAYS** be called once per attempt, except when a
275        failure occurs earlier in the request pipeline. This method may be
276        called multiple times in the event of retries. The duration between
277        invocation of this hook and `before_signing` is very close to
278        the amount of time spent signing the request.
279
280        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request) is **ALWAYS** available.
281        Other information **WILL NOT** be available. In the event of retries,
282        the `InterceptorContext` will not include changes made in previous
283        attempts (e.g. by request signers or other interceptors).
284
285        **Error Behavior:** If errors are raised by this
286        hook, execution will jump to `modify_before_attempt_completion` with
287        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
288        "
289    );
290
291    interceptor_trait_fn!(
292        mut modify_before_transmit,
293        BeforeTransmitInterceptorContextMut,
294        "
295        A hook called before the transport request message is sent to the
296        service. This method has the ability to modify and return
297        a new transport request message of the same type.
298
299        **When:** This will **ALWAYS** be called once per attempt, except when a
300        failure occurs earlier in the request pipeline. This method may be
301        called multiple times in the event of retries.
302
303        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request)
304        is **ALWAYS** available. The `http::Request` may have been modified by earlier
305        `modify_before_transmit` hooks, and may be modified further by later
306        hooks. Other information **WILL NOT** be available.
307        In the event of retries, the `InterceptorContext` will not include
308        changes made in previous attempts (e.g. by request signers or
309        other interceptors).
310
311        **Error Behavior:** If errors are raised by this
312        hook, execution will jump to `modify_before_attempt_completion` with
313        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
314
315        **Return Constraints:** The transport request message returned by this
316        hook MUST be the same type of request message passed into this hook
317
318        If not, an error will immediately be raised.
319        "
320    );
321
322    interceptor_trait_fn!(
323        read_before_transmit,
324        BeforeTransmitInterceptorContextRef,
325        "
326        A hook called before the transport request message is sent to the
327        service.
328
329        **When:** This will **ALWAYS** be called once per attempt, except when a
330        failure occurs earlier in the request pipeline. This method may be
331        called multiple times in the event of retries. The duration between
332        invocation of this hook and `after_transmit` is very close to
333        the amount of time spent communicating with the service.
334        Depending on the protocol, the duration may not include the
335        time spent reading the response data.
336
337        **Available Information:** The [`InterceptorContext::request`](context::InterceptorContext::request)
338        is **ALWAYS** available. Other information **WILL NOT** be available. In the event of retries,
339        the `InterceptorContext` will not include changes made in previous
340        attempts (e.g. by request signers or other interceptors).
341
342
343        **Error Behavior:** If errors are raised by this
344        hook, execution will jump to `modify_before_attempt_completion` with
345        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
346        "
347    );
348
349    interceptor_trait_fn!(
350        read_after_transmit,
351        BeforeDeserializationInterceptorContextRef,
352        "
353        A hook called after the transport request message is sent to the
354        service and a transport response message is received.
355
356        **When:** This will **ALWAYS** be called once per attempt, except when a
357        failure occurs earlier in the request pipeline. This method may be
358        called multiple times in the event of retries. The duration between
359        invocation of this hook and `before_transmit` is very close to
360        the amount of time spent communicating with the service.
361        Depending on the protocol, the duration may not include the time
362        spent reading the response data.
363
364        **Available Information:** The [`InterceptorContext::response`](context::InterceptorContext::response)
365        is **ALWAYS** available. Other information **WILL NOT** be available. In the event of retries,
366        the `InterceptorContext` will not include changes made in previous
367        attempts (e.g. by request signers or other interceptors).
368
369        **Error Behavior:** If errors are raised by this
370        hook, execution will jump to `modify_before_attempt_completion` with
371        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
372        "
373    );
374
375    interceptor_trait_fn!(
376        mut modify_before_deserialization,
377        BeforeDeserializationInterceptorContextMut,
378        "
379        A hook called before the transport response message is unmarshalled.
380        This method has the ability to modify and return a new transport
381        response message of the same type.
382
383        **When:** This will **ALWAYS** be called once per attempt, except when a
384        failure occurs earlier in the request pipeline. This method may be
385        called multiple times in the event of retries.
386
387        **Available Information:** The [`InterceptorContext::response`](context::InterceptorContext::response)
388        is **ALWAYS** available. The transmit_response may have been modified by earlier
389        `modify_before_deserialization` hooks, and may be modified further by
390        later hooks. Other information **WILL NOT** be available. In the event of
391        retries, the `InterceptorContext` will not include changes made in
392        previous attempts (e.g. by request signers or other interceptors).
393
394        **Error Behavior:** If errors are raised by this
395        hook, execution will jump to `modify_before_attempt_completion` with
396        the raised error as the
397        [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
398
399        **Return Constraints:** The transport response message returned by this
400        hook MUST be the same type of response message passed into
401        this hook. If not, an error will immediately be raised.
402        "
403    );
404
405    interceptor_trait_fn!(
406        read_before_deserialization,
407        BeforeDeserializationInterceptorContextRef,
408        "
409        A hook called before the transport response message is unmarshalled
410
411        **When:** This will **ALWAYS** be called once per attempt, except when a
412        failure occurs earlier in the request pipeline. This method may be
413        called multiple times in the event of retries. The duration between
414        invocation of this hook and `after_deserialization` is very close
415        to the amount of time spent unmarshalling the service response.
416        Depending on the protocol and operation, the duration may include
417        the time spent downloading the response data.
418
419        **Available Information:** The [`InterceptorContext::response`](context::InterceptorContext::response)
420        is **ALWAYS** available. Other information **WILL NOT** be available. In the event of retries,
421        the `InterceptorContext` will not include changes made in previous
422        attempts (e.g. by request signers or other interceptors).
423
424        **Error Behavior:** If errors are raised by this
425        hook, execution will jump to `modify_before_attempt_completion`
426        with the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
427        "
428    );
429
430    interceptor_trait_fn!(
431        read_after_deserialization,
432        AfterDeserializationInterceptorContextRef,
433        "
434        A hook called after the transport response message is unmarshalled.
435
436        **When:** This will **ALWAYS** be called once per attempt, except when a
437        failure occurs earlier in the request pipeline. The duration
438        between invocation of this hook and `before_deserialization` is
439        very close to the amount of time spent unmarshalling the
440        service response. Depending on the protocol and operation,
441        the duration may include the time spent downloading
442        the response data.
443
444        **Available Information:** The [`InterceptorContext::response`](context::InterceptorContext::response)
445        and [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error)
446        are **ALWAYS** available. In the event of retries, the `InterceptorContext` will not include changes made
447        in previous attempts (e.g. by request signers or other interceptors).
448
449        **Error Behavior:** If errors are raised by this
450        hook, execution will jump to `modify_before_attempt_completion` with
451        the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
452        "
453    );
454
455    /// A hook called when an attempt is completed. This method has the
456    /// ability to modify and return a new output message or error
457    /// matching the currently-executing operation.
458    ///
459    /// **When:** This will **ALWAYS** be called once per attempt, except when a
460    /// failure occurs before `before_attempt`. This method may
461    /// be called multiple times in the event of retries.
462    ///
463    /// **Available Information:**
464    /// The [`InterceptorContext::input`](context::InterceptorContext::input),
465    /// [`InterceptorContext::request`](context::InterceptorContext::request),
466    /// [`InterceptorContext::response`](context::InterceptorContext::response), or
467    /// [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error) **MAY** be available.
468    /// If the operation succeeded, the `output` will be available. Otherwise, any of the other
469    /// pieces of information may be available depending on where in the operation lifecycle it failed.
470    /// In the event of retries, the `InterceptorContext` will not include changes made
471    /// in previous attempts (e.g. by request signers or other interceptors).
472    ///
473    /// **Error Behavior:** If errors are raised by this
474    /// hook, execution will jump to `after_attempt` with
475    /// the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
476    ///
477    /// **Return Constraints:** Any output message returned by this
478    /// hook MUST match the operation being invoked. Any error type can be
479    /// returned, replacing the response currently in the context.
480    fn modify_before_attempt_completion(
481        &self,
482        context: &mut FinalizerInterceptorContextMut<'_>,
483        runtime_components: &RuntimeComponents,
484        cfg: &mut ConfigBag,
485    ) -> Result<(), BoxError> {
486        let (_ctx, _rc, _cfg) = (context, runtime_components, cfg);
487        Ok(())
488    }
489
490    /// A hook called when an attempt is completed.
491    ///
492    /// **When:** This will **ALWAYS** be called once per attempt, as long as
493    /// `before_attempt` has been executed.
494    ///
495    /// **Available Information:**
496    /// The [`InterceptorContext::input`](context::InterceptorContext::input),
497    /// [`InterceptorContext::request`](context::InterceptorContext::request),
498    /// [`InterceptorContext::response`](context::InterceptorContext::response), or
499    /// [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error) **MAY** be available.
500    /// If the operation succeeded, the `output` will be available. Otherwise, any of the other
501    /// pieces of information may be available depending on where in the operation lifecycle it failed.
502    /// In the event of retries, the `InterceptorContext` will not include changes made
503    /// in previous attempts (e.g. by request signers or other interceptors).
504    ///
505    /// **Error Behavior:** Errors raised by this hook will be stored
506    /// until all interceptors have had their `after_attempt` invoked.
507    /// If multiple `after_execution` methods raise errors, the latest
508    /// will be used and earlier ones will be logged and dropped. If the
509    /// retry strategy determines that the execution is retryable,
510    /// execution will then jump to `before_attempt`. Otherwise,
511    /// execution will jump to `modify_before_attempt_completion` with the
512    /// raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
513    fn read_after_attempt(
514        &self,
515        context: &FinalizerInterceptorContextRef<'_>,
516        runtime_components: &RuntimeComponents,
517        cfg: &mut ConfigBag,
518    ) -> Result<(), BoxError> {
519        let (_ctx, _rc, _cfg) = (context, runtime_components, cfg);
520        Ok(())
521    }
522
523    /// A hook called when an execution is completed.
524    /// This method has the ability to modify and return a new
525    /// output message or error matching the currently - executing
526    /// operation.
527    ///
528    /// **When:** This will **ALWAYS** be called once per execution.
529    ///
530    /// **Available Information:**
531    /// The [`InterceptorContext::input`](context::InterceptorContext::input),
532    /// [`InterceptorContext::request`](context::InterceptorContext::request),
533    /// [`InterceptorContext::response`](context::InterceptorContext::response), or
534    /// [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error) **MAY** be available.
535    /// If the operation succeeded, the `output` will be available. Otherwise, any of the other
536    /// pieces of information may be available depending on where in the operation lifecycle it failed.
537    /// In the event of retries, the `InterceptorContext` will not include changes made
538    /// in previous attempts (e.g. by request signers or other interceptors).
539    ///
540    /// **Error Behavior:** If errors are raised by this
541    /// hook , execution will jump to `after_attempt` with
542    /// the raised error as the [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error).
543    ///
544    /// **Return Constraints:** Any output message returned by this
545    /// hook MUST match the operation being invoked. Any error type can be
546    /// returned , replacing the response currently in the context.
547    fn modify_before_completion(
548        &self,
549        context: &mut FinalizerInterceptorContextMut<'_>,
550        runtime_components: &RuntimeComponents,
551        cfg: &mut ConfigBag,
552    ) -> Result<(), BoxError> {
553        let (_ctx, _rc, _cfg) = (context, runtime_components, cfg);
554        Ok(())
555    }
556
557    /// A hook called when an execution is completed.
558    ///
559    /// **When:** This will **ALWAYS** be called once per execution. The duration
560    /// between invocation of this hook and `before_execution` is very
561    /// close to the full duration of the execution.
562    ///
563    /// **Available Information:**
564    /// The [`InterceptorContext::input`](context::InterceptorContext::input),
565    /// [`InterceptorContext::request`](context::InterceptorContext::request),
566    /// [`InterceptorContext::response`](context::InterceptorContext::response), or
567    /// [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error) **MAY** be available.
568    /// If the operation succeeded, the `output` will be available. Otherwise, any of the other
569    /// pieces of information may be available depending on where in the operation lifecycle it failed.
570    /// In the event of retries, the `InterceptorContext` will not include changes made
571    /// in previous attempts (e.g. by request signers or other interceptors).
572    ///
573    /// **Error Behavior:** Errors raised by this hook will be stored
574    /// until all interceptors have had their `after_execution` invoked.
575    /// The error will then be treated as the
576    /// [`InterceptorContext::output_or_error`](context::InterceptorContext::output_or_error)
577    /// to the customer. If multiple `after_execution` methods raise errors , the latest will be
578    /// used and earlier ones will be logged and dropped.
579    fn read_after_execution(
580        &self,
581        context: &FinalizerInterceptorContextRef<'_>,
582        runtime_components: &RuntimeComponents,
583        cfg: &mut ConfigBag,
584    ) -> Result<(), BoxError> {
585        let (_ctx, _rc, _cfg) = (context, runtime_components, cfg);
586        Ok(())
587    }
588}
589
590/// Interceptor wrapper that may be shared
591#[derive(Clone)]
592pub struct SharedInterceptor {
593    interceptor: Arc<dyn Intercept>,
594    check_enabled: Arc<dyn Fn(&ConfigBag) -> bool + Send + Sync>,
595}
596
597impl fmt::Debug for SharedInterceptor {
598    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599        f.debug_struct("SharedInterceptor")
600            .field("interceptor", &self.interceptor)
601            .finish()
602    }
603}
604
605impl SharedInterceptor {
606    /// Create a new `SharedInterceptor` from `Interceptor`.
607    pub fn new<T: Intercept + 'static>(interceptor: T) -> Self {
608        Self {
609            interceptor: Arc::new(interceptor),
610            check_enabled: Arc::new(|conf: &ConfigBag| {
611                conf.load::<DisableInterceptor<T>>().is_none()
612            }),
613        }
614    }
615
616    /// Checks if this interceptor is enabled in the given config.
617    pub fn enabled(&self, conf: &ConfigBag) -> bool {
618        (self.check_enabled)(conf)
619    }
620}
621
622impl ValidateConfig for SharedInterceptor {}
623
624impl Intercept for SharedInterceptor {
625    fn name(&self) -> &'static str {
626        self.interceptor.name()
627    }
628
629    fn modify_before_attempt_completion(
630        &self,
631        context: &mut FinalizerInterceptorContextMut<'_>,
632        runtime_components: &RuntimeComponents,
633        cfg: &mut ConfigBag,
634    ) -> Result<(), BoxError> {
635        self.interceptor
636            .modify_before_attempt_completion(context, runtime_components, cfg)
637    }
638
639    fn modify_before_completion(
640        &self,
641        context: &mut FinalizerInterceptorContextMut<'_>,
642        runtime_components: &RuntimeComponents,
643        cfg: &mut ConfigBag,
644    ) -> Result<(), BoxError> {
645        self.interceptor
646            .modify_before_completion(context, runtime_components, cfg)
647    }
648
649    fn modify_before_deserialization(
650        &self,
651        context: &mut BeforeDeserializationInterceptorContextMut<'_>,
652        runtime_components: &RuntimeComponents,
653        cfg: &mut ConfigBag,
654    ) -> Result<(), BoxError> {
655        self.interceptor
656            .modify_before_deserialization(context, runtime_components, cfg)
657    }
658
659    fn modify_before_retry_loop(
660        &self,
661        context: &mut BeforeTransmitInterceptorContextMut<'_>,
662        runtime_components: &RuntimeComponents,
663        cfg: &mut ConfigBag,
664    ) -> Result<(), BoxError> {
665        self.interceptor
666            .modify_before_retry_loop(context, runtime_components, cfg)
667    }
668
669    fn modify_before_serialization(
670        &self,
671        context: &mut BeforeSerializationInterceptorContextMut<'_>,
672        runtime_components: &RuntimeComponents,
673        cfg: &mut ConfigBag,
674    ) -> Result<(), BoxError> {
675        self.interceptor
676            .modify_before_serialization(context, runtime_components, cfg)
677    }
678
679    fn modify_before_signing(
680        &self,
681        context: &mut BeforeTransmitInterceptorContextMut<'_>,
682        runtime_components: &RuntimeComponents,
683        cfg: &mut ConfigBag,
684    ) -> Result<(), BoxError> {
685        self.interceptor
686            .modify_before_signing(context, runtime_components, cfg)
687    }
688
689    fn modify_before_transmit(
690        &self,
691        context: &mut BeforeTransmitInterceptorContextMut<'_>,
692        runtime_components: &RuntimeComponents,
693        cfg: &mut ConfigBag,
694    ) -> Result<(), BoxError> {
695        self.interceptor
696            .modify_before_transmit(context, runtime_components, cfg)
697    }
698
699    fn read_after_attempt(
700        &self,
701        context: &FinalizerInterceptorContextRef<'_>,
702        runtime_components: &RuntimeComponents,
703        cfg: &mut ConfigBag,
704    ) -> Result<(), BoxError> {
705        self.interceptor
706            .read_after_attempt(context, runtime_components, cfg)
707    }
708
709    fn read_after_deserialization(
710        &self,
711        context: &AfterDeserializationInterceptorContextRef<'_>,
712        runtime_components: &RuntimeComponents,
713        cfg: &mut ConfigBag,
714    ) -> Result<(), BoxError> {
715        self.interceptor
716            .read_after_deserialization(context, runtime_components, cfg)
717    }
718
719    fn read_after_execution(
720        &self,
721        context: &FinalizerInterceptorContextRef<'_>,
722        runtime_components: &RuntimeComponents,
723        cfg: &mut ConfigBag,
724    ) -> Result<(), BoxError> {
725        self.interceptor
726            .read_after_execution(context, runtime_components, cfg)
727    }
728
729    fn read_after_serialization(
730        &self,
731        context: &BeforeTransmitInterceptorContextRef<'_>,
732        runtime_components: &RuntimeComponents,
733        cfg: &mut ConfigBag,
734    ) -> Result<(), BoxError> {
735        self.interceptor
736            .read_after_serialization(context, runtime_components, cfg)
737    }
738
739    fn read_after_signing(
740        &self,
741        context: &BeforeTransmitInterceptorContextRef<'_>,
742        runtime_components: &RuntimeComponents,
743        cfg: &mut ConfigBag,
744    ) -> Result<(), BoxError> {
745        self.interceptor
746            .read_after_signing(context, runtime_components, cfg)
747    }
748
749    fn read_after_transmit(
750        &self,
751        context: &BeforeDeserializationInterceptorContextRef<'_>,
752        runtime_components: &RuntimeComponents,
753        cfg: &mut ConfigBag,
754    ) -> Result<(), BoxError> {
755        self.interceptor
756            .read_after_transmit(context, runtime_components, cfg)
757    }
758
759    fn read_before_attempt(
760        &self,
761        context: &BeforeTransmitInterceptorContextRef<'_>,
762        runtime_components: &RuntimeComponents,
763        cfg: &mut ConfigBag,
764    ) -> Result<(), BoxError> {
765        self.interceptor
766            .read_before_attempt(context, runtime_components, cfg)
767    }
768
769    fn read_before_deserialization(
770        &self,
771        context: &BeforeDeserializationInterceptorContextRef<'_>,
772        runtime_components: &RuntimeComponents,
773        cfg: &mut ConfigBag,
774    ) -> Result<(), BoxError> {
775        self.interceptor
776            .read_before_deserialization(context, runtime_components, cfg)
777    }
778
779    fn read_before_execution(
780        &self,
781        context: &BeforeSerializationInterceptorContextRef<'_>,
782        cfg: &mut ConfigBag,
783    ) -> Result<(), BoxError> {
784        self.interceptor.read_before_execution(context, cfg)
785    }
786
787    fn read_before_serialization(
788        &self,
789        context: &BeforeSerializationInterceptorContextRef<'_>,
790        runtime_components: &RuntimeComponents,
791        cfg: &mut ConfigBag,
792    ) -> Result<(), BoxError> {
793        self.interceptor
794            .read_before_serialization(context, runtime_components, cfg)
795    }
796
797    fn read_before_signing(
798        &self,
799        context: &BeforeTransmitInterceptorContextRef<'_>,
800        runtime_components: &RuntimeComponents,
801        cfg: &mut ConfigBag,
802    ) -> Result<(), BoxError> {
803        self.interceptor
804            .read_before_signing(context, runtime_components, cfg)
805    }
806
807    fn read_before_transmit(
808        &self,
809        context: &BeforeTransmitInterceptorContextRef<'_>,
810        runtime_components: &RuntimeComponents,
811        cfg: &mut ConfigBag,
812    ) -> Result<(), BoxError> {
813        self.interceptor
814            .read_before_transmit(context, runtime_components, cfg)
815    }
816}
817
818impl_shared_conversions!(convert SharedInterceptor from Intercept using SharedInterceptor::new);
819
820/// Generalized interceptor disabling interface
821///
822/// RuntimePlugins can disable interceptors by inserting [`DisableInterceptor<T>`](DisableInterceptor) into the config bag
823#[must_use]
824#[derive(Debug)]
825pub struct DisableInterceptor<T> {
826    _t: PhantomData<T>,
827    #[allow(unused)]
828    cause: &'static str,
829}
830
831impl<T> Storable for DisableInterceptor<T>
832where
833    T: fmt::Debug + Send + Sync + 'static,
834{
835    type Storer = StoreReplace<Self>;
836}
837
838/// Disable an interceptor with a given cause
839pub fn disable_interceptor<T: Intercept>(cause: &'static str) -> DisableInterceptor<T> {
840    DisableInterceptor {
841        _t: PhantomData,
842        cause,
843    }
844}