/test/System.Web.Http.WebHost.Test/HttpControllerHandlerTest.cs
C# | 2119 lines | 1600 code | 325 blank | 194 comment | 84 complexity | b4eab9694b6c24e48ca5e40a68bb6289 MD5 | raw file
Possible License(s): Apache-2.0
Large files files are truncated, but you can click here to view the full file
- // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Diagnostics.Contracts;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Net.Http.Formatting;
- using System.Net.Http.Headers;
- using System.Reflection;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Web.Http.Controllers;
- using System.Web.Http.ExceptionHandling;
- using System.Web.Http.Hosting;
- using System.Web.Http.Results;
- using System.Web.Http.WebHost.Routing;
- using System.Web.Routing;
- using Microsoft.TestCommon;
- using Moq;
- using Newtonsoft.Json.Linq;
- namespace System.Web.Http.WebHost
- {
- public class HttpControllerHandlerTest
- {
- public static TheoryDataSet<HttpMethod> AllHttpMethods
- {
- get
- {
- return new TheoryDataSet<HttpMethod>
- {
- HttpMethod.Get,
- HttpMethod.Post,
- HttpMethod.Put,
- HttpMethod.Delete,
- HttpMethod.Head,
- HttpMethod.Options,
- HttpMethod.Trace
- };
- }
- }
- public static TheoryDataSet<HttpMethod> HttpMethodsWithContent
- {
- get
- {
- return new TheoryDataSet<HttpMethod>
- {
- HttpMethod.Post,
- HttpMethod.Put,
- HttpMethod.Delete,
- };
- }
- }
- [Theory]
- [PropertyData("AllHttpMethods")]
- public void ConvertRequest_Creates_HttpRequestMessage_For_All_HttpMethods(HttpMethod httpMethod)
- {
- // Arrange
- HttpContextBase contextBase = CreateStubContextBase(httpMethod.Method, new MemoryStream());
- // Act
- HttpRequestMessage request = HttpControllerHandler.ConvertRequest(contextBase);
- // Assert
- Assert.Equal(httpMethod, request.Method);
- }
- [Fact]
- public void ConvertRequest_Copies_Headers_And_Content_Headers()
- {
- // Arrange
- HttpContextBase contextBase = CreateStubContextBase("Get", new MemoryStream());
- HttpRequestBase requestBase = contextBase.Request;
- NameValueCollection nameValues = requestBase.Headers;
- nameValues["myHeader"] = "myValue";
- nameValues["Content-Type"] = "application/mine";
- // Act
- HttpRequestMessage request = HttpControllerHandler.ConvertRequest(contextBase);
- string[] headerValues = request.Headers.GetValues("myHeader").ToArray();
- // Assert
- Assert.Equal("myValue", headerValues[0]);
- Assert.Equal("application/mine", request.Content.Headers.ContentType.MediaType);
- }
- [Theory]
- [PropertyData("HttpMethodsWithContent")]
- public void ConvertRequest_Creates_Request_With_Content_For_Content_Methods(HttpMethod httpMethod)
- {
- // Arrange
- HttpContextBase contextBase = CreateStubContextBase(httpMethod.Method, new MemoryStream());
- // Act
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(contextBase);
- // Assert
- Assert.NotNull(actualRequest.Content);
- }
- [Fact]
- public void ConvertRequest_Uses_HostBufferPolicySelector_To_Select_Buffered_Stream()
- {
- // Arrange
- HttpContextBase contextMock = CreateStubContextBase("Post", new MemoryStream(new byte[] { 5 }));
- MemoryStream memoryStream = new MemoryStream();
- // Act
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(contextMock);
- actualRequest.Content.CopyToAsync(memoryStream).Wait();
- byte[] actualBuffer = memoryStream.GetBuffer();
- // Assert
- Assert.Equal(5, actualBuffer[0]);
- }
- [Fact]
- public void ConvertRequest_AddsOwinEnvironment_WhenPresentInHttpContext()
- {
- // Arrange
- using (MemoryStream ignoreStream = new MemoryStream())
- {
- HttpRequestBase stubRequest = CreateStubRequestBase("IgnoreMethod", ignoreStream);
- IDictionary<string, object> expectedEnvironment = new Dictionary<string, object>();
- IDictionary items = new Hashtable();
- items.Add(HttpControllerHandler.OwinEnvironmentHttpContextKey, expectedEnvironment);
- HttpContextBase context = CreateStubContextBase(stubRequest, items);
- // Act
- using (HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context))
- {
- IDictionary<string, object> environment = actualRequest.GetOwinEnvironment();
- // Assert
- Assert.Same(expectedEnvironment, environment);
- }
- }
- }
- [Fact]
- public void ConvertRequest_DoesNotAddOwinEnvironment_WhenNotPresentInHttpContext()
- {
- // Arrange
- using (MemoryStream ignoreStream = new MemoryStream())
- {
- HttpRequestBase stubRequest = CreateStubRequestBase("IgnoreMethod", ignoreStream);
- IDictionary items = new Hashtable();
- HttpContextBase context = CreateStubContextBase(stubRequest, items);
- // Act
- using (HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context))
- {
- // Assert
- object ignore;
- bool found = actualRequest.Properties.TryGetValue(HttpControllerHandler.OwinEnvironmentKey,
- out ignore);
- Assert.False(found);
- }
- }
- }
- [Fact]
- public void ConvertRequest_DoesNotAddOwinEnvironment_WhenItemsIsNull()
- {
- // Arrange
- using (MemoryStream ignoreStream = new MemoryStream())
- {
- HttpRequestBase stubRequest = CreateStubRequestBase("IgnoreMethod", ignoreStream);
- IDictionary items = null;
- HttpContextBase context = CreateStubContextBase(stubRequest, items);
- // Act
- using (HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context))
- {
- // Assert
- object ignore;
- bool found = actualRequest.Properties.TryGetValue(HttpControllerHandler.OwinEnvironmentKey,
- out ignore);
- Assert.False(found);
- }
- }
- }
- [Fact]
- public void ConvertRequest_DoesLazyGetInputStream()
- {
- bool inputStreamCalled = false;
- HttpRequestBase stubRequest = CreateFakeRequestBase(() =>
- {
- inputStreamCalled = true;
- return new MemoryStream();
- }, buffered: true);
- HttpContextBase context = CreateStubContextBase(request: stubRequest, items: null);
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context);
- Assert.False(inputStreamCalled);
- var contentStream = actualRequest.Content.ReadAsStreamAsync().Result;
- Assert.True(inputStreamCalled);
- }
- [Fact]
- public void ConvertRequest_UsesRequestInputStream_InClassicMode()
- {
- // Arrange
- string input = "Hello world";
- var stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
- HttpRequestBase fakeRequest = CreateFakeRequestBase(() => stream, buffered: true);
- HttpContextBase context = CreateStubContextBase(request: fakeRequest, items: null);
- Mock<HttpRequestBase> mockRequest = Mock.Get<HttpRequestBase>(fakeRequest);
- // Act
- fakeRequest.InputStream.Position = 10;
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context);
- string result = actualRequest.Content.ReadAsStringAsync().Result;
- // Assert
- // Verify that the InputStream was reset when reading the content.
- Assert.Equal(input, result);
- mockRequest.Verify(r => r.InputStream, Times.AtLeastOnce());
- mockRequest.Verify(r => r.GetBufferedInputStream(), Times.Never());
- }
- [Fact]
- public void ConvertRequest_UsesBufferedInputStream_IfReadEntityBodyModeIsNone()
- {
- // Arrange
- HttpRequestBase stubRequest = CreateFakeRequestBase(() => new MemoryStream(), buffered: true);
- HttpContextBase context = CreateStubContextBase(request: stubRequest, items: null);
- Mock<HttpRequestBase> mockRequest = Mock.Get<HttpRequestBase>(stubRequest);
- // Act
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context);
- actualRequest.Content.ReadAsStreamAsync().Wait();
- // Assert
- mockRequest.Verify(r => r.InputStream, Times.Never());
- mockRequest.Verify(r => r.GetBufferedInputStream(), Times.AtLeastOnce());
- }
- [Fact]
- public void ConvertRequest_WithBufferedPolicy_ThrowsIfRequestHasBeenPartiallyRead()
- {
- // Arrange
- var stream = new MemoryStream(new byte[16]);
- HttpRequestBase fakeRequest = CreateFakeRequestBase(() => stream, buffered: true);
- HttpContextBase context = CreateStubContextBase(request: fakeRequest, items: null);
- // Act
- fakeRequest.GetBufferedInputStream().Position = 4;
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context);
- // Assert
- Assert.Throws<InvalidOperationException>(() => actualRequest.Content.ReadAsStringAsync().Result);
- }
- [Fact]
- public void ConvertRequest_WithBufferedPolicy_ReturnsInputStreamIfBufferedStreamWasFullyRead()
- {
- // Arrange
- string inputStreamMessage = "This is from input stream";
- var bufferedStream = new MemoryStream(new byte[16]);
- var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(inputStreamMessage));
- HttpRequestBase fakeRequest = CreateFakeRequestBase(() => bufferedStream, buffered: true);
- HttpContextBase context = CreateStubContextBase(request: fakeRequest, items: null);
- Mock<HttpRequestBase> mockRequest = Mock.Get<HttpRequestBase>(fakeRequest);
- mockRequest.SetupGet(f => f.InputStream)
- .Returns(inputStream)
- .Verifiable();
- // Act
- bufferedStream.Seek(0, SeekOrigin.End);
- new StreamReader(fakeRequest.GetBufferedInputStream()).ReadToEnd();
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context);
- string result = actualRequest.Content.ReadAsStringAsync().Result;
- // Assert
- Assert.Equal(inputStreamMessage, result);
- }
- [Theory]
- [InlineData(ReadEntityBodyMode.None)]
- [InlineData(ReadEntityBodyMode.Bufferless)]
- public void ConvertRequest_DoesLazyGetBufferlessInputStream_IfRequestStreamHasNotBeenRead(ReadEntityBodyMode readEntityBodyMode)
- {
- // Arrange
- bool inputStreamCalled = false;
- var hostBufferPolicy = new Mock<IHostBufferPolicySelector>();
- hostBufferPolicy.Setup(c => c.UseBufferedInputStream(It.IsAny<object>()))
- .Returns(false);
- hostBufferPolicy.Setup(c => c.UseBufferedOutputStream(It.IsAny<HttpResponseMessage>()))
- .Returns(true);
- HttpRequestBase stubRequest = CreateFakeRequestBase(() =>
- {
- inputStreamCalled = true;
- return new MemoryStream();
- }, buffered: false);
- HttpContextBase context = HttpControllerHandlerTest.CreateStubContextBase(request: stubRequest, items: null);
- // Act
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context, hostBufferPolicy.Object);
- // Assert
- Assert.False(inputStreamCalled);
- Stream contentStream = actualRequest.Content.ReadAsStreamAsync().Result;
- Assert.True(inputStreamCalled);
- }
- [Fact]
- public void ConvertRequest_WithBufferlessPolicy_ThrowsIfRequestStreamHasBeenReadInClassicMode()
- {
- // Arrange
- var hostBufferPolicy = new Mock<IHostBufferPolicySelector>();
- hostBufferPolicy.Setup(c => c.UseBufferedInputStream(It.IsAny<object>()))
- .Returns(false);
- hostBufferPolicy.Setup(c => c.UseBufferedOutputStream(It.IsAny<HttpResponseMessage>()))
- .Returns(true);
- var stream = new MemoryStream(8);
- HttpRequestBase stubRequest = CreateFakeRequestBase(() => stream, buffered: false);
- HttpContextBase context = HttpControllerHandlerTest.CreateStubContextBase(request: stubRequest, items: null);
- // Act
- context.Request.InputStream.Position = 2;
- HttpRequestMessage actualRequest = HttpControllerHandler.ConvertRequest(context, hostBufferPolicy.Object);
- // Assert
- Assert.Throws<InvalidOperationException>(() => actualRequest.Content.ReadAsStreamAsync().Result,
- "Unable to read the entity body in Bufferless mode. The request stream has already been buffered.");
- }
- [Fact]
- public void ConvertRequest_WithBufferlessPolicy_ThrowsIfRequestStreamHasBeenReadInBufferedMode()
- {
- // Arrange
- var hostBufferPolicy = new Mock<IHostBufferPolicySelector>();
- hostBufferPolicy.Setup(c => c.UseBufferedInputStream(It.IsAny<object>()))
- .Returns(false);
- hostBufferPolicy.Setup(c => c.UseBufferedOutputStream(It.IsAny<HttpResponseMessage>()))
- .Returns(true);
- var stream = new MemoryStream(8);
- HttpRequestBase stubRequest = CreateFakeRequestBase(() => stream, buffered: false);
- HttpContextBase context = HttpControllerHandlerTest.CreateStubContextBase(request: stubRequest, items: null);
- // Act
- context.Request.GetBufferedInputStream();
- HttpRequestMessage message = HttpControllerHandler.ConvertRequest(context, hostBufferPolicy.Object);
- // Assert
- Assert.Throws<InvalidOperationException>(() => message.Content.ReadAsStringAsync().Result,
- "Unable to read the entity body. The request stream has already been read in 'Buffered' mode.");
- }
- [Fact]
- public void ConvertRequest_WithBufferlessPolicy_ThrowsIfRequestStreamHasBeenRead()
- {
- // Arrange
- var hostBufferPolicy = new Mock<IHostBufferPolicySelector>();
- hostBufferPolicy.Setup(c => c.UseBufferedInputStream(It.IsAny<object>()))
- .Returns(false);
- hostBufferPolicy.Setup(c => c.UseBufferedOutputStream(It.IsAny<HttpResponseMessage>()))
- .Returns(true);
- var stream = new MemoryStream(new byte[16]);
- HttpRequestBase stubRequest = CreateFakeRequestBase(() => stream, buffered: false);
- HttpContextBase context = HttpControllerHandlerTest.CreateStubContextBase(request: stubRequest, items: null);
- // Act
- context.Request.GetBufferlessInputStream().Position = 4;
- HttpRequestMessage message = HttpControllerHandler.ConvertRequest(context, hostBufferPolicy.Object);
- // Assert
- Assert.Throws<InvalidOperationException>(() => message.Content.ReadAsStringAsync().Result,
- "Unable to read the entity body. A portion of the request stream has already been read.");
- }
- [Fact]
- public void ConvertRequest_AddsWebHostHttpRequestContext()
- {
- // Arrange
- Mock<HttpRequestBase> requestBaseMock = new Mock<HttpRequestBase>(MockBehavior.Strict);
- requestBaseMock.Setup(r => r.HttpMethod).Returns("IGNORED");
- requestBaseMock.Setup(r => r.Url).Returns(new Uri("http://ignore"));
- requestBaseMock.Setup(r => r.Headers).Returns(new NameValueCollection());
- requestBaseMock.Setup(r => r.ReadEntityBodyMode).Returns(ReadEntityBodyMode.None);
- HttpRequestBase requestBase = requestBaseMock.Object;
- Mock<HttpContextBase> contextBaseMock = new Mock<HttpContextBase>(MockBehavior.Strict);
- contextBaseMock.Setup(c => c.Request).Returns(requestBase);
- contextBaseMock.Setup(c => c.Items).Returns((IDictionary)null);
- HttpContextBase contextBase = contextBaseMock.Object;
- // Act
- using (HttpRequestMessage expectedRequest = HttpControllerHandler.ConvertRequest(contextBase))
- {
- // Assert
- HttpRequestContext context = expectedRequest.GetRequestContext();
- Assert.IsType<WebHostHttpRequestContext>(context);
- WebHostHttpRequestContext typedContext = (WebHostHttpRequestContext)context;
- Assert.Same(contextBase, typedContext.Context);
- Assert.Same(requestBase, typedContext.WebRequest);
- Assert.Same(expectedRequest, typedContext.Request);
- }
- }
- [Fact]
- public void CopyResponseAsync_IfResponseHasNoCacheControlDefined_SetsNoCacheCacheabilityOnAspNetResponse()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- HttpRequestMessage request = new HttpRequestMessage();
- HttpResponseMessage response = new HttpResponseMessage();
- // Act
- CopyResponseAsync(contextMock.Object, request, response).Wait();
- // Assert
- contextMock.Verify(c => c.Response.Cache.SetCacheability(HttpCacheability.NoCache));
- }
- [Fact]
- public void CopyResponseAsync_IfResponseHasCacheControlDefined_DoesNotSetCacheCacheabilityOnAspNetResponse()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- HttpRequestMessage request = new HttpRequestMessage();
- HttpResponseMessage response = new HttpResponseMessage();
- response.Headers.CacheControl = new CacheControlHeaderValue { Public = true };
- // Act
- CopyResponseAsync(contextMock.Object, request, response).Wait();
- // Assert
- contextMock.Verify(c => c.Response.Cache.SetCacheability(HttpCacheability.NoCache), Times.Never());
- }
- [Fact]
- public Task ProcessRequestAsync_DisposesRequestAndResponse()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- contextMock.SetupGet((hcb) => hcb.Response.OutputStream).Returns(Stream.Null);
- IDictionary items = new Dictionary<object, object>();
- contextMock.SetupGet((hcb) => hcb.Items).Returns(items);
- HttpContextBase context = contextMock.Object;
- HttpRequestMessage request = new HttpRequestMessage();
- context.SetHttpRequestMessage(request);
- SpyDisposable spy = new SpyDisposable();
- request.RegisterForDispose(spy);
- HttpResponseMessage response = new HttpResponseMessage();
- Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsync = (r, c) =>
- Task.FromResult(response);
- using (HttpMessageHandler handler = new LambdaHttpMessageHandler(sendAsync))
- {
- HttpControllerHandler product = new HttpControllerHandler(
- new Mock<RouteData>(MockBehavior.Strict).Object, handler);
- // Act
- return product.ProcessRequestAsyncCore(context).ContinueWith(
- _ =>
- {
- // Assert
- Assert.True(spy.Disposed);
- Assert.ThrowsObjectDisposed(() => request.Method = HttpMethod.Get, typeof(HttpRequestMessage).FullName);
- Assert.ThrowsObjectDisposed(() => response.StatusCode = HttpStatusCode.OK, typeof(HttpResponseMessage).FullName);
- });
- }
- }
- [Fact]
- public Task ProcessRequestAsync_DisposesRequestAndResponseWithContent()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- contextMock.SetupGet((hcb) => hcb.Response.OutputStream).Returns(Stream.Null);
- IDictionary items = new Dictionary<object, object>();
- contextMock.SetupGet((hcb) => hcb.Items).Returns(items);
- HttpContextBase context = contextMock.Object;
- HttpRequestMessage request = new HttpRequestMessage() { Content = new StringContent("request") };
- context.SetHttpRequestMessage(request);
- SpyDisposable spy = new SpyDisposable();
- request.RegisterForDispose(spy);
- HttpResponseMessage response = new HttpResponseMessage() { Content = new StringContent("response") };
- Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsync = (r, c) =>
- Task.FromResult(response);
- using (HttpMessageHandler handler = new LambdaHttpMessageHandler(sendAsync))
- {
- HttpControllerHandler product = new HttpControllerHandler(
- new Mock<RouteData>(MockBehavior.Strict).Object, handler);
- // Act
- return product.ProcessRequestAsyncCore(context).ContinueWith(
- _ =>
- {
- // Assert
- Assert.True(spy.Disposed);
- Assert.ThrowsObjectDisposed(() => request.Method = HttpMethod.Get, typeof(HttpRequestMessage).FullName);
- Assert.ThrowsObjectDisposed(() => response.StatusCode = HttpStatusCode.OK, typeof(HttpResponseMessage).FullName);
- });
- }
- }
- [Fact]
- public Task ProcessRequestAsync_IfHandlerFaults_DisposesRequest()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- contextMock.SetupGet((hcb) => hcb.Response.OutputStream).Returns(Stream.Null);
- IDictionary items = new Dictionary<object, object>();
- contextMock.SetupGet((hcb) => hcb.Items).Returns(items);
- HttpContextBase context = contextMock.Object;
- HttpRequestMessage request = new HttpRequestMessage();
- context.SetHttpRequestMessage(request);
- SpyDisposable spy = new SpyDisposable();
- request.RegisterForDispose(spy);
- Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsync = (r, c) =>
- CreateFaultedTask<HttpResponseMessage>(CreateException());
- using (HttpMessageHandler handler = new LambdaHttpMessageHandler(sendAsync))
- {
- HttpControllerHandler product = new HttpControllerHandler(
- new Mock<RouteData>(MockBehavior.Strict).Object, handler);
- // Act
- return product.ProcessRequestAsyncCore(context).ContinueWith(
- _ =>
- {
- // Assert
- Assert.True(spy.Disposed);
- Assert.ThrowsObjectDisposed(() => request.Method = HttpMethod.Get, typeof(HttpRequestMessage).FullName);
- });
- }
- }
- [Fact]
- public void SuppressFormsAuthenticationRedirect_DoesntRequireSuppressRedirect()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- IDictionary contextItems = new Hashtable();
- contextMock.SetupGet(hcb => hcb.Response.StatusCode).Returns(200);
- contextMock.SetupGet(hcb => hcb.Items).Returns(contextItems);
- // Act
- HttpControllerHandler.EnsureSuppressFormsAuthenticationRedirect(contextMock.Object);
- // Assert
- Assert.False(contextMock.Object.Response.SuppressFormsAuthenticationRedirect);
- }
- [Fact]
- public void SuppressFormsAuthenticationRedirect_RequireSuppressRedirect()
- {
- // Arrange
- Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>() { DefaultValue = DefaultValue.Mock };
- IDictionary contextItems = new Hashtable();
- contextMock.SetupGet(hcb => hcb.Response.StatusCode).Returns(401);
- contextMock.SetupGet(hcb => hcb.Items).Returns(contextItems);
- // Act
- HttpControllerHandler.EnsureSuppressFormsAuthenticationRedirect(contextMock.Object);
- // Assert
- Assert.True(contextMock.Object.Response.SuppressFormsAuthenticationRedirect);
- }
- [Fact]
- public void CopyResponseAsync_Creates_Correct_HttpResponseBase()
- {
- // Arrange
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", new JsonMediaTypeFormatter());
- // Act
- Task task = CopyResponseAsync(contextMock.Object, request, response);
- task.Wait();
- // Assert preparation -- deserialize the response
- memoryStream.Seek(0L, SeekOrigin.Begin);
- string responseString = null;
- using (var streamReader = new StreamReader(memoryStream))
- {
- responseString = streamReader.ReadToEnd();
- }
- // Assert
- Assert.Equal<int>((int)HttpStatusCode.OK, responseBase.StatusCode);
- Assert.True(responseBase.Headers["Content-Type"].StartsWith(JsonMediaTypeFormatter.DefaultMediaType.MediaType));
- Assert.Equal("\"hello\"", responseString);
- }
- [Fact]
- public void CopyResponseAsync_IfTransferEncodingChunkedAndContentLengthAreBothSet_IgnoresContentLength()
- {
- // Arrange
- HttpResponseBase responseBase = CreateMockHttpResponseBaseForResponse(Stream.Null).Object;
- HttpContextBase contextBase = CreateStubContextBase(responseBase);
- using (HttpRequestMessage request = new HttpRequestMessage())
- using (HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request })
- {
- response.Headers.TransferEncodingChunked = true;
- response.Content = new StringContent("SomeContent");
- Assert.NotNull(response.Content.Headers.ContentLength); // Guard; added by System.Net.Http.
- // Act
- Task task = CopyResponseAsync(contextBase, request, response);
- // Assert
- Assert.NotNull(task);
- task.WaitUntilCompleted();
- task.ThrowIfFaulted();
- Assert.DoesNotContain("Content-Length", responseBase.Headers.OfType<string>());
- }
- }
- [Fact]
- public void CopyResponseAsync_IfTransferEncodingIsJustChunked_DoesNotCopyHeaderToHost()
- {
- // Arrange
- HttpResponseBase responseBase = CreateMockHttpResponseBaseForResponse(Stream.Null).Object;
- HttpContextBase contextBase = CreateStubContextBase(responseBase);
- using (HttpRequestMessage request = new HttpRequestMessage())
- using (HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request })
- {
- response.Headers.TransferEncodingChunked = true;
- // Act
- Task task = CopyResponseAsync(contextBase, request, response);
- // Assert
- Assert.NotNull(task);
- task.WaitUntilCompleted();
- task.ThrowIfFaulted();
- Assert.DoesNotContain("Transfer-Encoding", responseBase.Headers.OfType<string>());
- }
- }
- [Fact]
- public void CopyResponseAsync_IfTransferEncodingIsIdentity_CopiesHeaderToHost()
- {
- // Arrange
- HttpResponseBase responseBase = CreateMockHttpResponseBaseForResponse(Stream.Null).Object;
- HttpContextBase contextBase = CreateStubContextBase(responseBase);
- using (HttpRequestMessage request = new HttpRequestMessage())
- using (HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request })
- {
- response.Headers.TransferEncoding.Add(new TransferCodingHeaderValue("identity"));
- // Act
- Task task = CopyResponseAsync(contextBase, request, response);
- // Assert
- Assert.NotNull(task);
- task.WaitUntilCompleted();
- task.ThrowIfFaulted();
- Assert.Contains("Transfer-Encoding", responseBase.Headers.OfType<string>());
- Assert.Equal(new string[] { "identity" }, responseBase.Headers.GetValues("Transfer-Encoding"));
- }
- }
- [Fact]
- public void CopyResponseAsync_IfTransferEncodingIsIdentityChunked_CopiesHeaderToHost()
- {
- // Arrange
- HttpResponseBase responseBase = CreateMockHttpResponseBaseForResponse(Stream.Null).Object;
- HttpContextBase contextBase = CreateStubContextBase(responseBase);
- using (HttpRequestMessage request = new HttpRequestMessage())
- using (HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request })
- {
- response.Headers.TransferEncoding.Add(new TransferCodingHeaderValue("identity"));
- response.Headers.TransferEncodingChunked = true;
- Assert.Equal("identity, chunked", response.Headers.TransferEncoding.ToString()); // Guard
- // Act
- Task task = CopyResponseAsync(contextBase, request, response);
- // Assert
- Assert.NotNull(task);
- task.WaitUntilCompleted();
- task.ThrowIfFaulted();
- Assert.Contains("Transfer-Encoding", responseBase.Headers.OfType<string>());
- Assert.Equal(new string[] { "identity", "chunked" },
- responseBase.Headers.GetValues("Transfer-Encoding"));
- }
- }
- [Fact]
- public void CopyResponseAsync_IfTransferEncodingIsChunked_DisablesResponseBuffering()
- {
- // Arrange
- HttpResponseBase responseBase = CreateMockHttpResponseBaseForResponse(Stream.Null).Object;
- HttpContextBase contextBase = CreateStubContextBase(responseBase);
- using (HttpRequestMessage request = new HttpRequestMessage())
- using (HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request })
- {
- response.Headers.TransferEncodingChunked = true;
- response.Content = new ObjectContent(typeof(string), String.Empty, new JsonMediaTypeFormatter());
- // Act
- Task task = CopyResponseAsync(contextBase, request, response);
- // Assert
- Assert.NotNull(task);
- task.WaitUntilCompleted();
- task.ThrowIfFaulted();
- Assert.False(responseBase.BufferOutput);
- }
- }
- [Fact]
- public void CopyResponseAsync_IfHandlerIsDefault_Returns_Error_Response_When_Formatter_Write_Task_Faults()
- {
- // Arrange
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>() { CallBase = true };
- TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
- try
- {
- // to capture stack trace inside this method
- throw new NotSupportedException("Expected error");
- }
- catch (Exception ex)
- {
- tcs.SetException(ex);
- }
- formatterMock.Setup(m => m.WriteToStreamAsync(It.IsAny<Type>(),
- It.IsAny<object>(),
- It.IsAny<Stream>(),
- It.IsAny<HttpContent>(),
- It.IsAny<TransportContext>())).Returns(tcs.Task);
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- request.SetIsLocal(new Lazy<bool>(() => true));
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", formatterMock.Object);
- IExceptionLogger exceptionLogger = CreateStubExceptionLogger();
- IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(GlobalConfiguration.Configuration);
- // Act
- Task task = HttpControllerHandler.CopyResponseAsync(contextMock.Object, request, response, exceptionLogger,
- exceptionHandler, CancellationToken.None);
- task.Wait();
- // Assert preparation -- deserialize the HttpError response
- HttpError httpError = null;
- memoryStream.Seek(0L, SeekOrigin.Begin);
- using (StreamContent content = new StreamContent(memoryStream))
- {
- content.Headers.ContentType = JsonMediaTypeFormatter.DefaultMediaType;
- httpError = content.ReadAsAsync<HttpError>().Result;
- }
- // Assert
- Assert.Equal<int>((int)HttpStatusCode.InternalServerError, responseBase.StatusCode);
- Assert.True(responseBase.Headers["Content-Type"].StartsWith(JsonMediaTypeFormatter.DefaultMediaType.MediaType));
- Assert.Equal("An error has occurred.", httpError["Message"]);
- Assert.Equal("The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.", httpError["ExceptionMessage"]);
- Assert.Equal(typeof(InvalidOperationException).FullName, httpError["ExceptionType"]);
- Assert.True(httpError.ContainsKey("StackTrace"));
- HttpError innerError = (httpError["InnerException"] as JObject).ToObject<HttpError>();
- Assert.NotNull(innerError);
- Assert.Equal(typeof(NotSupportedException).FullName, innerError["ExceptionType"].ToString());
- Assert.Equal("Expected error", innerError["ExceptionMessage"]);
- Assert.Contains(MethodInfo.GetCurrentMethod().Name, innerError["StackTrace"].ToString());
- }
- [Fact]
- public void CopyResponseAsync_IfHandlerIsDefault_Returns_Error_Response_When_Formatter_Write_Throws_Immediately()
- {
- // Arrange
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>() { CallBase = true };
- formatterMock.Setup(m => m.WriteToStreamAsync(It.IsAny<Type>(),
- It.IsAny<object>(),
- It.IsAny<Stream>(),
- It.IsAny<HttpContent>(),
- It.IsAny<TransportContext>())).Throws(new NotSupportedException("Expected error"));
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- request.SetIsLocal(new Lazy<bool>(() => true));
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", formatterMock.Object);
- IExceptionLogger exceptionLogger = CreateStubExceptionLogger();
- IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(GlobalConfiguration.Configuration);
- // Act
- Task task = HttpControllerHandler.CopyResponseAsync(contextMock.Object, request, response, exceptionLogger, exceptionHandler, CancellationToken.None);
- task.Wait();
- // Assert preparation -- deserialize the HttpError response
- HttpError httpError = null;
- memoryStream.Seek(0L, SeekOrigin.Begin);
- using (StreamContent content = new StreamContent(memoryStream))
- {
- content.Headers.ContentType = JsonMediaTypeFormatter.DefaultMediaType;
- httpError = content.ReadAsAsync<HttpError>().Result;
- }
- // Assert
- Assert.Equal<int>((int)HttpStatusCode.InternalServerError, responseBase.StatusCode);
- Assert.True(responseBase.Headers["Content-Type"].StartsWith(JsonMediaTypeFormatter.DefaultMediaType.MediaType));
- Assert.Equal("An error has occurred.", httpError["Message"]);
- Assert.Equal("The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.", httpError["ExceptionMessage"]);
- Assert.Equal(typeof(InvalidOperationException).FullName, httpError["ExceptionType"]);
- Assert.True(httpError.ContainsKey("StackTrace"));
- HttpError innerError = (httpError["InnerException"] as JObject).ToObject<HttpError>();
- Assert.NotNull(innerError);
- Assert.Equal(typeof(NotSupportedException).FullName, innerError["ExceptionType"].ToString());
- Assert.Equal("Expected error", innerError["ExceptionMessage"]);
- Assert.Contains("System.Net.Http.HttpContent.CopyToAsync", innerError["StackTrace"].ToString());
- }
- [Fact]
- public void CopyResponseAsync_Returns_User_Response_When_Formatter_Write_Throws_HttpResponseException_With_No_Content()
- {
- // Arrange
- HttpResponseMessage errorResponse = new HttpResponseMessage(HttpStatusCode.MethodNotAllowed);
- errorResponse.Headers.Add("myHeader", "myValue");
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>() { CallBase = true };
- formatterMock.Setup(m => m.WriteToStreamAsync(It.IsAny<Type>(),
- It.IsAny<object>(),
- It.IsAny<Stream>(),
- It.IsAny<HttpContent>(),
- It.IsAny<TransportContext>())).Throws(new HttpResponseException(errorResponse));
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- request.SetIsLocal(new Lazy<bool>(() => true));
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", formatterMock.Object);
- // Act
- Task task = CopyResponseAsync(contextMock.Object, request, response);
- task.Wait();
- memoryStream.Seek(0L, SeekOrigin.Begin);
- // Assert
- Assert.Equal<int>((int)errorResponse.StatusCode, responseBase.StatusCode);
- Assert.Equal(0, memoryStream.Length);
- Assert.Equal("myValue", responseBase.Headers["myHeader"]);
- Assert.Null(responseBase.Headers["Content-Type"]);
- }
- [Fact]
- public void CopyResponseAsync_Returns_User_Response_When_Formatter_Write_Throws_HttpResponseException_With_Content()
- {
- // Arrange
- HttpResponseMessage errorResponse = new HttpResponseMessage(HttpStatusCode.MethodNotAllowed);
- errorResponse.Headers.Add("myHeader", "myValue");
- errorResponse.Content = new StringContent("user message", Encoding.UTF8, "application/fake");
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>() { CallBase = true };
- formatterMock.Setup(m => m.WriteToStreamAsync(It.IsAny<Type>(),
- It.IsAny<object>(),
- It.IsAny<Stream>(),
- It.IsAny<HttpContent>(),
- It.IsAny<TransportContext>())).Throws(new HttpResponseException(errorResponse));
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- request.SetIsLocal(new Lazy<bool>(() => true));
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", formatterMock.Object);
- // Act
- Task task = CopyResponseAsync(contextMock.Object, request, response);
- task.Wait();
- // Assert preparation -- deserialize the response
- memoryStream.Seek(0L, SeekOrigin.Begin);
- string responseContent = null;
- using (var streamReader = new StreamReader(memoryStream))
- {
- responseContent = streamReader.ReadToEnd();
- }
- // Assert
- Assert.Equal<int>((int)errorResponse.StatusCode, responseBase.StatusCode);
- Assert.True(responseBase.Headers["Content-Type"].StartsWith("application/fake"));
- Assert.Equal("user message", responseContent);
- Assert.Equal("myValue", responseBase.Headers["myHeader"]);
- }
- [Fact]
- public void CopyResponseAsync_Returns_InternalServerError_And_No_Content_When_Formatter_Write_Task_Faults_During_Error_Response()
- {
- // Arrange
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>() { CallBase = true };
- TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
- tcs.SetException(new NotSupportedException("Expected error"));
- // This formatter throws on any write attempt
- formatterMock.Setup(m => m.WriteToStreamAsync(It.IsAny<Type>(),
- It.IsAny<object>(),
- It.IsAny<Stream>(),
- It.IsAny<HttpContent>(),
- It.IsAny<TransportContext>())).Returns(tcs.Task);
- // Create a local config to hook to the request to condition
- // the formatter selection for the error response
- HttpConfiguration config = new HttpConfiguration();
- config.Formatters.Clear();
- config.Formatters.Add(formatterMock.Object);
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- request.SetIsLocal(new Lazy<bool>(() => true));
- request.SetConfiguration(config);
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", formatterMock.Object);
- IExceptionLogger exceptionLogger = CreateStubExceptionLogger();
- IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(GlobalConfiguration.Configuration);
- // Act
- Task task = HttpControllerHandler.CopyResponseAsync(contextMock.Object, request, response, exceptionLogger,
- exceptionHandler, CancellationToken.None);
- task.Wait();
- // Assert
- Assert.Equal<int>((int)HttpStatusCode.InternalServerError, responseBase.StatusCode);
- Assert.Equal(0, memoryStream.Length);
- Assert.Null(responseBase.Headers["Content-Type"]);
- }
- [Fact]
- public void CopyResponseAsync_Returns_InternalServerError_And_No_Content_When_Formatter_Write_Throws_Immediately_During_Error_Response()
- {
- // Arrange
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTypeFormatter>() { CallBase = true };
- // This formatter throws on any write attempt
- formatterMock.Setup(m => m.WriteToStreamAsync(It.IsAny<Type>(),
- It.IsAny<object>(),
- It.IsAny<Stream>(),
- It.IsAny<HttpContent>(),
- It.IsAny<TransportContext>())).Throws(new NotSupportedException("Expected error"));
- // Create a local config to hook to the request to condition
- // the formatter selection for the error response
- HttpConfiguration config = new HttpConfiguration();
- config.Formatters.Clear();
- config.Formatters.Add(formatterMock.Object);
- MemoryStream memoryStream = new MemoryStream();
- Mock<HttpContextBase> contextMock = CreateMockHttpContextBaseForResponse(memoryStream);
- HttpResponseBase responseBase = contextMock.Object.Response;
- HttpRequestMessage request = new HttpRequestMessage();
- request.SetIsLocal(new Lazy<bool>(() => true));
- request.SetConfiguration(config);
- HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
- response.Content = new ObjectContent<string>("hello", formatterMock.Object);
- IExceptionLogger exceptionLogger = CreateStubExceptionLogger();
- IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(GlobalConfiguration.Configuration);
- // Act
- Task task = HttpControllerHandler.CopyResponseAsync(contextMock.Object, request, response, exceptionLogger,
- exceptionHandler, CancellationToken.None);
- task.Wait();
- // Assert
- Assert.Equal<int>((int)HttpStatusCode.InternalServerError, responseBase.StatusCode);
- Assert.Equal(0, memoryStream.Length);
- Assert.Null(responseBase.Headers["Content-Type"]);
- }
- [Fact]
- public void CopyResponseAsync_Returns_InternalServerError_And_No_Content_When_Content_Negotiation_Cannot_Find_Formatter_For_Error_Response()
- {
- // Create a content negotiator that works attempting a normal response but fails when creating the error response.
- Mock<IContentNegotiator> negotiatorMock = new Mock<IContentNegotiator>() { CallBase = true };
- negotiatorMock.Setup(m => m.Negotiate(It.IsAny<Type>(), It.IsAny<HttpRequestMessage>(), It.IsAny<IEnumerable<MediaTypeFormatter>>()))
- .Returns((Type t, HttpRequestMessage r, IEnumerable<MediaTypeFormatter> f) =>
- {
- ContentNegotiationResult result = t == typeof(HttpError)
- ? null
- : new ContentNegotiationResult(f.First(), JsonMediaTypeFormatter.DefaultMediaType);
- return result;
- });
- // Arrange
- Mock<JsonMediaTypeFormatter> formatterMock = new Mock<JsonMediaTyp…
Large files files are truncated, but you can click here to view the full file