25 25 | use aws_smithy_runtime_api::client::runtime_plugin::{
|
26 26 | Order, SharedRuntimePlugin, StaticRuntimePlugin,
|
27 27 | };
|
28 28 | use aws_smithy_runtime_api::client::stalled_stream_protection::StalledStreamProtectionConfig;
|
29 29 | use aws_smithy_runtime_api::shared::IntoShared;
|
30 30 | use aws_smithy_types::config_bag::{ConfigBag, FrozenLayer, Layer};
|
31 31 | use aws_smithy_types::retry::RetryConfig;
|
32 32 | use aws_smithy_types::timeout::TimeoutConfig;
|
33 33 | use std::borrow::Cow;
|
34 34 | use std::time::Duration;
|
35 35 |
|
36 36 | fn default_plugin<CompFn>(name: &'static str, components_fn: CompFn) -> StaticRuntimePlugin
|
37 37 | where
|
38 38 | CompFn: FnOnce(RuntimeComponentsBuilder) -> RuntimeComponentsBuilder,
|
39 39 | {
|
40 40 | StaticRuntimePlugin::new()
|
41 41 | .with_order(Order::Defaults)
|
42 42 | .with_runtime_components((components_fn)(RuntimeComponentsBuilder::new(name)))
|
43 43 | }
|
44 44 |
|
45 45 | fn layer<LayerFn>(name: &'static str, layer_fn: LayerFn) -> FrozenLayer
|
46 46 | where
|
47 47 | LayerFn: FnOnce(&mut Layer),
|
48 48 | {
|
49 49 | let mut layer = Layer::new(name);
|
50 50 | (layer_fn)(&mut layer);
|
51 51 | layer.freeze()
|
52 52 | }
|
53 53 |
|
54 54 | /// Runtime plugin that provides a default connector.
|
55 + | #[deprecated(
|
56 + | since = "1.8.0",
|
57 + | note = "This function wasn't intended to be public, and didn't take the behavior major version as an argument, so it couldn't be evolved over time."
|
58 + | )]
|
55 59 | pub fn default_http_client_plugin() -> Option<SharedRuntimePlugin> {
|
56 - | let _default: Option<SharedHttpClient> = None;
|
57 60 | #[allow(deprecated)]
|
58 - | #[cfg(feature = "connector-hyper-0-14-x")]
|
59 - | let _default = crate::client::http::hyper_014::default_client();
|
61 + | default_http_client_plugin_v2(BehaviorVersion::v2024_03_28())
|
62 + | }
|
63 + |
|
64 + | /// Runtime plugin that provides a default HTTPS connector.
|
65 + | pub fn default_http_client_plugin_v2(
|
66 + | behavior_version: BehaviorVersion,
|
67 + | ) -> Option<SharedRuntimePlugin> {
|
68 + | let mut _default: Option<SharedHttpClient> = None;
|
60 69 |
|
61 - | // takes precedence over legacy connector if enabled
|
62 - | #[cfg(feature = "default-http-connector")]
|
63 - | let _default = aws_smithy_http_client::default_client();
|
70 + | if behavior_version.is_at_least(BehaviorVersion::v2025_01_17()) {
|
71 + | // the latest https stack takes precedence if the config flag
|
72 + | // is enabled otherwise try to fall back to the legacy connector
|
73 + | // if that feature flag is available.
|
74 + | #[cfg(all(
|
75 + | feature = "connector-hyper-0-14-x",
|
76 + | not(feature = "default-https-client")
|
77 + | ))]
|
78 + | #[allow(deprecated)]
|
79 + | {
|
80 + | _default = crate::client::http::hyper_014::default_client();
|
81 + | }
|
82 + |
|
83 + | // takes precedence over legacy connector if enabled
|
84 + | #[cfg(feature = "default-https-client")]
|
85 + | {
|
86 + | _default = aws_smithy_http_client::default_client();
|
87 + | }
|
88 + | } else {
|
89 + | // fallback to legacy hyper client for given behavior version
|
90 + | #[cfg(feature = "connector-hyper-0-14-x")]
|
91 + | #[allow(deprecated)]
|
92 + | {
|
93 + | _default = crate::client::http::hyper_014::default_client();
|
94 + | }
|
95 + | }
|
64 96 |
|
65 97 | _default.map(|default| {
|
66 98 | default_plugin("default_http_client_plugin", |components| {
|
67 99 | components.with_http_client(Some(default))
|
68 100 | })
|
69 101 | .into_shared()
|
70 102 | })
|
71 103 | }
|
72 104 |
|
73 105 | /// Runtime plugin that provides a default async sleep implementation.
|
74 106 | pub fn default_sleep_impl_plugin() -> Option<SharedRuntimePlugin> {
|
75 107 | default_async_sleep().map(|default| {
|
76 108 | default_plugin("default_sleep_impl_plugin", |components| {
|
77 109 | components.with_sleep_impl(Some(default))
|
78 110 | })
|
79 111 | .into_shared()
|
80 112 | })
|
81 113 | }
|
82 114 |
|
83 115 | /// Runtime plugin that provides a default time source.
|
84 116 | pub fn default_time_source_plugin() -> Option<SharedRuntimePlugin> {
|
85 117 | Some(
|
86 118 | default_plugin("default_time_source_plugin", |components| {
|
87 119 | components.with_time_source(Some(SystemTimeSource::new()))
|
88 120 | })
|
89 121 | .into_shared(),
|
90 122 | )
|
91 123 | }
|
92 124 |
|
93 125 | /// Runtime plugin that sets the default retry strategy, config (disabled), and partition.
|
176 208 | }
|
177 209 |
|
178 210 | /// Runtime plugin that sets the default stalled stream protection config.
|
179 211 | ///
|
180 212 | /// By default, when throughput falls below 1/Bs for more than 5 seconds, the
|
181 213 | /// stream is cancelled.
|
182 214 | #[deprecated(
|
183 215 | since = "1.2.0",
|
184 216 | note = "This function wasn't intended to be public, and didn't take the behavior major version as an argument, so it couldn't be evolved over time."
|
185 217 | )]
|
186 218 | pub fn default_stalled_stream_protection_config_plugin() -> Option<SharedRuntimePlugin> {
|
187 219 | #[allow(deprecated)]
|
188 220 | default_stalled_stream_protection_config_plugin_v2(BehaviorVersion::v2023_11_09())
|
189 221 | }
|
190 222 | fn default_stalled_stream_protection_config_plugin_v2(
|
191 223 | behavior_version: BehaviorVersion,
|
192 224 | ) -> Option<SharedRuntimePlugin> {
|
193 225 | Some(
|
194 226 | default_plugin(
|
195 227 | "default_stalled_stream_protection_config_plugin",
|
196 228 | |components| {
|
197 229 | components.with_config_validator(SharedConfigValidator::base_client_config_fn(
|
198 230 | validate_stalled_stream_protection_config,
|
199 231 | ))
|
200 232 | },
|
201 233 | )
|
202 234 | .with_config(layer("default_stalled_stream_protection_config", |layer| {
|
203 235 | let mut config =
|
204 236 | StalledStreamProtectionConfig::enabled().grace_period(Duration::from_secs(5));
|
205 237 | // Before v2024_03_28, upload streams did not have stalled stream protection by default
|
238 + | #[allow(deprecated)]
|
206 239 | if !behavior_version.is_at_least(BehaviorVersion::v2024_03_28()) {
|
207 240 | config = config.upload_enabled(false);
|
208 241 | }
|
209 242 | layer.store_put(config.build());
|
210 243 | }))
|
211 244 | .into_shared(),
|
212 245 | )
|
213 246 | }
|
214 247 |
|
215 248 | fn enforce_content_length_runtime_plugin() -> Option<SharedRuntimePlugin> {
|
216 249 | Some(EnforceContentLengthRuntimePlugin::new().into_shared())
|
217 250 | }
|
218 251 |
|
219 252 | fn validate_stalled_stream_protection_config(
|
220 253 | components: &RuntimeComponentsBuilder,
|
221 254 | cfg: &ConfigBag,
|
222 255 | ) -> Result<(), BoxError> {
|
223 256 | if let Some(stalled_stream_protection_config) = cfg.load::<StalledStreamProtectionConfig>() {
|
224 257 | if stalled_stream_protection_config.is_enabled() {
|
225 258 | if components.sleep_impl().is_none() {
|
226 259 | return Err(
|
227 260 | "An async sleep implementation is required for stalled stream protection to work. \
|
228 261 | Please provide a `sleep_impl` on the config, or disable stalled stream protection.".into());
|
229 262 | }
|
230 263 |
|
231 264 | if components.time_source().is_none() {
|
232 265 | return Err(
|
233 266 | "A time source is required for stalled stream protection to work.\
|
234 267 | Please provide a `time_source` on the config, or disable stalled stream protection.".into());
|
235 268 | }
|
255 288 | }
|
256 289 |
|
257 290 | impl DefaultPluginParams {
|
258 291 | /// Creates a new [`DefaultPluginParams`].
|
259 292 | pub fn new() -> Self {
|
260 293 | Default::default()
|
261 294 | }
|
262 295 |
|
263 296 | /// Sets the retry partition name.
|
264 297 | pub fn with_retry_partition_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
265 298 | self.retry_partition_name = Some(name.into());
|
266 299 | self
|
267 300 | }
|
268 301 |
|
269 302 | /// Sets the behavior major version.
|
270 303 | pub fn with_behavior_version(mut self, version: BehaviorVersion) -> Self {
|
271 304 | self.behavior_version = Some(version);
|
272 305 | self
|
273 306 | }
|
274 307 | }
|
275 308 |
|
276 309 | /// All default plugins.
|
277 310 | pub fn default_plugins(
|
278 311 | params: DefaultPluginParams,
|
279 312 | ) -> impl IntoIterator<Item = SharedRuntimePlugin> {
|
280 313 | let behavior_version = params
|
281 314 | .behavior_version
|
282 315 | .unwrap_or_else(BehaviorVersion::latest);
|
283 316 |
|
284 317 | [
|
285 - | default_http_client_plugin(),
|
318 + | default_http_client_plugin_v2(behavior_version),
|
286 319 | default_identity_cache_plugin(),
|
287 320 | default_retry_config_plugin(
|
288 321 | params
|
289 322 | .retry_partition_name
|
290 323 | .expect("retry_partition_name is required"),
|
291 324 | ),
|
292 325 | default_sleep_impl_plugin(),
|
293 326 | default_time_source_plugin(),
|
294 327 | default_timeout_config_plugin(),
|
295 328 | enforce_content_length_runtime_plugin(),
|
296 329 | default_stalled_stream_protection_config_plugin_v2(behavior_version),
|
297 330 | ]
|
298 331 | .into_iter()
|
299 332 | .flatten()
|
300 333 | .collect::<Vec<SharedRuntimePlugin>>()
|
301 334 | }
|
302 335 |
|
303 336 | #[cfg(test)]
|
304 337 | mod tests {
|
305 338 | use super::*;
|
306 339 | use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugins;
|
307 340 |
|
308 341 | fn test_plugin_params(version: BehaviorVersion) -> DefaultPluginParams {
|
309 342 | DefaultPluginParams::new()
|
310 343 | .with_behavior_version(version)
|
311 344 | .with_retry_partition_name("dontcare")
|
312 345 | }
|
313 346 | fn config_for(plugins: impl IntoIterator<Item = SharedRuntimePlugin>) -> ConfigBag {
|
314 347 | let mut config = ConfigBag::base();
|
315 348 | let plugins = RuntimePlugins::new().with_client_plugins(plugins);
|