5 5 |
|
6 6 | use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
7 7 | use aws_types::app_name::AppName;
|
8 8 | use aws_types::build_metadata::{OsFamily, BUILD_METADATA};
|
9 9 | use aws_types::os_shim_internal::Env;
|
10 10 | use std::borrow::Cow;
|
11 11 | use std::error::Error;
|
12 12 | use std::fmt;
|
13 13 |
|
14 14 | mod interceptor;
|
15 - |
|
16 15 | pub use interceptor::UserAgentInterceptor;
|
17 16 |
|
18 17 | /// AWS User Agent
|
19 18 | ///
|
20 19 | /// Ths struct should be inserted into the [`ConfigBag`](aws_smithy_types::config_bag::ConfigBag)
|
21 20 | /// during operation construction. The `UserAgentInterceptor` reads `AwsUserAgent`
|
22 21 | /// from the config bag and sets the `User-Agent` and `x-amz-user-agent` headers.
|
23 22 | #[derive(Clone, Debug)]
|
24 23 | pub struct AwsUserAgent {
|
25 24 | sdk_metadata: SdkMetadata,
|
26 25 | api_metadata: ApiMetadata,
|
27 26 | os_metadata: OsMetadata,
|
28 27 | language_metadata: LanguageMetadata,
|
29 28 | exec_env_metadata: Option<ExecEnvMetadata>,
|
30 29 | feature_metadata: Vec<FeatureMetadata>,
|
31 30 | config_metadata: Vec<ConfigMetadata>,
|
32 31 | framework_metadata: Vec<FrameworkMetadata>,
|
33 32 | app_name: Option<AppName>,
|
34 33 | build_env_additional_metadata: Option<AdditionalMetadata>,
|
35 - | additional_metadata: Vec<AdditionalMetadata>,
|
36 34 | }
|
37 35 |
|
38 36 | impl AwsUserAgent {
|
39 37 | /// Load a User Agent configuration from the environment
|
40 38 | ///
|
41 39 | /// This utilizes [`BUILD_METADATA`](const@aws_types::build_metadata::BUILD_METADATA) from `aws_types`
|
42 40 | /// to capture the Rust version & target platform. `ApiMetadata` provides
|
43 41 | /// the version & name of the specific service.
|
44 42 | pub fn new_from_environment(env: Env, api_metadata: ApiMetadata) -> Self {
|
45 43 | let build_metadata = &BUILD_METADATA;
|
46 44 | let sdk_metadata = SdkMetadata {
|
47 45 | name: "rust",
|
48 46 | version: build_metadata.core_pkg_version,
|
49 47 | };
|
50 48 | let os_metadata = OsMetadata {
|
51 49 | os_family: &build_metadata.os_family,
|
52 50 | version: None,
|
53 51 | };
|
54 52 | let exec_env_metadata = env
|
55 53 | .get("AWS_EXECUTION_ENV")
|
56 54 | .ok()
|
57 55 | .map(|name| ExecEnvMetadata { name });
|
58 56 |
|
59 57 | // Retrieve additional metadata at compile-time from the AWS_SDK_RUST_BUILD_UA_METADATA env var
|
60 58 | let build_env_additional_metadata = option_env!("AWS_SDK_RUST_BUILD_UA_METADATA")
|
61 59 | .and_then(|value| AdditionalMetadata::new(value).ok());
|
62 60 |
|
63 61 | AwsUserAgent {
|
64 62 | sdk_metadata,
|
65 63 | api_metadata,
|
66 64 | os_metadata,
|
67 65 | language_metadata: LanguageMetadata {
|
68 66 | lang: "rust",
|
69 67 | version: BUILD_METADATA.rust_version,
|
70 68 | extras: Default::default(),
|
71 69 | },
|
72 70 | exec_env_metadata,
|
73 71 | feature_metadata: Default::default(),
|
74 72 | config_metadata: Default::default(),
|
75 73 | framework_metadata: Default::default(),
|
76 74 | app_name: Default::default(),
|
77 75 | build_env_additional_metadata,
|
78 - | additional_metadata: Default::default(),
|
79 76 | }
|
80 77 | }
|
81 78 |
|
82 79 | /// For test purposes, construct an environment-independent User Agent
|
83 80 | ///
|
84 81 | /// Without this, running CI on a different platform would produce different user agent strings
|
85 82 | pub fn for_tests() -> Self {
|
86 83 | Self {
|
87 84 | sdk_metadata: SdkMetadata {
|
88 85 | name: "rust",
|
89 86 | version: "0.123.test",
|
90 87 | },
|
91 88 | api_metadata: ApiMetadata {
|
92 89 | service_id: "test-service".into(),
|
93 90 | version: "0.123",
|
94 91 | },
|
95 92 | os_metadata: OsMetadata {
|
96 93 | os_family: &OsFamily::Windows,
|
97 94 | version: Some("XPSP3".to_string()),
|
98 95 | },
|
99 96 | language_metadata: LanguageMetadata {
|
100 97 | lang: "rust",
|
101 98 | version: "1.50.0",
|
102 99 | extras: Default::default(),
|
103 100 | },
|
104 101 | exec_env_metadata: None,
|
105 102 | feature_metadata: Vec::new(),
|
106 103 | config_metadata: Vec::new(),
|
107 104 | framework_metadata: Vec::new(),
|
108 105 | app_name: None,
|
109 106 | build_env_additional_metadata: None,
|
110 - | additional_metadata: Vec::new(),
|
111 107 | }
|
112 108 | }
|
113 109 |
|
114 110 | #[doc(hidden)]
|
115 111 | /// Adds feature metadata to the user agent.
|
116 112 | pub fn with_feature_metadata(mut self, metadata: FeatureMetadata) -> Self {
|
117 113 | self.feature_metadata.push(metadata);
|
118 114 | self
|
119 115 | }
|
120 116 |
|
121 117 | #[doc(hidden)]
|
122 118 | /// Adds feature metadata to the user agent.
|
123 119 | pub fn add_feature_metadata(&mut self, metadata: FeatureMetadata) -> &mut Self {
|
124 120 | self.feature_metadata.push(metadata);
|
125 121 | self
|
126 122 | }
|
127 123 |
|
128 124 | #[doc(hidden)]
|
129 125 | /// Adds config metadata to the user agent.
|
130 126 | pub fn with_config_metadata(mut self, metadata: ConfigMetadata) -> Self {
|
131 127 | self.config_metadata.push(metadata);
|
132 128 | self
|
133 129 | }
|
134 130 |
|
135 131 | #[doc(hidden)]
|
136 132 | /// Adds config metadata to the user agent.
|
137 133 | pub fn add_config_metadata(&mut self, metadata: ConfigMetadata) -> &mut Self {
|
138 134 | self.config_metadata.push(metadata);
|
139 135 | self
|
140 136 | }
|
141 137 |
|
142 138 | #[doc(hidden)]
|
143 139 | /// Adds framework metadata to the user agent.
|
144 140 | pub fn with_framework_metadata(mut self, metadata: FrameworkMetadata) -> Self {
|
145 141 | self.framework_metadata.push(metadata);
|
146 142 | self
|
147 143 | }
|
148 144 |
|
149 145 | #[doc(hidden)]
|
150 146 | /// Adds framework metadata to the user agent.
|
151 147 | pub fn add_framework_metadata(&mut self, metadata: FrameworkMetadata) -> &mut Self {
|
152 148 | self.framework_metadata.push(metadata);
|
153 149 | self
|
154 150 | }
|
155 151 |
|
156 - | /// Adds additional metadata to the user agent.
|
157 - | pub fn with_additional_metadata(mut self, metadata: AdditionalMetadata) -> Self {
|
158 - | self.additional_metadata.push(metadata);
|
159 - | self
|
160 - | }
|
161 - |
|
162 - | /// Adds additional metadata to the user agent.
|
163 - | pub fn add_additional_metadata(&mut self, metadata: AdditionalMetadata) -> &mut Self {
|
164 - | self.additional_metadata.push(metadata);
|
165 - | self
|
166 - | }
|
167 - |
|
168 152 | /// Sets the app name for the user agent.
|
169 153 | pub fn with_app_name(mut self, app_name: AppName) -> Self {
|
170 154 | self.app_name = Some(app_name);
|
171 155 | self
|
172 156 | }
|
173 157 |
|
174 158 | /// Sets the app name for the user agent.
|
175 159 | pub fn set_app_name(&mut self, app_name: AppName) -> &mut Self {
|
176 160 | self.app_name = Some(app_name);
|
177 161 | self
|
178 162 | }
|
179 163 |
|
180 164 | /// Generate a new-style user agent style header
|
181 165 | ///
|
182 166 | /// This header should be set at `x-amz-user-agent`
|
183 167 | pub fn aws_ua_header(&self) -> String {
|
184 168 | /*
|
185 169 | ABNF for the user agent (see the bottom of the file for complete ABNF):
|
186 170 | ua-string = sdk-metadata RWS
|
187 171 | [api-metadata RWS]
|
188 172 | os-metadata RWS
|
189 173 | language-metadata RWS
|
190 174 | [env-metadata RWS]
|
191 175 | *(feat-metadata RWS)
|
192 176 | *(config-metadata RWS)
|
193 177 | *(framework-metadata RWS)
|
194 178 | [appId]
|
195 179 | */
|
196 180 | let mut ua_value = String::new();
|
197 181 | use std::fmt::Write;
|
198 182 | // unwrap calls should never fail because string formatting will always succeed.
|
199 183 | write!(ua_value, "{} ", &self.sdk_metadata).unwrap();
|
200 184 | write!(ua_value, "{} ", &self.api_metadata).unwrap();
|
201 185 | write!(ua_value, "{} ", &self.os_metadata).unwrap();
|
202 186 | write!(ua_value, "{} ", &self.language_metadata).unwrap();
|
203 187 | if let Some(ref env_meta) = self.exec_env_metadata {
|
204 188 | write!(ua_value, "{} ", env_meta).unwrap();
|
205 189 | }
|
206 190 | for feature in &self.feature_metadata {
|
207 191 | write!(ua_value, "{} ", feature).unwrap();
|
208 192 | }
|
209 193 | for config in &self.config_metadata {
|
210 194 | write!(ua_value, "{} ", config).unwrap();
|
211 195 | }
|
212 196 | for framework in &self.framework_metadata {
|
213 197 | write!(ua_value, "{} ", framework).unwrap();
|
214 198 | }
|
215 - | for additional_metadata in &self.additional_metadata {
|
216 - | write!(ua_value, "{} ", additional_metadata).unwrap();
|
217 - | }
|
218 199 | if let Some(app_name) = &self.app_name {
|
219 200 | write!(ua_value, "app/{}", app_name).unwrap();
|
220 201 | }
|
221 202 | if let Some(additional_metadata) = &self.build_env_additional_metadata {
|
222 203 | write!(ua_value, "{}", additional_metadata).unwrap();
|
223 204 | }
|
224 205 | if ua_value.ends_with(' ') {
|
225 206 | ua_value.truncate(ua_value.len() - 1);
|
226 207 | }
|
227 208 | ua_value
|