using Amazon; using Amazon.Runtime; using Amazon.Runtime.Internal; using Amazon.Runtime.Internal.Transform; using AWSSDK_DotNet.IntegrationTests.Tests; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; namespace AWSSDK_DotNet.IntegrationTests.Utils { public static class RetryUtilities { // Flag to force failing of a first request, but passing of retry requests public static bool FailOriginalRequests = false; public static bool TestClockSkewCorrection = false; public static bool SetIncorrectClockOffsetFuture = false; public static void ConfigureClient(AmazonServiceClient client) { if (FailOriginalRequests) ForceConfigureClient(client); // Attach events to client client.BeforeRequestEvent += (s, e) => { if (TestClockSkewCorrection) { // set clockskew correction to wrong value SetIncorrectOffset(client.Config); } }; client.AfterResponseEvent += (s, e) => { }; client.ExceptionEvent += (s, e) => { }; } #region Clock Skew testing /// /// Disables clock skew correction until result is disposed /// /// public static IDisposable DisableClockSkewCorrection() { return ClockSkewTemporarySwitch.Disable(); } /// /// Enables clock skew correction until result is disposed /// /// public static IDisposable EnableClockSkewCorrection() { return ClockSkewTemporarySwitch.Enable(); } /// /// Class that switches clock skew correction on or off at creation, /// then returns to the previous setting when disposed /// private class ClockSkewTemporarySwitch : IDisposable { public bool OldValue { get; private set; } public ClockSkewTemporarySwitch(bool temporarilyCorrectClockSkew) { OldValue = AWSConfigs.CorrectForClockSkew; AWSConfigs.CorrectForClockSkew = temporarilyCorrectClockSkew; } public static ClockSkewTemporarySwitch Enable() { return new ClockSkewTemporarySwitch(temporarilyCorrectClockSkew: true); } public static ClockSkewTemporarySwitch Disable() { return new ClockSkewTemporarySwitch(temporarilyCorrectClockSkew: false); } public void Dispose() { AWSConfigs.CorrectForClockSkew = OldValue; } } private static void SetIncorrectOffset(IClientConfig config) { TimeSpan offset; if (SetIncorrectClockOffsetFuture) offset = General.IncorrectPositiveClockSkewOffset; else offset = General.IncorrectNegativeClockSkewOffset; General.SetClockSkewCorrection(config, offset); } #endregion #region Retry testing public static void ForceConfigureClient(AmazonServiceClient client) { RetryHttpRequestFactory.AddToClient(client); } private class RetryHttpRequestFactory : IHttpRequestFactory { public IHttpRequest CreateHttpRequest(Uri requestUri) { var request = new RetryHttpRequest(requestUri); return request; } public void Dispose() { } public static void AddToClient(AmazonServiceClient client) { var pipeline = client .GetType() .GetProperty("RuntimePipeline", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) .GetValue(client, null) as RuntimePipeline; var requestFactory = new RetryHttpRequestFactory(); var httpHandler = new HttpHandler(requestFactory, client); pipeline.ReplaceHandler>(httpHandler); } } private class RetryHttpRequest : HttpRequest { public RetryHttpRequest(Uri requestUri) : base(requestUri) { IsRetry = false; } public bool IsRetry { get; private set; } public bool IsRewindable { get; private set; } public override Amazon.Runtime.Internal.Transform.IWebResponseData GetResponse() { if (IsRetry || !IsRewindable) return base.GetResponse(); else { base.Abort(); throw new WebException("Newp!", null, WebExceptionStatus.ConnectionClosed, null); } } #if BCL45 public override System.Threading.Tasks.Task GetResponseAsync(System.Threading.CancellationToken cancellationToken) { if (IsRetry || !IsRewindable) return base.GetResponseAsync(cancellationToken); else { base.Abort(); throw new WebException("Newp!", null, WebExceptionStatus.ConnectionClosed, null); } } #elif BCL && !BCL45 public override IWebResponseData EndGetResponse(IAsyncResult asyncResult) { if (IsRetry || !IsRewindable) return base.EndGetResponse(asyncResult); else { base.Abort(); throw new WebException("Newp!", null, WebExceptionStatus.ConnectionClosed, null); } } #endif public override void ConfigureRequest(IRequestContext requestContext) { base.ConfigureRequest(requestContext); IsRetry = requestContext.Retries > 0; IsRewindable = requestContext.Request.IsRequestStreamRewindable(); } } #endregion } }