/
ClientConfig.cs
1243 lines (1141 loc) · 50.6 KB
/
ClientConfig.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Threading;
using Amazon.Runtime.Internal.Auth;
using Amazon.Util;
using System.Globalization;
using Amazon.Internal;
using Amazon.Runtime.Endpoints;
using Amazon.Runtime.Internal;
using Amazon.Runtime.Internal.Util;
using System.ComponentModel.Design;
using Amazon.Runtime.CredentialManagement;
using Amazon.Runtime.Internal.Settings;
#if NETSTANDARD
using System.Runtime.InteropServices;
#endif
namespace Amazon.Runtime
{
/// <summary>
/// This class is the base class of all the configurations settings to connect
/// to a service.
/// </summary>
public abstract partial class ClientConfig : IClientConfig
{
// Represents infinite timeout. http://msdn.microsoft.com/en-us/library/system.threading.timeout.infinite.aspx
internal static readonly TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(-1);
/// <summary>
/// Represents upper limit value for <see cref="RequestMinCompressionSizeBytes"/>
/// </summary>
internal const long UpperLimitCompressionSizeBytes = 10485760;
// Represents max timeout.
public static readonly TimeSpan MaxTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
private IDefaultConfigurationProvider _defaultConfigurationProvider;
private string serviceId = null;
private DefaultConfigurationMode? defaultConfigurationMode;
private RegionEndpoint regionEndpoint = null;
private bool probeForRegionEndpoint = true;
private bool throttleRetries = true;
private bool useHttp = false;
private bool useAlternateUserAgentHeader = AWSConfigs.UseAlternateUserAgentHeader;
private string serviceURL = null;
private string authRegion = null;
private string authServiceName = null;
private string signatureVersion = "4";
private string clientAppId = null;
private SigningAlgorithm signatureMethod = SigningAlgorithm.HmacSHA256;
private bool readEntireResponse = false;
private bool logResponse = false;
private int bufferSize = AWSSDKUtils.DefaultBufferSize;
private long progressUpdateInterval = AWSSDKUtils.DefaultProgressUpdateInterval;
private bool resignRetries = false;
private ICredentials proxyCredentials;
private bool logMetrics = AWSConfigs.LoggingConfig.LogMetrics;
private bool disableLogging = false;
private TimeSpan? timeout = null;
private bool allowAutoRedirect = true;
private bool? useDualstackEndpoint;
private bool? useFIPSEndpoint;
private bool? disableRequestCompression;
private long? requestMinCompressionSizeBytes;
private TimeSpan? readWriteTimeout = null;
private bool disableHostPrefixInjection = false;
private bool? endpointDiscoveryEnabled = null;
private bool? ignoreConfiguredEndpointUrls;
private int endpointDiscoveryCacheLimit = 1000;
private RequestRetryMode? retryMode = null;
private int? maxRetries = null;
private const int MaxRetriesDefault = 2;
private const int MaxRetriesLegacyDefault = 4;
private const long DefaultMinCompressionSizeBytes = 10240;
private bool didProcessServiceURL = false;
private IAWSTokenProvider _awsTokenProvider = new DefaultAWSTokenProviderChain();
private CredentialProfileStoreChain credentialProfileStoreChain;
#if BCL
private readonly TcpKeepAlive tcpKeepAlive = new TcpKeepAlive();
#endif
/// <summary>
/// Specifies the profile to be used. When this is set on the ClientConfig and that config is passed to
/// the service client constructor the sdk will try to find the credentials associated with the Profile.Name property
/// If set, this will override AWS_PROFILE and AWSConfigs.ProfileName.
/// </summary>
public Profile Profile { get; set; }
private CredentialProfileStoreChain CredentialProfileStoreChain
{
get
{
if (credentialProfileStoreChain == null)
{
if(Profile != null)
{
credentialProfileStoreChain = new CredentialProfileStoreChain(Profile.Location);
}
else
{
credentialProfileStoreChain = new CredentialProfileStoreChain();
}
}
return credentialProfileStoreChain;
}
set
{
credentialProfileStoreChain = value;
}
}
#if BCL
private static WebProxy GetWebProxyWithCredentials(string value)
#else
private static Amazon.Runtime.Internal.Util.WebProxy GetWebProxyWithCredentials(string value)
#endif
{
if (!string.IsNullOrEmpty(value))
{
var asUri = new Uri(value);
#if BCL
var parsedProxy = new WebProxy(asUri);
#else
var parsedProxy = new Amazon.Runtime.Internal.Util.WebProxy(asUri);
#endif
if (!string.IsNullOrEmpty(asUri.UserInfo)) {
var userAndPass = asUri.UserInfo.Split(':');
parsedProxy.Credentials = new NetworkCredential(
userAndPass[0],
userAndPass.Length > 1 ? userAndPass[1] : string.Empty
);
}
return parsedProxy;
}
return null;
}
/// <inheritdoc />
public IAWSTokenProvider AWSTokenProvider
{
get { return this._awsTokenProvider; }
set { this._awsTokenProvider = value; }
}
/// <summary>
/// Gets Service Version
/// </summary>
public abstract string ServiceVersion
{
get;
}
/// <summary>
/// Gets and sets of the signatureMethod property.
/// </summary>
public SigningAlgorithm SignatureMethod
{
get { return this.signatureMethod; }
set { this.signatureMethod = value; }
}
/// <summary>
/// Gets and sets of the SignatureVersion property.
///
/// Note: This property exists for backward compatibility but is no longer
/// used by any service other than S3.
/// </summary>
public string SignatureVersion
{
get { return this.signatureVersion; }
set { this.signatureVersion = value; }
}
/// <summary>
/// Gets and sets of the UserAgent property.
/// </summary>
public abstract string UserAgent { get; }
/// <summary>
/// When set to true, the service client will use the x-amz-user-agent
/// header instead of the User-Agent header to report version and
/// environment information to the AWS service.
///
/// Note: This is especially useful when using a platform like WebAssembly
/// which doesn't allow to specify the User-Agent header.
/// </summary>
public bool UseAlternateUserAgentHeader
{
get { return this.useAlternateUserAgentHeader; }
set { this.useAlternateUserAgentHeader = value; }
}
/// <summary>
/// <para>
/// Gets and sets the RegionEndpoint property. The region constant that
/// determines the endpoint to use.
///
/// Setting this property to null will force the SDK to recalculate the
/// RegionEndpoint value based on App/WebConfig, environment variables,
/// profile, etc.
/// </para>
/// <para>
/// RegionEndpoint and ServiceURL are mutually exclusive properties.
/// Whichever property is set last will cause the other to automatically
/// be reset to null.
/// </para>
/// </summary>
public RegionEndpoint RegionEndpoint
{
get
{
if (probeForRegionEndpoint)
{
RegionEndpoint = GetDefaultRegionEndpoint();
this.probeForRegionEndpoint = false;
}
return this.regionEndpoint;
}
set
{
this.defaultConfigurationBackingField = null;
this.serviceURL = null;
this.regionEndpoint = value;
this.probeForRegionEndpoint = this.regionEndpoint == null;
// legacy support for initial pseudo regions - convert to base Region
// and set FIPSEndpoint to true
if (!string.IsNullOrEmpty(value?.SystemName) &&
(value.SystemName.Contains("fips-") || value.SystemName.Contains("-fips")))
{
Logger.GetLogger(GetType()).InfoFormat($"FIPS Pseudo Region support is deprecated. Will attempt to convert {value.SystemName}.");
this.UseFIPSEndpoint = true;
this.regionEndpoint =
RegionEndpoint.GetBySystemName(
value.SystemName.Replace("fips-", "").Replace("-fips", ""));
#pragma warning disable CS0612,CS0618
this.RegionEndpoint.OriginalSystemName = value.SystemName;
#pragma warning restore CS0612,CS0618
}
}
}
/// <summary>
/// The constant used to lookup in the region hash the endpoint.
/// </summary>
public abstract string RegionEndpointServiceName
{
get;
}
/// <summary>
/// <para>
/// Gets and sets of the ServiceURL property.
/// This is an optional property; change it
/// only if you want to try a different service
/// endpoint.
/// </para>
/// <para>
/// RegionEndpoint and ServiceURL are mutually exclusive properties.
/// Whichever property is set last will cause the other to automatically
/// be reset to null.
/// </para>
/// </summary>
public string ServiceURL
{
get
{
if (!didProcessServiceURL && this.serviceURL == null && IgnoreConfiguredEndpointUrls == false && ServiceId != null)
{
string serviceSpecificTransformedEnvironmentVariable = TransformServiceId.TransformServiceIdToEnvVariable(ServiceId);
string transformedConfigServiceId = TransformServiceId.TransformServiceIdToConfigVariable(ServiceId);
if (Environment.GetEnvironmentVariable(serviceSpecificTransformedEnvironmentVariable) != null)
{
Logger.GetLogger(GetType()).InfoFormat($"ServiceURL configured from service specific environment variable: {serviceSpecificTransformedEnvironmentVariable}.");
this.ServiceURL = Environment.GetEnvironmentVariable(serviceSpecificTransformedEnvironmentVariable);
}
else if (Environment.GetEnvironmentVariable(EnvironmentVariables.GLOBAL_ENDPOINT_ENVIRONMENT_VARIABLE) != null)
{
this.ServiceURL = Environment.GetEnvironmentVariable(EnvironmentVariables.GLOBAL_ENDPOINT_ENVIRONMENT_VARIABLE);
Logger.GetLogger(GetType()).InfoFormat($"ServiceURL configured from global environment variable: {EnvironmentVariables.GLOBAL_ENDPOINT_ENVIRONMENT_VARIABLE}.");
}
else
{
Dictionary<string, string> innerDictionary;
string endpointUrlValue;
CredentialProfile profile;
if (Profile != null)
{
CredentialProfileStoreChain.TryGetProfile(Profile.Name, out profile);
}
else
{
CredentialProfileStoreChain.TryGetProfile(FallbackCredentialsFactory.GetProfileName(), out profile);
}
if(profile != null)
{
if (profile.NestedProperties.TryGetValue(transformedConfigServiceId, out innerDictionary))
{
if (innerDictionary.TryGetValue(SettingsConstants.EndpointUrl, out endpointUrlValue))
{
Logger.GetLogger(GetType()).InfoFormat($"ServiceURL configured from service specific endpoint url in " +
$"profile {profile.Name} from key {transformedConfigServiceId}.");
this.ServiceURL = endpointUrlValue;
}
}
else if (!String.IsNullOrEmpty(profile.EndpointUrl))
{
Logger.GetLogger(GetType()).InfoFormat($"ServiceURL configured from global endpoint url" +
$"in profile {profile.Name} from key {SettingsConstants.EndpointUrl}.");
this.ServiceURL = profile.EndpointUrl;
}
}
}
didProcessServiceURL = true;
}
return this.serviceURL;
}
set
{
this.regionEndpoint = null;
this.probeForRegionEndpoint = false;
if(!string.IsNullOrEmpty(value))
{
// If the URL passed in only has a host name make sure there is an ending "/" to avoid signature mismatch issues.
// If there is a resource path do not add a "/" because the marshallers are relying on the URL to be in format without the "/".
// API Gateway Management API is an example of a service that vends its own URL that users have to set which has a resource path.
// The marshallers add new segments to the resource path with the "/".
try
{
var path = new Uri(value).PathAndQuery;
if (string.IsNullOrEmpty(path) || path == "/")
{
if (!string.IsNullOrEmpty(value) && !value.EndsWith("/"))
{
value += "/";
}
}
}
catch(UriFormatException)
{
throw new AmazonClientException("Value for ServiceURL is not a valid URL: " + value);
}
}
this.serviceURL = value;
}
}
/// <summary>
/// Gets and sets the UseHttp.
/// If this property is set to true, the client attempts
/// to use HTTP protocol, if the target endpoint supports it.
/// By default, this property is set to false.
/// </summary>
/// <remarks>This does not apply if an explicit <see cref="ServiceURL"/> is specified.</remarks>
public bool UseHttp
{
get { return this.useHttp; }
set { this.useHttp = value; }
}
/// <summary>
/// Given this client configuration, return a string form ofthe service endpoint url.
/// </summary>
[Obsolete("This operation is obsoleted because as of version 3.7.100 endpoint is resolved using a newer system that uses request level parameters to resolve the endpoint, use the service-specific client.DetermineServiceOperationEndPoint method instead.")]
public virtual string DetermineServiceURL()
{
string url;
if (this.ServiceURL != null)
{
url = this.ServiceURL;
}
else
{
url = GetUrl(this, RegionEndpoint);
}
return url;
}
/// <summary>
/// Given this client configuration, return a DNS suffix for service endpoint url.
/// </summary>
[Obsolete("This operation is obsoleted because as of version 3.7.100 endpoint is resolved using a newer system that uses request level parameters to resolve the endpoint, use the service-specific client.DetermineServiceOperationEndPoint method instead.")]
public virtual string DetermineDnsSuffix()
{
var endpoint = regionEndpoint.GetEndpointForService(this);
return endpoint.DnsSuffix;
}
internal static string GetUrl(IClientConfig config, RegionEndpoint regionEndpoint)
{
#pragma warning disable CS0612,CS0618
var endpoint =
regionEndpoint.GetEndpointForService(
config.RegionEndpointServiceName,
config.ToGetEndpointForServiceOptions());
#pragma warning restore CS0612,CS0618
string url = new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", config.UseHttp ? "http://" : "https://", endpoint.Hostname)).AbsoluteUri;
return url;
}
/// <summary>
/// Gets and sets the AuthenticationRegion property.
/// Used in AWS4 request signing, this is an optional property;
/// change it only if the region cannot be determined from the
/// service endpoint.
/// </summary>
public string AuthenticationRegion
{
get { return this.authRegion; }
set { this.authRegion = value; }
}
/// <summary>
/// Gets and sets the AuthenticationServiceName property.
/// Used in AWS4 request signing, this is the short-form
/// name of the service being called.
/// </summary>
public string AuthenticationServiceName
{
get { return this.authServiceName; }
set { this.authServiceName = value; }
}
/// <summary>
/// The serviceId for the service, which is specified in the metadata in the ServiceModel.
/// The transformed value of the service ID (replace any spaces in the service ID
/// with underscores and uppercase all letters) is used to set service-specific endpoint urls.
/// I.e: AWS_ENDPOINT_URL_ELASTIC_BEANSTALK
/// For configuration files, replace any spaces with underscores and lowercase all letters
/// I.e. elastic_beanstalk =
/// endpoint_url = http://localhost:8000
/// </summary>
public string ServiceId
{
get { return this.serviceId; }
set { this.serviceId = value; }
}
/// <summary>
/// Returns the flag indicating how many retry HTTP requests an SDK should
/// make for a single SDK operation invocation before giving up. This flag will
/// return 4 when the RetryMode is set to "Legacy" which is the default. For
/// RetryMode values of "Standard" or "Adaptive" this flag will return 2. In
/// addition to the values returned that are dependent on the RetryMode, the
/// value can be set to a specific value by using the AWS_MAX_ATTEMPTS environment
/// variable, max_attempts in the shared configuration file, or by setting a
/// value directly on this property. When using AWS_MAX_ATTEMPTS or max_attempts
/// the value returned from this property will be one less than the value entered
/// because this flag is the number of retry requests, not total requests. To
/// learn more about the RetryMode property that affects the values returned by
/// this flag, see <see cref="RetryMode"/>.
/// </summary>
public int MaxErrorRetry
{
get
{
if (!this.maxRetries.HasValue)
{
//For legacy mode there was no MaxAttempts shared config or
//environment variables so use the legacy default value.
if (RetryMode == RequestRetryMode.Legacy)
{
return MaxRetriesLegacyDefault;
}
//For standard and adaptive modes first check the environment variables
//and shared config for a value. Otherwise default to the new default value.
//In the shared config or environment variable MaxAttempts is the total number
//of attempts. This will include the initial call and must be deducted from
//from the number of actual retries.
return FallbackInternalConfigurationFactory.MaxAttempts - 1 ?? MaxRetriesDefault;
}
return this.maxRetries.Value;
}
set { this.maxRetries = value; }
}
/// <summary>
/// Determines if MaxErrorRetry has been manually set.
/// </summary>
public bool IsMaxErrorRetrySet
{
get
{
return this.maxRetries.HasValue;
}
}
/// <summary>
/// Gets and sets the LogResponse property.
/// If this property is set to true, the service response is logged.
/// The size of response being logged is controlled by the AWSConfigs.LoggingConfig.LogResponsesSizeLimit property.
/// </summary>
public bool LogResponse
{
get { return this.logResponse; }
set { this.logResponse = value; }
}
/// <summary>
/// Gets and sets the ReadEntireResponse property.
/// NOTE: This property does not effect response processing and is deprecated.
/// To enable response logging, the ClientConfig.LogResponse and AWSConfigs.LoggingConfig
/// properties can be used.
/// </summary>
[Obsolete("This property does not effect response processing and is deprecated." +
"To enable response logging, the ClientConfig.LogResponse and AWSConfigs.LoggingConfig.LogResponses properties can be used.")]
public bool ReadEntireResponse
{
get { return this.readEntireResponse; }
set { this.readEntireResponse = value; }
}
/// <summary>
/// Gets and Sets the BufferSize property.
/// The BufferSize controls the buffer used to read in from input streams and write
/// out to the request.
/// </summary>
public int BufferSize
{
get { return this.bufferSize; }
set { this.bufferSize = value; }
}
/// <summary>
/// <para>
/// Gets or sets the interval at which progress update events are raised
/// for upload operations. By default, the progress update events are
/// raised at every 100KB of data transferred.
/// </para>
/// <para>
/// If the value of this property is set less than ClientConfig.BufferSize,
/// progress updates events will be raised at the interval specified by ClientConfig.BufferSize.
/// </para>
/// </summary>
public long ProgressUpdateInterval
{
get { return progressUpdateInterval; }
set { progressUpdateInterval = value; }
}
/// <summary>
/// Flag on whether to resign requests on retry or not.
/// For Amazon S3 and Amazon Glacier this value will always be set to true.
/// </summary>
public bool ResignRetries
{
get { return this.resignRetries; }
set { this.resignRetries = value; }
}
/// <summary>
/// This flag controls if .NET HTTP infrastructure should follow redirection
/// responses (e.g. HTTP 307 - temporary redirect).
/// </summary>
public bool AllowAutoRedirect
{
get
{
return this.allowAutoRedirect;
}
set
{
this.allowAutoRedirect = value;
}
}
/// <summary>
/// Flag on whether to log metrics for service calls.
///
/// This can be set in the application's configs, as below:
/// <code>
/// <?xml version="1.0" encoding="utf-8" ?>
/// <configuration>
/// <appSettings>
/// <add key="AWSLogMetrics" value"true"/>
/// </appSettings>
/// </configuration>
/// </code>
/// </summary>
public bool LogMetrics
{
get { return this.logMetrics; }
set { this.logMetrics = value; }
}
/// <summary>
/// Gets and sets the DisableLogging. If true logging for this client will be disabled.
/// </summary>
public bool DisableLogging
{
get { return this.disableLogging; }
set { this.disableLogging = value; }
}
/// <summary>
/// Specify a <see cref="Amazon.Runtime.DefaultConfigurationMode"/> to use.
/// <para />
/// Returns the <see cref="Amazon.Runtime.DefaultConfigurationMode"/> that will be used. If none is specified,
/// than the correct one is computed by <see cref="IDefaultConfigurationProvider"/>.
/// </summary>
public DefaultConfigurationMode DefaultConfigurationMode
{
get
{
if (this.defaultConfigurationMode.HasValue)
return this.defaultConfigurationMode.Value;
return DefaultConfiguration.Name;
}
set
{
this.defaultConfigurationMode = value;
defaultConfigurationBackingField = null;
}
}
private IDefaultConfiguration defaultConfigurationBackingField;
protected IDefaultConfiguration DefaultConfiguration
{
get
{
if (defaultConfigurationBackingField != null)
return defaultConfigurationBackingField;
defaultConfigurationBackingField =
_defaultConfigurationProvider.GetDefaultConfiguration(RegionEndpoint, defaultConfigurationMode);
return defaultConfigurationBackingField;
}
}
/// <summary>
/// Credentials to use with a proxy.
/// </summary>
public ICredentials ProxyCredentials
{
get
{
if(this.proxyCredentials == null &&
(!string.IsNullOrEmpty(AWSConfigs.ProxyConfig.Username) ||
!string.IsNullOrEmpty(AWSConfigs.ProxyConfig.Password)))
{
return new NetworkCredential(AWSConfigs.ProxyConfig.Username, AWSConfigs.ProxyConfig.Password ?? string.Empty);
}
return this.proxyCredentials;
}
set { this.proxyCredentials = value; }
}
#if BCL
public WebProxy GetHttpProxy()
#else
public IWebProxy GetHttpProxy()
#endif
{
var explicitProxy = GetWebProxy();
if (explicitProxy != null)
{
return explicitProxy;
}
return GetWebProxyWithCredentials(Environment.GetEnvironmentVariable("http_proxy"));
}
#if BCL
public WebProxy GetHttpsProxy()
#else
public IWebProxy GetHttpsProxy()
#endif
{
var explicitProxy = GetWebProxy();
if (explicitProxy != null)
{
return explicitProxy;
}
return GetWebProxyWithCredentials(Environment.GetEnvironmentVariable("https_proxy"));
}
#if BCL
/// <summary>
/// Specifies the TCP keep-alive values to use for service requests.
/// </summary>
public TcpKeepAlive TcpKeepAlive
{
get { return this.tcpKeepAlive; }
}
#endif
#region Constructor
protected ClientConfig(IDefaultConfigurationProvider defaultConfigurationProvider)
{
_defaultConfigurationProvider = defaultConfigurationProvider;
Initialize();
}
public ClientConfig() : this(new LegacyOnlyDefaultConfigurationProvider())
{
this.defaultConfigurationBackingField = _defaultConfigurationProvider.GetDefaultConfiguration(null, null);
this.defaultConfigurationMode = this.defaultConfigurationBackingField.Name;
}
/// <summary>
/// Specialized <see cref="IDefaultConfigurationProvider"/> that is only meant to provide backwards
/// compatibility for the obsolete <see cref="ClientConfig"/> constructor.
/// </summary>
private class LegacyOnlyDefaultConfigurationProvider : IDefaultConfigurationProvider
{
public IDefaultConfiguration GetDefaultConfiguration(RegionEndpoint clientRegion, DefaultConfigurationMode? requestedConfigurationMode = null)
{
if (requestedConfigurationMode.HasValue &&
requestedConfigurationMode.Value != Runtime.DefaultConfigurationMode.Legacy)
throw new AmazonClientException($"This ClientConfig only supports {Runtime.DefaultConfigurationMode.Legacy}");
return new DefaultConfiguration
{
Name = Runtime.DefaultConfigurationMode.Legacy,
RetryMode = RequestRetryMode.Legacy,
S3UsEast1RegionalEndpoint = S3UsEast1RegionalEndpointValue.Legacy,
StsRegionalEndpoints = StsRegionalEndpointsValue.Legacy
};
}
}
#endregion
protected virtual void Initialize()
{
}
/// <summary>
/// .NET Framework 3.5
/// ------------------
/// Overrides the default request timeout value.
/// This field does not impact Begin*/End* calls. A manual timeout must be implemented.
///
/// .NET Framework 4.5
/// ------------------
/// Overrides the default request timeout value.
/// This field does not impact *Async calls. A manual timeout (for instance, using CancellationToken) must be implemented.
/// </summary>
/// <remarks>
/// <para>
/// If the value is set, the value is assigned to the Timeout property of the HttpWebRequest/HttpClient object used
/// to send requests.
/// </para>
/// <para>
/// Please specify a timeout value only if the operation will not complete within the default intervals
/// specified for an HttpWebRequest/HttpClient.
/// </para>
/// </remarks>
/// <exception cref="System.ArgumentNullException">The timeout specified is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">The timeout specified is less than or equal to zero and is not Infinite.</exception>
/// <seealso cref="P:System.Net.HttpWebRequest.Timeout"/>
/// <seealso cref="P:System.Net.Http.HttpClient.Timeout"/>
public TimeSpan? Timeout
{
get
{
if (this.timeout.HasValue)
return this.timeout;
// TimeToFirstByteTimeout is not a perfect match with HttpWebRequest/HttpClient.Timeout. However, given
// that both are configured to only use Timeout until the Response Headers are downloaded, this value
// provides a reasonable default value.
return DefaultConfiguration.TimeToFirstByteTimeout;
}
set
{
ValidateTimeout(value);
this.timeout = value;
}
}
#if AWS_ASYNC_API
/// <summary>
/// Generates a <see cref="CancellationToken"/> based on the value
/// for <see cref="DefaultConfiguration.TimeToFirstByteTimeout"/>.
/// </summary>
internal CancellationToken BuildDefaultCancellationToken()
{
// legacy mode never had a working cancellation token, so keep it to default()
if (DefaultConfiguration.Name == Runtime.DefaultConfigurationMode.Legacy)
return default(CancellationToken);
// TimeToFirstByteTimeout is not a perfect match with HttpWebRequest/HttpClient.Timeout. However, given
// that both are configured to only use Timeout until the Response Headers are downloaded, this value
// provides a reasonable default value.
var cancelTimeout = DefaultConfiguration.TimeToFirstByteTimeout;
return cancelTimeout.HasValue
? new CancellationTokenSource(cancelTimeout.Value).Token
: default(CancellationToken);
}
#endif
/// <summary>
/// Configures the endpoint calculation for a service to go to a dual stack (ipv6 enabled) endpoint
/// for the configured region.
/// </summary>
/// <remarks>
/// Note: AWS services are enabling dualstack endpoints over time. It is your responsibility to check
/// that the service actually supports a dualstack endpoint in the configured region before enabling
/// this option for a service.
/// </remarks>
public bool UseDualstackEndpoint
{
get
{
if (!this.useDualstackEndpoint.HasValue)
{
return FallbackInternalConfigurationFactory.UseDualStackEndpoint ?? false;
}
return this.useDualstackEndpoint.Value;
}
set { useDualstackEndpoint = value; }
}
/// <summary>
/// Configures the endpoint calculation to go to a FIPS (https://aws.amazon.com/compliance/fips/) endpoint
/// for the configured region.
/// </summary>
public bool UseFIPSEndpoint
{
get
{
if (!this.useFIPSEndpoint.HasValue)
{
return FallbackInternalConfigurationFactory.UseFIPSEndpoint ?? false;
}
return this.useFIPSEndpoint.Value;
}
set { useFIPSEndpoint = value; }
}
/// <summary>
/// If set to true the SDK will ignore the configured endpointUrls in the config file or in the environment variables.
/// By default it is set to false.
/// </summary>
public bool IgnoreConfiguredEndpointUrls
{
get
{
if (!this.ignoreConfiguredEndpointUrls.HasValue)
return FallbackInternalConfigurationFactory.IgnoreConfiguredEndpointUrls ?? false;
return this.ignoreConfiguredEndpointUrls.Value;
}
set { ignoreConfiguredEndpointUrls = value; }
}
/// <summary>
/// Controls whether request payloads are automatically compressed for supported operations.
/// This setting only applies to operations that support compression.
/// The default value is "false". Set to "true" to disable compression.
/// </summary>
public bool DisableRequestCompression
{
get
{
if (!this.disableRequestCompression.HasValue)
{
return FallbackInternalConfigurationFactory.DisableRequestCompression ?? false;
}
return this.disableRequestCompression.Value;
}
set { disableRequestCompression = value; }
}
/// <summary>
/// Minimum size in bytes that a request body should be to trigger compression.
/// </summary>
public long RequestMinCompressionSizeBytes
{
get
{
if (!this.requestMinCompressionSizeBytes.HasValue)
{
return FallbackInternalConfigurationFactory.RequestMinCompressionSizeBytes ?? DefaultMinCompressionSizeBytes;
}
return this.requestMinCompressionSizeBytes.Value;
}
set
{
ValidateMinCompression(value);
requestMinCompressionSizeBytes = value;
}
}
/// <summary>
/// <para>
/// ClientAppId is an optional application specific identifier that can be set. When set it will be appended to the User-Agent header of every request in the form of <c>app/{ClientAppId}</c>.
/// </para>
/// <para>
/// If the ClientAppId is not set on the object the SDK will search the environment variable <c>AWS_SDK_UA_APP_ID</c> and the shared config profile attribute <c>sdk_ua_app_id</c> for a potential value for the ClientAppId.
/// </para>
/// </summary>
/// <remarks>
/// See <see href="https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html"/> for more information on environment variables and shared config settings.
/// </remarks>
public string ClientAppId
{
get
{
if (this.clientAppId == null)
{
return FallbackInternalConfigurationFactory.ClientAppId;
}
return this.clientAppId;
}
set
{
ValidateClientAppId(value);
this.clientAppId = value;
}
}
private static void ValidateClientAppId(string clientAppId)
{
if (clientAppId != null && clientAppId.Length > EnvironmentVariableInternalConfiguration.AWS_SDK_UA_APP_ID_MAX_LENGTH)
{
Logger.GetLogger(typeof(InternalConfiguration)).InfoFormat("Warning: Client app id exceeds recommended maximum length of {0} characters: \"{1}\"", EnvironmentVariableInternalConfiguration.AWS_SDK_UA_APP_ID_MAX_LENGTH, clientAppId);
}
}
private static void ValidateMinCompression(long minCompressionSize)
{
if (minCompressionSize < 0 || minCompressionSize > UpperLimitCompressionSizeBytes)
{
throw new ArgumentException(string.Format("Invalid value {0} for {1}." +
" A long value between 0 and {2} bytes inclusive is expected.", minCompressionSize,
nameof(requestMinCompressionSizeBytes), UpperLimitCompressionSizeBytes));
}
}
/// <summary>
/// Enable or disable the Retry Throttling feature by setting the ThrottleRetries flag to True/False respectively.
/// Retry Throttling is a feature that intelligently throttles retry attempts when a large percentage of requests
/// are failing and retries are unsuccessful as well. In such situations the allotted retry capacity for the service URL
/// will be drained until requests start to succeed again. Once the requisite capacity is available, retries would
/// be permitted again. When retries are throttled, the service enters a fail-fast behaviour as the traditional retry attempt
/// for the request would be circumvented. Hence, errors will resurface quickly. This will result in a greater number of exceptions
/// but prevents requests being tied up in unsuccessful retry attempts.
/// Note: Retry Throttling is enabled by default. Set the ThrottleRetries flag to false to switch off this feature.
/// </summary>
public bool ThrottleRetries
{
get { return throttleRetries; }
set { throttleRetries = value; }
}
/// <summary>
/// Enable or disable the Nagle algorithm on the underlying http
/// client.
///
/// This method is not intended to be called by consumers of the AWS SDK for .NET
/// </summary>
/// <param name="useNagle"></param>
public void SetUseNagleIfAvailable(bool useNagle)
{
#if BCL
this.UseNagleAlgorithm = useNagle;
#endif
}
/// <summary>
/// Performs validation on this config object.
/// Throws exception if any of the required values are missing/invalid.