aws_smithy_runtime_api/http/
non_utf8.rs1use aws_smithy_types::config_bag::{Storable, StoreReplace};
9
10#[cfg_attr(
25 feature = "client",
26 doc = r#"
27```no_run
28# use aws_smithy_runtime_api::box_error::BoxError;
29# use aws_smithy_runtime_api::client::interceptors::context::{
30# BeforeDeserializationInterceptorContextRef, BeforeSerializationInterceptorContextRef,
31# };
32# use aws_smithy_runtime_api::client::interceptors::Intercept;
33# use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
34# use aws_smithy_runtime_api::http::NonUtf8HeaderHandling;
35# use aws_smithy_types::config_bag::ConfigBag;
36# use std::sync::{Arc, Mutex};
37#[derive(Clone, Debug, Default)]
38struct SkipNonUtf8Headers {
39 seen: Arc<Mutex<Vec<(String, Vec<u8>)>>>,
40}
41
42impl Intercept for SkipNonUtf8Headers {
43 fn name(&self) -> &'static str {
44 "SkipNonUtf8Headers"
45 }
46
47 fn read_before_execution(
48 &self,
49 _context: &BeforeSerializationInterceptorContextRef<'_>,
50 cfg: &mut ConfigBag,
51 ) -> Result<(), BoxError> {
52 cfg.interceptor_state()
53 .store_put(NonUtf8HeaderHandling::Skip);
54 Ok(())
55 }
56
57 fn read_before_deserialization(
58 &self,
59 context: &BeforeDeserializationInterceptorContextRef<'_>,
60 _runtime_components: &RuntimeComponents,
61 _cfg: &mut ConfigBag,
62 ) -> Result<(), BoxError> {
63 // Runs once per attempt, so overwrite rather than append.
64 *self.seen.lock().unwrap() = context
65 .response()
66 .headers()
67 .iter_bytes()
68 .filter(|(_, value)| std::str::from_utf8(value).is_err())
69 .map(|(name, value)| (name.to_owned(), value.to_vec()))
70 .collect();
71 Ok(())
72 }
73}
74```
75"#
76)]
77#[derive(Debug, Clone, PartialEq, Eq, Default)]
81#[non_exhaustive]
82pub enum NonUtf8HeaderHandling {
83 #[default]
87 Reject,
88
89 Skip,
97}
98
99impl Storable for NonUtf8HeaderHandling {
100 type Storer = StoreReplace<Self>;
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use aws_smithy_types::config_bag::{CloneableLayer, ConfigBag};
107
108 #[test]
109 fn rejects_by_default() {
110 assert_eq!(NonUtf8HeaderHandling::Reject, Default::default());
111 let bag = ConfigBag::base();
113 assert_eq!(None, bag.load::<NonUtf8HeaderHandling>());
114 }
115
116 #[test]
117 fn round_trips_through_the_config_bag() {
118 let mut layer = CloneableLayer::new("test");
119 layer.store_put(NonUtf8HeaderHandling::Skip);
120 let bag = ConfigBag::of_layers(vec![layer.into()]);
121 assert_eq!(
122 Some(&NonUtf8HeaderHandling::Skip),
123 bag.load::<NonUtf8HeaderHandling>()
124 );
125 }
126}