/// <summary> /// Return true if the request should be retried. Implements additional checks /// specific to S3 on top of the checks in DefaultRetryPolicy. /// </summary> /// <param name="executionContext">Request context containing the state of the request.</param> /// <param name="exception">The exception thrown by the previous request.</param> /// <returns>Return true if the request should be retried.</returns> public override bool RetryForException(Runtime.IExecutionContext executionContext, Exception exception) { var serviceException = exception as AmazonServiceException; if (serviceException != null) { if (serviceException.StatusCode == HttpStatusCode.OK) { var requestType = executionContext.RequestContext.OriginalRequest.GetType(); if (AmazonS3RetryPolicy.RequestsWith200Error.Contains(requestType)) { // Retry on HTTP 200 responses which contain an error response. // CopyObject, CopyPart and CompleteMultipartUpload operations can return this // response. return(true); } } if (serviceException.StatusCode == HttpStatusCode.BadRequest) { var configuredUri = new Uri(executionContext.RequestContext.ClientConfig.DetermineServiceURL()); if (configuredUri.Host.Equals(S3Constants.S3DefaultEndpoint) && (serviceException.Message.Contains(AWS4Signer.AWS4AlgorithmTag) || serviceException.Message.Contains(AWS_KMS_Signature_Error)) ) { // If the response message indicates AWS4 signing should have been used, // we've attempted to access a bucket in an AWS4-only region (e.g. EU Central (Frankfurt)) with an AWS2 // signature and/or client not configured with the correct region. // Retry the request to the s3-external endpoint to yield a 307 redirect // that we can then follow to the correct bucket location with the expected // signing algorithm. Logger.InfoFormat("Request {0}: the bucket you are attempting to access should be addressed using a region-specific endpoint." + " Additional calls will be made to attempt to determine the correct region to be used." + " For better performance configure your client to use the correct region.", executionContext.RequestContext.RequestName); var r = executionContext.RequestContext.Request; var s3Uri = new AmazonS3Uri(r.Endpoint); // since DNS resolved, yielding an auth error from the service, // we're assuming we do not need to test (again) for dns compatibility // on the bucket name var tempEndpoint = string.Format(CultureInfo.InvariantCulture, "https://{0}.{1}", s3Uri.Bucket, S3Constants.S3AlternateDefaultEndpoint); r.Endpoint = new Uri(tempEndpoint); if (serviceException.Message.Contains(AWS_KMS_Signature_Error)) { r.UseSigV4 = true; r.AuthenticationRegion = RegionEndpoint.USEast1.SystemName; executionContext.RequestContext.IsSigned = false; } return(true); } } } return(base.RetryForException(executionContext, exception)); }
internal static async Task <bool> SharedRetryForExceptionAsync(Runtime.IExecutionContext executionContext, Exception exception, Func <Runtime.IExecutionContext, Exception, bool?> retryForExceptionSync, Func <Runtime.IExecutionContext, Exception, bool> baseRetryForException) { var syncResult = retryForExceptionSync(executionContext, exception); if (syncResult.HasValue) { return(syncResult.Value); } else { var serviceException = exception as AmazonServiceException; string correctedRegion = null; AmazonS3Uri s3BucketUri; if (AmazonS3Uri.TryParseAmazonS3Uri(executionContext.RequestContext.Request.Endpoint, out s3BucketUri)) { var credentials = executionContext.RequestContext.ImmutableCredentials; correctedRegion = await BucketRegionDetector.DetectMismatchWithHeadBucketFallbackAsync(s3BucketUri, serviceException, credentials).ConfigureAwait(false); } if (correctedRegion == null) { return(baseRetryForException(executionContext, exception)); } else { // change authentication region of request and signal the handler to sign again with the new region executionContext.RequestContext.Request.AuthenticationRegion = correctedRegion; executionContext.RequestContext.IsSigned = false; return(true); } } }
/// <summary> /// Return true if the request should be retried. Implements additional checks /// specific to S3 on top of the checks in DefaultRetryPolicy. /// </summary> /// <param name="executionContext">Request context containing the state of the request.</param> /// <param name="exception">The exception thrown by the previous request.</param> /// <returns>Return true if the request should be retried.</returns> public override bool RetryForException(Runtime.IExecutionContext executionContext, Exception exception) { var syncResult = RetryForExceptionSync(executionContext, exception); if (syncResult.HasValue) { return(syncResult.Value); } else { var serviceException = exception as AmazonServiceException; string correctedRegion = null; AmazonS3Uri s3BucketUri; if (AmazonS3Uri.TryParseAmazonS3Uri(executionContext.RequestContext.Request.Endpoint, out s3BucketUri)) { var credentials = executionContext.RequestContext.ImmutableCredentials; if (credentials != null) { correctedRegion = BucketRegionDetector.DetectMismatchWithHeadBucketFallback(s3BucketUri, serviceException, credentials); } } if (correctedRegion == null) { return(base.RetryForException(executionContext, exception)); } else { // change authentication region of request and signal the handler to sign again with the new region executionContext.RequestContext.Request.AuthenticationRegion = correctedRegion; executionContext.RequestContext.IsSigned = false; return(true); } } }
/// <summary> /// Return true if the request should be retried. Implements additional checks /// specific to S3 on top of the checks in StandardRetryPolicy. /// </summary> /// <param name="executionContext">Request context containing the state of the request.</param> /// <param name="exception">The exception thrown by the previous request.</param> /// <returns>Return true if the request should be retried.</returns> public override async Task <bool> RetryForExceptionAsync(Runtime.IExecutionContext executionContext, Exception exception) { return(await AmazonS3RetryPolicy.SharedRetryForExceptionAsync(executionContext, exception, RetryForExceptionSync, base.RetryForException).ConfigureAwait(false)); }
/// <summary> /// Perform the processor-bound portion of the RetryForException logic. /// This is shared by the sync, async, and APM versions of the RetryForException method. /// </summary> /// <param name="executionContext"></param> /// <param name="exception"></param> /// <returns>a value if it can be determined, or null if the IO-bound calculations need to be done</returns> public bool?RetryForExceptionSync(Runtime.IExecutionContext executionContext, Exception exception) { return(SharedRetryForExceptionSync(executionContext, exception, Logger, base.RetryForException)); }
/// <summary> /// Return true if the request should be retried. Implements additional checks /// specific to S3 on top of the checks in StandardRetryPolicy. /// </summary> /// <param name="executionContext">Request context containing the state of the request.</param> /// <param name="exception">The exception thrown by the previous request.</param> /// <returns>Return true if the request should be retried.</returns> public override bool RetryForException(Runtime.IExecutionContext executionContext, Exception exception) { return(AmazonS3RetryPolicy.SharedRetryForException(executionContext, exception, RetryForExceptionSync, base.RetryForException)); }