/// <summary>
 /// Helper for regression tests that URLs less than or equal to 2048 characters, or requests that are not GET,
 /// are not modified. If you are testing with GET, the length should be less than 2048.
 /// </summary>
 private void SubtestGetWithUrlOkayLengthByDefault(uint length, HttpMethod method)
 {
     var requestUri = "http://www.example.com/?q=" + new String('x', (int)length - 26);
     var request = new HttpRequestMessage(method, requestUri);
     var mockHandler = new MockMessageHandler();
     var handler = new ConfigurableMessageHandler(mockHandler);
     handler.ExecuteInterceptors.Add(new MaxUrlLengthInterceptor(DefaultMaxUrlLength));
     using (var httpClient = new HttpClient(handler))
     {
         httpClient.SendAsync(request);
         Assert.That(request.RequestUri.ToString().Length, Is.EqualTo(length));
         Assert.That(request.Method, Is.EqualTo(method));
         Assert.That(request.Headers.Contains("X-HTTP-Method-Override"), Is.False);
         Assert.That(request.Content, Is.Null);
         Assert.That(request.RequestUri, Is.EqualTo(new Uri(requestUri)));
     }
 }
        public ConfigurableHttpClient CreateHttpClient(CreateHttpClientArgs args)
        {
            // Create the handler.
            var handler = CreateHandler(args);
            var configurableHandler = new ConfigurableMessageHandler(handler)
                {
                    ApplicationName = args.ApplicationName
                };

            // Create the client.
            var client = new ConfigurableHttpClient(configurableHandler);
            foreach (var initializer in args.Initializers)
            {
                initializer.Initialize(client);
            }

            return client;
        }
        public ConfigurableHttpClient CreateHttpClient(CreateHttpClientArgs args)
        {
            // Create the handler.
            var handler             = CreateHandler(args);
            var configurableHandler = new ConfigurableMessageHandler(handler)
            {
                ApplicationName = args.ApplicationName
            };

            // Create the client.
            var client = new ConfigurableHttpClient(configurableHandler);

            foreach (var initializer in args.Initializers)
            {
                initializer.Initialize(client);
            }

            return(client);
        }
        public void SendAsync_ThrowException_WithoutExceptionHandler()
        {
            var handler = new ExceptionMessageHandler { ThrowException = true };

            var configurableHanlder = new ConfigurableMessageHandler(handler);

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-exception-handler");
                try
                {
                    HttpResponseMessage response = client.SendAsync(request).Result;
                    Assert.Fail("SendAsync should throw an exception");
                }
                catch (AggregateException ae)
                {
                    Assert.That(ae.InnerException.Message, Is.EqualTo(ExceptionMessageHandler.ExceptionMessage));
                }
                catch (Exception)
                {
                    Assert.Fail("AggregateException was suppose to be thrown");
                }
                Assert.That(handler.Calls, Is.EqualTo(1));
            }
        }
        /// <summary>Subtest for exception handler which tests that exception handler is invoked.</summary>
        private void SubtestSendAsyncExceptionHandler(bool throwException, bool handle)
        {
            var handler = new ExceptionMessageHandler { ThrowException = throwException };

            var configurableHanlder = new ConfigurableMessageHandler(handler);
            var exceptionHandler = new ExceptionMessageHandler.ExceptionHandler { Handle = handle };
            configurableHanlder.AddExceptionHandler(exceptionHandler);

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-exception-handler");
                try
                {
                    HttpResponseMessage response = client.SendAsync(request).Result;
                    if (throwException)
                    {
                        Assert.Fail("SendAsync should throw an exception");
                    }
                }
                catch (AggregateException ae)
                {
                    Assert.That(ae.InnerException.Message, Is.EqualTo(ExceptionMessageHandler.ExceptionMessage));
                }

                // if exception is thrown, check if it's handles. if so, there should be num tries calls, otherwise
                // only 1
                if (throwException)
                {
                    Assert.That(exceptionHandler.Calls, Is.EqualTo(handle ? configurableHanlder.NumTries : 1));
                }
                // exception wasn't supposed to be thrown, so no call to exception handler should be made
                else
                {
                    Assert.That(exceptionHandler.Calls, Is.EqualTo(0));
                }

                Assert.That(handler.Calls, Is.EqualTo(throwException & handle ? configurableHanlder.NumTries : 1));
            }
        }
        public void SendAsync_AbnormalResponse_WithoutUnsuccessfulReponseHandler()
        {
            var handler = new UnsuccessfulResponseMessageHandler
                {
                    ResponseStatusCode = HttpStatusCode.ServiceUnavailable
                };

            var configurableHanlder = new ConfigurableMessageHandler(handler);
            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-unsuccessful-handler");

                HttpResponseMessage response = client.SendAsync(request).Result;
                Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.ServiceUnavailable));
                Assert.That(handler.Calls, Is.EqualTo(1));
            }
        }
        /// <summary>Test helper for testing unsuccessful response handlers.</summary>
        private void SubtestSendAsyncUnsuccessfulReponseHanlder(HttpStatusCode code)
        {
            var handler = new UnsuccessfulResponseMessageHandler { ResponseStatusCode = code };

            var configurableHanlder = new ConfigurableMessageHandler(handler);
            var unsuccessfulHandler = new UnsuccessfulResponseMessageHandler.ServiceUnavailableResponseHandler();
            configurableHanlder.AddUnsuccessfulResponseHandler(unsuccessfulHandler);

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-unsuccessful-handler");

                HttpResponseMessage response = client.SendAsync(request).Result;
                Assert.That(response.StatusCode, Is.EqualTo(code));

                // if service unavailable, retry will occur because we plugged unsuccessful response handler which 
                // handles service unavailable responses
                if (code == HttpStatusCode.ServiceUnavailable)
                {
                    Assert.That(unsuccessfulHandler.Calls, Is.EqualTo(configurableHanlder.NumTries));
                    Assert.That(handler.Calls, Is.EqualTo(configurableHanlder.NumTries));
                }
                else
                {
                    // if status is OK, there isn't any call to unsuccessful response handler
                    Assert.That(unsuccessfulHandler.Calls, Is.EqualTo(code != HttpStatusCode.OK ? 1 : 0));
                    Assert.That(handler.Calls, Is.EqualTo(1));
                }
            }
        }
 /// <summary>Constructs a new HTTP client.</summary>
 public ConfigurableHttpClient(ConfigurableMessageHandler handler)
     : base(handler)
 {
     MessageHandler = handler;
     DefaultRequestHeaders.ExpectContinue = false;
 }
        /// <summary>
        /// Tests the retry mechanism. In case the abnormal response is handled, there should be retries, but otherwise
        /// there should not be any retry.
        /// </summary>
        /// <param name="numTries"></param>
        /// <param name="handle"></param>
        private void SubtestSendAsyncNumTries(int numTries, bool handle = true)
        {
            var handler = new UnsuccessfulResponseMessageHandler
                {
                    ResponseStatusCode = HttpStatusCode.ServiceUnavailable
                };
            var configurableHanlder = new ConfigurableMessageHandler(handler)
                {
                    NumTries = numTries
                };
            if (handle)
            {
                var unsuccessfulHandler = new UnsuccessfulResponseMessageHandler.ServiceUnavailableResponseHandler();
                configurableHanlder.AddUnsuccessfulResponseHandler(unsuccessfulHandler);
            }

            using (var client = new HttpClient(configurableHanlder))
            {
                client.GetAsync("http://num-retres");
                Assert.That(handler.Calls, Is.EqualTo(handle ? numTries : 1));
            }
        }
        /// <summary>Tests that retry works with different kind of contents (String, Stream and ByteArray).</summary>
        private void SubtestSendAsyncRetryContent(ContentType type)
        {
            var content = "test-content";
            var contentHandler = new ContentMessageHandler();
            var configurableHanlder = new ConfigurableMessageHandler(contentHandler)
                {
                    NumTries = 10
                };
            configurableHanlder.AddUnsuccessfulResponseHandler(new TrueUnsuccessfulResponseHandler());
            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Put, "https://test-unsuccessful-handler");
                // set the right content
                switch (type)
                {
                    case ContentType.String:
                        request.Content = new StringContent(content);
                        break;
                    case ContentType.Stream:
                        {
                            var stream = new MemoryStream();
                            var buffer = Encoding.UTF8.GetBytes(content);
                            stream.Write(buffer, 0, buffer.Length);
                            stream.Position = 0;
                            request.Content = new StreamContent(stream);
                        }
                        break;
                    case ContentType.ByteArray:
                        request.Content = new ByteArrayContent(Encoding.UTF8.GetBytes(content));
                        break;
                }

                HttpResponseMessage response = client.SendAsync(request).Result;
                Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
                Assert.That(contentHandler.Calls, Is.EqualTo(ContentMessageHandler.NumFails));
                Assert.That(contentHandler.ReadContent, Is.EqualTo(content));
            }
        }
        public void SendAsync_Redirect()
        {
            var location = "https://google.com";
            var redirectHandler = new RedirectMessageHandler(location);
            var configurableHanlder = new ConfigurableMessageHandler(redirectHandler)
            {
                NumRedirects = 5
            };

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, location);
                request.Headers.IfModifiedSince = new DateTimeOffset(DateTime.Now);
                request.Headers.IfUnmodifiedSince = new DateTimeOffset(DateTime.Now);
                request.Headers.IfMatch.Add(new EntityTagHeaderValue("\"a\""));
                request.Headers.IfNoneMatch.Add(new EntityTagHeaderValue("\"b\""));

                HttpResponseMessage response = client.SendAsync(request).Result;

                Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Redirect));
                Assert.That(response.Headers.Location, Is.EqualTo(
                    new Uri(location + (configurableHanlder.NumRedirects + 1))));
                Assert.That(redirectHandler.Calls, Is.EqualTo(configurableHanlder.NumRedirects + 1));
            }
        }
        public void SendAsync_UserAgent()
        {
            var apiVersion = string.Format("google-api-dotnet-client/{0} (gzip)", Utilities.GetLibraryVersion());
            const string applicationName = "NO NAME";

            var handler = new MockMessageHandler();
            var configurableHanlder = new ConfigurableMessageHandler(handler);

            using (var client = new HttpClient(configurableHanlder))
            {
                // without application name
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-user-agent");
                HttpResponseMessage response = client.SendAsync(request).Result;
                var userAgent = string.Join(" ", request.Headers.GetValues("User-Agent").ToArray());
                Assert.That(userAgent, Is.EqualTo(apiVersion));

                // with application name
                configurableHanlder.ApplicationName = applicationName;
                request = new HttpRequestMessage(HttpMethod.Get, "https://test-user-agent");
                response = client.SendAsync(request).Result;
                userAgent = string.Join(" ", request.Headers.GetValues("User-Agent").ToArray());
                Assert.That(userAgent, Is.EqualTo(applicationName + " " + apiVersion));
            }
        }
 /// <summary>Constructs a new HTTP client.</summary>
 public ConfigurableHttpClient(ConfigurableMessageHandler handler)
     : base(handler)
 {
     MessageHandler = handler;
     DefaultRequestHeaders.ExpectContinue = false;
 }
 public void TestGetWithUrlTooLongByUserSpecified()
 {
     uint maxUrlLength = 1000;
     var query = "q=" + new String('x', 900) + "&x=" + new String('y', 72);
     var uri = "http://www.example.com/";
     var requestUri = uri + "?" + query;
     var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
     var mockHandler = new MockMessageHandler();
     var handler = new ConfigurableMessageHandler(mockHandler);
     handler.ExecuteInterceptors.Add(new MaxUrlLengthInterceptor(maxUrlLength));
     using (var httpClient = new HttpClient(handler))
     {
         httpClient.SendAsync(request);
         // Confirm the test URI is one character too long
         Assert.That(requestUri.Length, Is.EqualTo(maxUrlLength + 1));
         // Confirm the request was modified correctly:
         Assert.That(request.Method, Is.EqualTo(HttpMethod.Post));
         Assert.That(request.Headers.GetValues("X-HTTP-Method-Override").Single(), Is.EqualTo("GET"));
         Assert.That(request.Content.Headers.ContentType,
             Is.EqualTo(new MediaTypeHeaderValue("application/x-www-form-urlencoded")));
         Assert.That(request.RequestUri, Is.EqualTo(new Uri(uri)));
         Assert.That(mockHandler.RequestContent, Is.EqualTo(query));
     }
 }
 public void TestGetPathQueryWithUrlOkayLengthByDefault()
 {
     uint maxUrlLength = 1000;
     var query = "q=" + new String('x', 1000);
     var uri = "http://www.googleapis.com/language/translate/v2";
     var requestUri = uri + "?" + query;
     var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
     var mockHandler = new MockMessageHandler();
     var handler = new ConfigurableMessageHandler(mockHandler);
     handler.AddExecuteInterceptor(new MaxUrlLengthInterceptor(maxUrlLength));
     using (var httpClient = new HttpClient(handler))
     {
         httpClient.SendAsync(request);
         // Confirm the request was modified correctly, and the uri was set correctly.
         Assert.That(request.RequestUri, Is.EqualTo(new Uri(uri)));
         Assert.That(mockHandler.RequestContent, Is.EqualTo(query));
     }
 }
        /// <summary>Subtest that back-off handler works as expected when exception is or isn't thrown.</summary>
        private void SubtestSendAsync_BackOffExceptionHandler(bool throwException,
            BackOffHandler.Initializer initializer, Exception exceptionToThrow = null)
        {
            var handler = new ExceptionMessageHandler { ThrowException = throwException };
            if (exceptionToThrow != null)
            {
                handler.Exception = exceptionToThrow;
            }

            var configurableHanlder = new ConfigurableMessageHandler(handler);
            var boHandler = new MockBackOffHandler(initializer);
            configurableHanlder.AddExceptionHandler(boHandler);

            int boHandleCount = 0;
            // if an exception should be thrown and the handler can handle it then calculate the handle count by the 
            // lg(MaxTimeSpan)
            if (throwException && initializer.HandleExceptionFunc(exceptionToThrow))
            {
                boHandleCount = Math.Min((int)Math.Floor(Math.Log(boHandler.MaxTimeSpan.TotalSeconds, 2)) + 1,
                    configurableHanlder.NumTries - 1);
                boHandleCount = boHandleCount >= 0 ? boHandleCount : 0;
            }

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-exception-handler");
                try
                {
                    HttpResponseMessage response = client.SendAsync(request).Result;
                    Assert.False(throwException);
                }
                catch (AggregateException ae)
                {
                    Assert.True(throwException);
                    // Don't compare exception messages because for TaskCanceledException the message
                    // on Mono is different if there is a task associated with the exception.
                    Assert.AreEqual(handler.Exception.GetType(), ae.InnerException.GetType());
                }

                Assert.That(boHandler.Waits.Count, Is.EqualTo(boHandleCount));
                // check the exponential behavior - wait 1, 2, 4, 8, ... seconds.
                if (throwException)
                {
                    for (int i = 0; i < boHandler.Waits.Count; ++i)
                    {
                        Assert.That(boHandler.Waits[i].TotalSeconds, Is.EqualTo((int)Math.Pow(2, i)));
                    }
                }
                Assert.That(handler.Calls, Is.EqualTo(boHandleCount + 1));
            }
        }
        /// <summary>
        /// Subtest that back-off handler works as expected when a successful or abnormal response is returned.
        /// For testing the back-off handler in case of a canceled request, set the <code>cancelRequestNum</code>
        /// parameter to the index of the request you want to cancel.
        /// </summary>
        private void SubtestSendAsync_BackOffUnsuccessfulResponseHandler(HttpStatusCode statusCode,
            BackOffHandler.Initializer initializer, int cancelRequestNum = 0, int numTries = 10)
        {
            var handler = new UnsuccessfulResponseMessageHandler { ResponseStatusCode = statusCode };

            CancellationToken cancellationToken = CancellationToken.None;
            bool cancel = cancelRequestNum > 0;

            if (cancel)
            {
                CancellationTokenSource tcs = new CancellationTokenSource();
                handler.CancellationTokenSource = tcs;
                handler.CancelRequestNum = cancelRequestNum;
                cancellationToken = tcs.Token;
            }

            var configurableHanlder = new ConfigurableMessageHandler(handler)
                {
                    NumTries = numTries
                };
            var boHandler = new MockBackOffHandler(initializer);
            configurableHanlder.AddUnsuccessfulResponseHandler(boHandler);

            int boHandleCount = 0;
            if (initializer.HandleUnsuccessfulResponseFunc != null &&
                initializer.HandleUnsuccessfulResponseFunc(new HttpResponseMessage { StatusCode = statusCode }))
            {
                boHandleCount = Math.Min((int)Math.Floor(Math.Log(boHandler.MaxTimeSpan.TotalSeconds, 2)) + 1,
                    configurableHanlder.NumTries - 1);
                boHandleCount = boHandleCount >= 0 ? boHandleCount : 0;
                if (cancel)
                {
                    boHandleCount = Math.Min(boHandleCount, cancelRequestNum);
                }
            }

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-exception-handler");
                try
                {
                    HttpResponseMessage response = client.SendAsync(request, cancellationToken).Result;
                    Assert.False(cancel);
                }
                catch (AggregateException ae)
                {
                    // a canceled request should throw an exception
                    Assert.IsInstanceOf<TaskCanceledException>(ae.InnerException);
                    Assert.True(cancel);
                }

                Assert.That(boHandler.Waits.Count, Is.EqualTo(boHandleCount));

                // check the exponential behavior - wait 1, 2, 4, 8, ... seconds.
                for (int i = 0; i < boHandler.Waits.Count; ++i)
                {
                    Assert.That(boHandler.Waits[i].TotalSeconds, Is.EqualTo((int)Math.Pow(2, i)));
                }

                // if the request was canceled the number of calls to the message handler is equal to the number of 
                // calls to back-off handler
                Assert.That(handler.Calls, Is.EqualTo(boHandleCount + (cancel ? 0 : 1)));
            }
        }
        public void SendAsync_Redirect_FollowRedirectFalse()
        {
            const int tries = 12;
            var location = "https://google.com";
            var redirectHandler = new RedirectMessageHandler(location);
            var configurableHanlder = new ConfigurableMessageHandler(redirectHandler)
            {
                NumRedirects = tries,
                FollowRedirect = false
            };

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, location);
                request.Headers.IfModifiedSince = new DateTimeOffset(DateTime.Now);
                request.Headers.IfUnmodifiedSince = new DateTimeOffset(DateTime.Now);
                request.Headers.IfMatch.Add(new EntityTagHeaderValue("\"a\""));
                request.Headers.IfNoneMatch.Add(new EntityTagHeaderValue("\"b\""));

                HttpResponseMessage response = client.SendAsync(request).Result;

                // there should be only one request because follow redirect is false
                Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Redirect));
                Assert.That(response.Headers.Location, Is.EqualTo(new Uri(location + 1)));
                Assert.That(redirectHandler.Calls, Is.EqualTo(1));
            }
        }
        public void NumTries_Setter()
        {
            var configurableHanlder = new ConfigurableMessageHandler(new HttpClientHandler());

            // valid values
            configurableHanlder.NumTries = ConfigurableMessageHandler.MaxAllowedNumTries;
            configurableHanlder.NumTries = ConfigurableMessageHandler.MaxAllowedNumTries - 1;
            configurableHanlder.NumTries = 1;

            // test invalid values
            try
            {
                configurableHanlder.NumTries = ConfigurableMessageHandler.MaxAllowedNumTries + 1;
                Assert.Fail();
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Assert.True(ex.Message.Contains("Parameter name: NumTries"));
            }
            try
            {
                configurableHanlder.NumTries = 0;
                Assert.Fail();
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Assert.True(ex.Message.Contains("Parameter name: NumTries"));
            }
            try
            {
                configurableHanlder.NumTries = -2;
                Assert.Fail();
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Assert.True(ex.Message.Contains("Parameter name: NumTries"));
            }
        }
        /// <summary>Tests that execute interceptor is called.</summary>
        private void SubtestSendAsyncExecuteInterceptor(HttpStatusCode code)
        {
            var handler = new InterceptorMessageHandler();
            handler.InjectedResponseMessage = new HttpResponseMessage()
                {
                    StatusCode = code
                };

            var configurableHanlder = new ConfigurableMessageHandler(handler);
            var interceptor = new InterceptorMessageHandler.Interceptor();
            configurableHanlder.AddExecuteInterceptor(interceptor);

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-execute-interceptor");

                HttpResponseMessage response = client.SendAsync(request).Result;
                Assert.That(interceptor.Calls, Is.EqualTo(1));
                Assert.That(handler.Calls, Is.EqualTo(1));
            }
        }
        public void SendAsync_ExecuteInterceptor_AbnormalResponse_UnsuccessfulResponseHandler()
        {
            var handler = new InterceptorMessageHandler();
            handler.InjectedResponseMessage = new HttpResponseMessage()
                {
                    StatusCode = HttpStatusCode.ServiceUnavailable
                };

            var configurableHanlder = new ConfigurableMessageHandler(handler);
            var interceptor = new InterceptorMessageHandler.Interceptor();
            configurableHanlder.AddExecuteInterceptor(interceptor);
            configurableHanlder.AddUnsuccessfulResponseHandler(new TrueUnsuccessfulResponseHandler());

            using (var client = new HttpClient(configurableHanlder))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, "https://test-execute-interceptor");

                HttpResponseMessage response = client.SendAsync(request).Result;
                Assert.That(interceptor.Calls, Is.EqualTo(configurableHanlder.NumTries));
                Assert.That(handler.Calls, Is.EqualTo(configurableHanlder.NumTries));
            }
        }
 /// <summary>Constructs a new HTTP client.</summary>
 /// <remarks>This is equivalent to calling <code>ConfigurableHttpClient(handler, true)</code></remarks>
 public ConfigurableHttpClient(ConfigurableMessageHandler handler)
     : this(handler, true)
 {
 }