/// <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) { }