/*
* 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
{
///
/// This class is the base class of all the configurations settings to connect
/// to a service.
///
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);
// 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 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 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 bool didProcessServiceURL = false;
private IAWSTokenProvider _awsTokenProvider = new DefaultAWSTokenProviderChain();
private CredentialProfileStoreChain credentialProfileStoreChain;
#if BCL
private readonly TcpKeepAlive tcpKeepAlive = new TcpKeepAlive();
#endif
///
/// 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.
///
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;
}
}
///
public IAWSTokenProvider AWSTokenProvider
{
get { return this._awsTokenProvider; }
set { this._awsTokenProvider = value; }
}
///
/// Gets Service Version
///
public abstract string ServiceVersion
{
get;
}
///
/// Gets and sets of the signatureMethod property.
///
public SigningAlgorithm SignatureMethod
{
get { return this.signatureMethod; }
set { this.signatureMethod = value; }
}
///
/// 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.
///
public string SignatureVersion
{
get { return this.signatureVersion; }
set { this.signatureVersion = value; }
}
///
/// Gets and sets of the UserAgent property.
///
public abstract string UserAgent { get; }
///
/// 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.
///
public bool UseAlternateUserAgentHeader
{
get { return this.useAlternateUserAgentHeader; }
set { this.useAlternateUserAgentHeader = value; }
}
///
///
/// 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.
///
///
/// RegionEndpoint and ServiceURL are mutually exclusive properties.
/// Whichever property is set last will cause the other to automatically
/// be reset to null.
///
///
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", ""));
this.RegionEndpoint.OriginalSystemName = value.SystemName;
}
}
}
///
/// The constant used to lookup in the region hash the endpoint.
///
public abstract string RegionEndpointServiceName
{
get;
}
///
///
/// Gets and sets of the ServiceURL property.
/// This is an optional property; change it
/// only if you want to try a different service
/// endpoint.
///
///
/// RegionEndpoint and ServiceURL are mutually exclusive properties.
/// Whichever property is set last will cause the other to automatically
/// be reset to null.
///
///
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)
{
didProcessServiceURL = true;
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)
{
didProcessServiceURL = true;
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 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}.");
didProcessServiceURL = true;
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}.");
didProcessServiceURL = true;
this.ServiceURL = profile.EndpointUrl;
}
}
}
}
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;
}
}
///
/// 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.
///
/// This does not apply if an explicit is specified.
public bool UseHttp
{
get { return this.useHttp; }
set { this.useHttp = value; }
}
///
/// Given this client configuration, return a string form ofthe service endpoint url.
///
[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.")]
public virtual string DetermineServiceURL()
{
string url;
if (this.ServiceURL != null)
{
url = this.ServiceURL;
}
else
{
url = GetUrl(this, RegionEndpoint);
}
return url;
}
///
/// Given this client configuration, return a DNS suffix for service endpoint url.
///
[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.")]
public virtual string DetermineDnsSuffix()
{
var endpoint = regionEndpoint.GetEndpointForService(this);
return endpoint.DnsSuffix;
}
internal static string GetUrl(IClientConfig config, RegionEndpoint regionEndpoint)
{
var endpoint =
regionEndpoint.GetEndpointForService(
config.RegionEndpointServiceName,
config.ToGetEndpointForServiceOptions());
string url = new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", config.UseHttp ? "http://" : "https://", endpoint.Hostname)).AbsoluteUri;
return url;
}
///
/// 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.
///
public string AuthenticationRegion
{
get { return this.authRegion; }
set { this.authRegion = value; }
}
///
/// Gets and sets the AuthenticationServiceName property.
/// Used in AWS4 request signing, this is the short-form
/// name of the service being called.
///
public string AuthenticationServiceName
{
get { return this.authServiceName; }
set { this.authServiceName = value; }
}
///
/// 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
///
public string ServiceId
{
get { return this.serviceId; }
set { this.serviceId = value; }
}
///
/// 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 .
///
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; }
}
///
/// Determines if MaxErrorRetry has been manually set.
///
public bool IsMaxErrorRetrySet
{
get
{
return this.maxRetries.HasValue;
}
}
///
/// 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.
///
public bool LogResponse
{
get { return this.logResponse; }
set { this.logResponse = value; }
}
///
/// 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.
///
[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; }
}
///
/// Gets and Sets the BufferSize property.
/// The BufferSize controls the buffer used to read in from input streams and write
/// out to the request.
///
public int BufferSize
{
get { return this.bufferSize; }
set { this.bufferSize = value; }
}
///
///
/// 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.
///
///
/// 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.
///
///
public long ProgressUpdateInterval
{
get { return progressUpdateInterval; }
set { progressUpdateInterval = value; }
}
///
/// Flag on whether to resign requests on retry or not.
/// For Amazon S3 and Amazon Glacier this value will always be set to true.
///
public bool ResignRetries
{
get { return this.resignRetries; }
set { this.resignRetries = value; }
}
///
/// This flag controls if .NET HTTP infrastructure should follow redirection
/// responses (e.g. HTTP 307 - temporary redirect).
///
public bool AllowAutoRedirect
{
get
{
return this.allowAutoRedirect;
}
set
{
this.allowAutoRedirect = value;
}
}
///
/// Flag on whether to log metrics for service calls.
///
/// This can be set in the application's configs, as below:
///
/// <?xml version="1.0" encoding="utf-8" ?>
/// <configuration>
/// <appSettings>
/// <add key="AWSLogMetrics" value"true"/>
/// </appSettings>
/// </configuration>
///
///
public bool LogMetrics
{
get { return this.logMetrics; }
set { this.logMetrics = value; }
}
///
/// Gets and sets the DisableLogging. If true logging for this client will be disabled.
///
public bool DisableLogging
{
get { return this.disableLogging; }
set { this.disableLogging = value; }
}
///
/// Specify a to use.
///
/// Returns the that will be used. If none is specified,
/// than the correct one is computed by .
///
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;
}
}
///
/// Credentials to use with a proxy.
///
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
///
/// Specifies the TCP keep-alive values to use for service requests.
///
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;
}
///
/// Specialized that is only meant to provide backwards
/// compatibility for the obsolete constructor.
///
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()
{
}
#if BCL35
///
/// Overrides the default request timeout value.
/// This field does not impact Begin*/End* calls. A manual timeout must be implemented.
///
#elif BCL45
///
/// Overrides the default request timeout value.
/// This field does not impact *Async calls. A manual timeout (for instance, using CancellationToken) must be implemented.
///
#endif
///
///
/// If the value is set, the value is assigned to the Timeout property of the HttpWebRequest/HttpClient object used
/// to send requests.
///
///
/// Please specify a timeout value only if the operation will not complete within the default intervals
/// specified for an HttpWebRequest/HttpClient.
///
///
/// The timeout specified is null.
/// The timeout specified is less than or equal to zero and is not Infinite.
///
///
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
///
/// Generates a based on the value
/// for .
///
/// NOTE: uses
///
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
///
/// Configures the endpoint calculation for a service to go to a dual stack (ipv6 enabled) endpoint
/// for the configured region.
///
///
/// 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.
///
public bool UseDualstackEndpoint
{
get
{
if (!this.useDualstackEndpoint.HasValue)
{
return FallbackInternalConfigurationFactory.UseDualStackEndpoint ?? false;
}
return this.useDualstackEndpoint.Value;
}
set { useDualstackEndpoint = value; }
}
///
/// Configures the endpoint calculation to go to a FIPS (https://aws.amazon.com/compliance/fips/) endpoint
/// for the configured region.
///
public bool UseFIPSEndpoint
{
get
{
if (!this.useFIPSEndpoint.HasValue)
{
return FallbackInternalConfigurationFactory.UseFIPSEndpoint ?? false;
}
return this.useFIPSEndpoint.Value;
}
set { useFIPSEndpoint = value; }
}
///
/// 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.
///
public bool IgnoreConfiguredEndpointUrls
{
get
{
if (!this.ignoreConfiguredEndpointUrls.HasValue)
return FallbackInternalConfigurationFactory.IgnoreConfiguredEndpointUrls ?? false;
return this.ignoreConfiguredEndpointUrls.Value;
}
set { ignoreConfiguredEndpointUrls = value; }
}
///
/// 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.
///
public bool ThrottleRetries
{
get { return throttleRetries; }
set { throttleRetries = value; }
}
///
/// 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
///
///
public void SetUseNagleIfAvailable(bool useNagle)
{
#if BCL
this.UseNagleAlgorithm = useNagle;
#endif
}
///
/// Performs validation on this config object.
/// Throws exception if any of the required values are missing/invalid.
///
public virtual void Validate()
{
if (RegionEndpoint == null && string.IsNullOrEmpty(this.ServiceURL))
throw new AmazonClientException("No RegionEndpoint or ServiceURL configured");
#if BCL
if (TcpKeepAlive.Enabled)
{
ValidateTcpKeepAliveTimeSpan(TcpKeepAlive.Timeout, "TcpKeepAlive.Timeout");
ValidateTcpKeepAliveTimeSpan(TcpKeepAlive.Interval, "TcpKeepAlive.Interval");
}
#endif
}
///
/// Returns the current UTC now after clock correction for this endpoint.
///
[Obsolete("Please use CorrectClockSkew.GetCorrectedUtcNowForEndpoint(string endpoint) instead.", false)]
public DateTime CorrectedUtcNow
{
get
{
return CorrectClockSkew.GetCorrectedUtcNowForEndpoint(DetermineServiceURL());
}
}
///
/// The calculated clock skew correction for a specific endpoint, if there is one.
/// This field will be set if a service call resulted in an exception
/// and the SDK has determined that there is a difference between local
/// and server times.
///
/// If is set to true, this
/// value will still be set to the correction, but it will not be used by the
/// SDK and clock skew errors will not be retried.
///
public TimeSpan ClockOffset
{
get
{
if (AWSConfigs.ManualClockCorrection.HasValue)
{
return AWSConfigs.ManualClockCorrection.Value;
}
else
{
string endpoint = DetermineServiceURL();
return CorrectClockSkew.GetClockCorrectionForEndpoint(endpoint);
}
}
}
///
/// Gets and sets the DisableHostPrefixInjection flag. If true, host prefix injection will be disabled for this client, the default value of this flag is false.
/// Host prefix injection prefixes the service endpoint with request members from APIs which use this feature.
/// Example: for a hostPrefix of "foo-name." and a endpoint of "service.region.amazonaws.com" the default behavior is to
/// prefix the endpoint with the hostPrefix resulting in a final endpoint of "foo-name.service.region.amazonaws.com". Setting
/// DisableHostPrefixInjection to true will disable hostPrefix injection resulting in a final endpoint of
/// "service.region.amazonaws.com" regardless of the value of hostPrefix. E.g. You may want to disable host prefix injection for testing against a local mock endpoint.
///
public bool DisableHostPrefixInjection
{
get { return this.disableHostPrefixInjection; }
set { this.disableHostPrefixInjection = value; }
}
///
/// Returns the flag indicating if endpoint discovery should be enabled or disabled for operations that are not required to use endpoint discovery.
///
public bool EndpointDiscoveryEnabled
{
get
{
if (!this.endpointDiscoveryEnabled.HasValue)
{
return FallbackInternalConfigurationFactory.EndpointDiscoveryEnabled ?? false;
}
return this.endpointDiscoveryEnabled.Value;
}
set { this.endpointDiscoveryEnabled = value; }
}
///
/// Returns the maximum number of discovered endpoints that can be stored within the cache for the client. The default limit is 1000 cache entries.
///
public int EndpointDiscoveryCacheLimit
{
get { return this.endpointDiscoveryCacheLimit; }
set { this.endpointDiscoveryCacheLimit = value; }
}
///
/// Returns the flag indicating the current mode in use for request
/// retries and influences the value returned from .
/// The default value is RequestRetryMode.Legacy. This flag can be configured
/// by using the AWS_RETRY_MODE environment variable, retry_mode in the
/// shared configuration file, or by setting this value directly.
///
public RequestRetryMode RetryMode
{
get
{
if (!this.retryMode.HasValue)
{
return FallbackInternalConfigurationFactory.RetryMode ?? DefaultConfiguration.RetryMode;
}
return this.retryMode.Value;
}
set { this.retryMode = value; }
}
///
/// Under Adaptive retry mode, this flag determines if the client should wait for
/// a send token to become available or don't block and fail the request immediately
/// if a send token is not available.
///
public bool FastFailRequests { get; set; } = false;
///
/// Throw an exception if the boxed TimeSpan parameter doesn't have a value or is out of range.
///
public static void ValidateTimeout(TimeSpan? timeout)
{
if (!timeout.HasValue)
{
throw new ArgumentNullException("timeout");
}
if (timeout != InfiniteTimeout && (timeout <= TimeSpan.Zero || timeout > MaxTimeout))
{
throw new ArgumentOutOfRangeException("timeout");
}
}
#if BCL
private static void ValidateTcpKeepAliveTimeSpan(TimeSpan? value, string paramName)
{
if (!value.HasValue)
{
throw new ArgumentNullException(paramName);
}
if (value > MaxTimeout || (int)value.Value.TotalMilliseconds <= 0)
{
throw new ArgumentOutOfRangeException(paramName);
}
}
#endif
///
/// Returns the request timeout value if its value is set,
/// else returns client timeout value.
///
public static TimeSpan? GetTimeoutValue(TimeSpan? clientTimeout, TimeSpan? requestTimeout)
{
return requestTimeout.HasValue ? requestTimeout
: (clientTimeout.HasValue ? clientTimeout : null);
}
#if NETSTANDARD
///
///
/// This is a switch used for performance testing and is not intended for production applications
/// to change. This switch may be removed in a future version of the SDK as the .NET Core platform matures.
///
///
/// If true, the HttpClient is cached and reused for every request made by the service client
/// and shared with other service clients.
///
///
/// For the .NET Core platform this is default to true because the HttpClient manages the connection
/// pool.
///
///
public bool CacheHttpClient {get; set;} = true;
private int? _httpClientCacheSize;
///
/// If CacheHttpClient is set to true then HttpClientCacheSize controls the number of HttpClients cached.
///
/// The default value is 1 which is suitable for Windows and for all other platforms that have HttpClient
/// implementations using (.NET Core 2.1 and higher).
///
///
public int HttpClientCacheSize
{
get
{
if(_httpClientCacheSize.HasValue)
{
return _httpClientCacheSize.Value;
}
// Use both NETCOREAPP3_1 and NETCOREAPP3_1_OR_GREATER because currently the build server only has .NET Core 3.1 SDK installed
// which predates the OR_GREATER preprocessor statements. The NETCOREAPP3_1_OR_GREATER is used for future proofing.
#if NETCOREAPP3_1 || NETCOREAPP3_1_OR_GREATER
return 1;
#else
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 1 : Environment.ProcessorCount;
#endif
}
set => _httpClientCacheSize = value;
}
#endif
///
/// Overrides the default read-write timeout value.
///
///
///
/// If the value is set, the value is assigned to the ReadWriteTimeout property of the HttpWebRequest object used
/// to send requests.
///
/// The timeout specified is null.
/// The timeout specified is less than or equal to zero and is not Infinite.
///
///
#if NETSTANDARD
[Obsolete("ReadWriteTimeout is not consumed in asynchronous HTTP requests. Please use a cancellation token to handle stream read/write timeouts.")]
#endif
public TimeSpan? ReadWriteTimeout
{
get { return this.readWriteTimeout; }
set
{
ValidateTimeout(value);
this.readWriteTimeout = value;
}
}
///
/// Gets and sets of the EndpointProvider property.
/// This property is used for endpoints resolution.
/// During service client creation it is set to service's default generated EndpointProvider,
/// but can be changed to use custom user supplied EndpointProvider.
///
public IEndpointProvider EndpointProvider { get; set; }
}
}