Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,271 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json.Linq;
using Xunit;
using System.Xml.Linq;
using System.Xml;
namespace System.Web.Http.SelfHost
{
public class DeepNestedTypeTests
{
private HttpSelfHostServer server = null;
private string baseAddress = null;
private HttpClient httpClient = null;
public DeepNestedTypeTests()
{
this.SetupHost();
}
public void SetupHost()
{
baseAddress = String.Format("http://localhost/");
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "{controller}/{action}", new { controller = "DeepNestedType" });
server = new HttpSelfHostServer(config);
httpClient = new HttpClient(server);
}
[Fact]
public void PostDeeplyNestedTypeInXmlThrows()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "DeepNestedType/PostNest"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GetNestedObjectInXml(8000), UTF8Encoding.UTF8, "application/xml");
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
}
[Fact]
public void PostNotTooDeeplyNestedTypeInXmlWorks()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "DeepNestedType/PostNest"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GetNestedObjectInXml(20), UTF8Encoding.UTF8, "application/xml");
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string expectedResponseValue = @"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/"">success from PostNest</string>";
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);
Assert.Equal(expectedResponseValue, response.Content.ReadAsStringAsync().Result);
}
[Fact]
public void PostDeeplyNestedTypeInFormUrlEncodedThrows()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "DeepNestedType/PostJToken"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GetNestedObjectInFormUrl(5000), UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
}
[Fact]
public void PostNotTooDeeplyNestedTypeInFormUrlEncodedWorks()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "DeepNestedType/PostJToken"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GetNestedObjectInFormUrl(20), UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string expectedResponseValue = @"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/"">success from PostJToken</string>";
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);
Assert.Equal(expectedResponseValue, response.Content.ReadAsStringAsync().Result);
}
[Fact]
public void PostNestedListInFormUrlEncodedWorks()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "DeepNestedType/PostNestedList"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GetBigListInFormUrl(70000), Encoding.UTF8, "application/x-www-form-urlencoded");
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string expectedResponseValue = @"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/"">success from PostNestedList</string>";
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);
Assert.Equal(expectedResponseValue, response.Content.ReadAsStringAsync().Result);
}
[Fact]
public void PostBigArrayWorks()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "DeepNestedType/PostXElement"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GetBigArray(5000), Encoding.UTF8, "application/xml");
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string expectedResponseValue = @"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/"">success from PostXElement</string>";
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);
Assert.Equal(expectedResponseValue, response.Content.ReadAsStringAsync().Result);
}
/*
<?xml version="1.0"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string />
<string />
<string />
</ArrayOfString>
*/
private string GetBigArray(int arraySize)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arraySize; i++)
{
sb.Append("<string/>");
}
sb.Insert(0, "<ArrayOfString>");
sb.Append("</ArrayOfString>");
sb.Insert(0, "<?xml version=\"1.0\"?>");
return sb.ToString();
}
private string GetNestedObjectInXml(int depth)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++)
{
sb.Insert(0, "<A>");
sb.Append("</A>");
}
sb.Insert(0, "<Nest xmlns=\"http://schemas.datacontract.org/2004/07/System.Web.Http.SelfHost\">");
sb.Append("</Nest>");
sb.Insert(0, "<?xml version=\"1.0\"?>");
return sb.ToString();
}
private string GetNestedObjectInFormUrl(int depth)
{
StringBuilder sb = new StringBuilder("a");
for (int i = 0; i < depth; i++)
{
sb.Append("[a]");
}
sb.Append("=1");
return sb.ToString();
}
private string GetBigListInFormUrl(int depth)
{
StringBuilder sb = new StringBuilder();
sb.Append("a");
for (int i = 0; i < depth; i++)
{
sb.Append("[N]");
}
sb.Append("[D]=1");
return sb.ToString();
}
}
public class DeepNestedTypeController : ApiController
{
public string PostNest(Nest a)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
return "success from PostNest";
}
public string PostJToken(JToken token)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
return "success from PostJToken";
}
public string PostNestedList(MyList a)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
return "success from PostNestedList";
}
public string PostXElement(XElement input)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
return "success from PostXElement";
}
}
public class Nest
{
public Nest A { get; set; }
}
public class MyList
{
public int D { get; set; }
public MyList N { get; set; }
}
}

View File

@@ -0,0 +1,308 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.IdentityModel.Selectors;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Web.Http.SelfHost.Channels;
using Moq;
using Xunit;
using Xunit.Extensions;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.SelfHost
{
public class HttpSelfHostConfigurationTest
{
[Fact]
public void HttpSelfHostConfiguration_NullBaseAddressString_Throws()
{
Assert.ThrowsArgumentNull(() => new HttpSelfHostConfiguration((string)null), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_RelativeBaseAddressString_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("relative"), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_QueryBaseAddressString_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("http://localhost?somequery"), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_FragmentBaseAddressString_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("http://localhost#somefragment"), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_InvalidSchemeBaseAddressString_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("ftp://localhost"), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_NullBaseAddress_Throws()
{
Assert.ThrowsArgumentNull(() => new HttpSelfHostConfiguration((Uri)null), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_RelativeBaseAddress_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("relative", UriKind.Relative)), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_QueryBaseAddress_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("http://localhost?somequery")), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_FragmentBaseAddress_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("http://localhost#somefragment")), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_InvalidSchemeBaseAddress_Throws()
{
Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("ftp://localhost")), "baseAddress");
}
[Fact]
public void HttpSelfHostConfiguration_BaseAddress_IsSet()
{
// Arrange
Uri baseAddress = new Uri("http://localhost");
// Act
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
// Assert
Assert.Same(baseAddress, config.BaseAddress);
}
[Fact]
public void HttpSelfHostConfiguration_MaxConcurrentRequests_RoundTrips()
{
Assert.Reflection.IntegerProperty(
new HttpSelfHostConfiguration("http://localhost"),
c => c.MaxConcurrentRequests,
expectedDefaultValue: GetDefaultMaxConcurrentRequests(),
minLegalValue: 1,
illegalLowerValue: 0,
maxLegalValue: null,
illegalUpperValue: null,
roundTripTestValue: 10);
}
[Fact]
public void HttpSelfHostConfiguration_MaxBufferSize_RoundTrips()
{
Assert.Reflection.IntegerProperty(
new HttpSelfHostConfiguration("http://localhost"),
c => c.MaxBufferSize,
expectedDefaultValue: 64 * 1024,
minLegalValue: 1,
illegalLowerValue: 0,
maxLegalValue: null,
illegalUpperValue: null,
roundTripTestValue: 10);
}
[Theory]
[InlineData(1, 1)]
[InlineData(1024, 1024)]
[InlineData(Int32.MaxValue - 1, Int32.MaxValue - 1)]
[InlineData(Int32.MaxValue, Int32.MaxValue)]
[InlineData(Int64.MaxValue - 1, Int32.MaxValue)]
[InlineData(Int64.MaxValue, Int32.MaxValue)]
public void HttpSelfHostConfiguration_MaxBufferSize_TracksMaxReceivedMessageSizeWhenNotSet(long maxReceivedMessageSize, int expectedMaxBufferSize)
{
// Arrange
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost");
config.MaxReceivedMessageSize = maxReceivedMessageSize;
// Act & Assert
Assert.Equal(expectedMaxBufferSize, config.MaxBufferSize);
}
[Theory]
[InlineData(2, 1)]
[InlineData(1025, 1024)]
[InlineData(Int64.MaxValue, Int32.MaxValue)]
public void HttpSelfHostConfiguration_MaxBufferSize_DoesNotTrackMaxReceivedMessageSizeWhenSet(long maxReceivedMessageSize, int maxBufferSize)
{
// Arrange
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost");
config.MaxBufferSize = maxBufferSize;
config.MaxReceivedMessageSize = maxReceivedMessageSize;
// Act & Assert
Assert.Equal(maxBufferSize, config.MaxBufferSize);
Assert.Equal(maxReceivedMessageSize, config.MaxReceivedMessageSize);
}
[Theory]
[InlineData(1)]
[InlineData(1024)]
[InlineData(Int64.MaxValue)]
public void HttpSelfHostConfiguration_MaxBufferSize_DoesNotTrackMaxReceivedMessageIfNotBuffered(long maxReceivedMessageSize)
{
// Arrange
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost");
config.TransferMode = TransferMode.Streamed;
config.MaxReceivedMessageSize = maxReceivedMessageSize;
// Act & Assert
Assert.Equal(maxReceivedMessageSize, config.MaxReceivedMessageSize);
Assert.Equal(64 * 1024, config.MaxBufferSize);
}
[Fact]
public void HttpSelfHostConfiguration_MaxReceivedMessageSize_RoundTrips()
{
Assert.Reflection.IntegerProperty(
new HttpSelfHostConfiguration("http://localhost"),
c => c.MaxReceivedMessageSize,
expectedDefaultValue: 64 * 1024,
minLegalValue: 1,
illegalLowerValue: 0,
maxLegalValue: null,
illegalUpperValue: null,
roundTripTestValue: 10);
}
[Fact]
public void HttpSelfHostConfiguration_UseWindowsAuthentication_RoundTrips()
{
Assert.Reflection.BooleanProperty(
new HttpSelfHostConfiguration("http://localhost"),
c => c.UseWindowsAuthentication,
expectedDefaultValue: false);
}
[Fact]
public void HttpSelfHostConfiguration_UserNamePasswordValidator_RoundTrips()
{
// Arrange
UserNamePasswordValidator userNamePasswordValidator = new Mock<UserNamePasswordValidator>().Object;
Assert.Reflection.Property(
new HttpSelfHostConfiguration("http://localhost"),
c => c.UserNamePasswordValidator,
expectedDefaultValue: null,
allowNull: true,
roundTripTestValue: userNamePasswordValidator);
}
[Fact]
public void HttpSelfHostConfiguration_TransferMode_RoundTrips()
{
Assert.Reflection.EnumProperty(
new HttpSelfHostConfiguration("http://localhost"),
c => c.TransferMode,
expectedDefaultValue: TransferMode.Buffered,
illegalValue: (TransferMode)999,
roundTripTestValue: TransferMode.Streamed);
}
[Fact]
public void HttpSelfHostConfiguration_HostNameComparisonMode_RoundTrips()
{
Assert.Reflection.EnumProperty(
new HttpSelfHostConfiguration("http://localhost"),
c => c.HostNameComparisonMode,
expectedDefaultValue: HostNameComparisonMode.StrongWildcard,
illegalValue: (HostNameComparisonMode)999,
roundTripTestValue: HostNameComparisonMode.Exact);
}
[Fact]
public void HttpSelfHostConfiguration_Settings_PropagateToBinding()
{
// Arrange
HttpBinding binding = new HttpBinding();
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost")
{
MaxBufferSize = 10,
MaxReceivedMessageSize = 11,
TransferMode = TransferMode.StreamedResponse,
HostNameComparisonMode = HostNameComparisonMode.WeakWildcard
};
// Act
config.ConfigureBinding(binding);
// Assert
Assert.Equal(10, binding.MaxBufferSize);
Assert.Equal(11, binding.MaxReceivedMessageSize);
Assert.Equal(TransferMode.StreamedResponse, binding.TransferMode);
Assert.Equal(HostNameComparisonMode.WeakWildcard, binding.HostNameComparisonMode);
}
[Theory]
[InlineData("http://localhost", HttpBindingSecurityMode.TransportCredentialOnly)]
[InlineData("https://localhost", HttpBindingSecurityMode.Transport)]
public void HttpSelfHostConfiguration_UseWindowsAuth_PropagatesToHttpBinding(string address, HttpBindingSecurityMode mode)
{
// Arrange
HttpBinding binding = new HttpBinding();
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(address)
{
UseWindowsAuthentication = true
};
// Act
BindingParameterCollection parameters = config.ConfigureBinding(binding);
// Assert
Assert.NotNull(parameters);
ServiceCredentials serviceCredentials = parameters.Find<ServiceCredentials>();
Assert.NotNull(serviceCredentials);
Assert.Equal(HttpClientCredentialType.Windows, binding.Security.Transport.ClientCredentialType);
Assert.Equal(mode, binding.Security.Mode);
}
[Theory]
[InlineData("http://localhost", HttpBindingSecurityMode.TransportCredentialOnly)]
[InlineData("https://localhost", HttpBindingSecurityMode.Transport)]
public void HttpSelfHostConfiguration_UserNamePasswordValidator_PropagatesToBinding(string address, HttpBindingSecurityMode mode)
{
// Arrange
HttpBinding binding = new HttpBinding();
UserNamePasswordValidator validator = new Mock<UserNamePasswordValidator>().Object;
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(address)
{
UserNamePasswordValidator = validator
};
// Act
BindingParameterCollection parameters = config.ConfigureBinding(binding);
// Assert
Assert.NotNull(parameters);
ServiceCredentials serviceCredentials = parameters.Find<ServiceCredentials>();
Assert.NotNull(serviceCredentials);
Assert.Equal(HttpClientCredentialType.Basic, binding.Security.Transport.ClientCredentialType);
Assert.Equal(mode, binding.Security.Mode);
}
private static int GetDefaultMaxConcurrentRequests()
{
try
{
return Math.Max(Environment.ProcessorCount * 100, 100);
}
catch
{
return 100;
}
}
}
}

View File

@@ -0,0 +1,377 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Extensions;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.SelfHost
{
public class HttpSelfHostServerTest : IDisposable
{
private string machineName = Environment.MachineName;
private HttpSelfHostServer _bufferServer;
private HttpSelfHostServer _streamServer;
public HttpSelfHostServerTest()
{
SetupHosts();
}
public void Dispose()
{
CleanupHosts();
}
private void SetupHosts()
{
try
{
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(BaseUri(TransferMode.Buffered));
config.Routes.MapHttpRoute("Default", "{controller}/{action}");
_bufferServer = new HttpSelfHostServer(config);
SafeOpen(_bufferServer);
config = new HttpSelfHostConfiguration(BaseUri(TransferMode.Streamed));
config.Routes.MapHttpRoute("Default", "{controller}/{action}");
config.TransferMode = TransferMode.Streamed;
_streamServer = new HttpSelfHostServer(config);
SafeOpen(_streamServer);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("HttpSelfHostServerTests.SetupHosts failed: " + ex.GetBaseException());
throw;
}
}
private void CleanupHosts()
{
SafeClose(_bufferServer);
SafeClose(_streamServer);
}
// HttpSelfHostServer has a small latency between CloseAsync.Wait
// completing and other async tasks still running. Theory driven
// tests run quickly enough they sometimes attempt to open when the
// prior test is still finishing those async tasks.
private static void SafeOpen(HttpSelfHostServer server)
{
for (int i = 0; i < 10; i++)
{
try
{
server.OpenAsync().Wait();
return;
}
catch (Exception)
{
if (i == 9)
{
System.Diagnostics.Debug.WriteLine("HttpSelfHostServerTests.SafeOpen failed to open server at " + server.Configuration.VirtualPathRoot);
throw;
}
Thread.Sleep(200);
}
}
}
private void SafeClose(HttpSelfHostServer server)
{
try
{
server.CloseAsync().Wait();
}
catch
{
System.Diagnostics.Debug.WriteLine("HttpSelfHostServerTests.SafeOpen failed to close server at " + server.Configuration.VirtualPathRoot);
}
}
private string BaseUri(TransferMode transferMode)
{
return transferMode == TransferMode.Streamed
? String.Format("http://{0}:8081/stream", machineName)
: String.Format("http://{0}:8081", machineName);
}
private HttpSelfHostServer GetServer(TransferMode transferMode)
{
return transferMode == TransferMode.Streamed
? _streamServer
: _bufferServer;
}
[Theory]
[InlineData("/SelfHostServerTest/EchoString", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/EchoString", TransferMode.Streamed)]
public void SendAsync_Direct_Returns_OK_For_Successful_ObjectContent_Write(string uri, TransferMode transferMode)
{
// Arrange & Act
HttpResponseMessage response = new HttpClient().GetAsync(BaseUri(transferMode) + uri).Result;
string responseString = response.Content.ReadAsStringAsync().Result;
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("\"echoString\"", responseString);
}
[Theory]
[InlineData("/SelfHostServerTest/EchoString", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/EchoString", TransferMode.Streamed)]
public void SendAsync_ServiceModel_Returns_OK_For_Successful_ObjectContent_Write(string uri, TransferMode transferMode)
{
// Arrange
bool shouldChunk = transferMode == TransferMode.Streamed;
// Act
HttpResponseMessage response = new HttpClient().GetAsync(BaseUri(transferMode) + uri).Result;
string responseString = response.Content.ReadAsStringAsync().Result;
IEnumerable<string> headerValues = null;
bool isChunked = response.Headers.TryGetValues("Transfer-Encoding", out headerValues) && headerValues != null &&
headerValues.Any((v) => String.Equals(v, "chunked", StringComparison.OrdinalIgnoreCase));
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("\"echoString\"", responseString);
Assert.Equal(shouldChunk, isChunked);
}
[Theory]
[InlineData("/SelfHostServerTest/EchoStream", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/EchoStream", TransferMode.Streamed)]
public void SendAsync_Direct_Returns_OK_For_Successful_Stream_Write(string uri, TransferMode transferMode)
{
// Arrange & Act
HttpResponseMessage response = new HttpClient(GetServer(transferMode)).GetAsync(BaseUri(transferMode) + uri).Result;
string responseString = response.Content.ReadAsStringAsync().Result;
IEnumerable<string> headerValues = null;
bool isChunked = response.Headers.TryGetValues("Transfer-Encoding", out headerValues) && headerValues != null &&
headerValues.Any((v) => String.Equals(v, "chunked", StringComparison.OrdinalIgnoreCase));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("echoStream", responseString);
Assert.False(isChunked); // stream never chunk, buffered or streamed
}
[Theory]
[InlineData("/SelfHostServerTest/EchoStream", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/EchoStream", TransferMode.Streamed)]
public void SendAsync_ServiceModel_Returns_OK_For_Successful_Stream_Write(string uri, TransferMode transferMode)
{
// Arrange & Act
HttpResponseMessage response = new HttpClient().GetAsync(BaseUri(transferMode) + uri).Result;
string responseString = response.Content.ReadAsStringAsync().Result;
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("echoStream", responseString);
}
[Theory]
[InlineData("/SelfHostServerTest/ThrowBeforeTask", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowBeforeTask", TransferMode.Streamed)]
[InlineData("/SelfHostServerTest/ThrowBeforeWrite", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowBeforeWrite", TransferMode.Streamed)]
[InlineData("/SelfHostServerTest/ThrowAfterWrite", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowAfterWrite", TransferMode.Streamed)]
public void SendAsync_Direct_Throws_When_ObjectContent_CopyToAsync_Throws(string uri, TransferMode transferMode)
{
// Arrange & Act & Assert
Assert.Throws<InvalidOperationException>(
() => new HttpClient(GetServer(transferMode)).GetAsync(BaseUri(transferMode) + uri).Wait());
}
[Theory]
[InlineData("/SelfHostServerTest/ThrowBeforeTask", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowBeforeTask", TransferMode.Streamed)]
[InlineData("/SelfHostServerTest/ThrowBeforeWrite", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowBeforeWrite", TransferMode.Streamed)]
[InlineData("/SelfHostServerTest/ThrowAfterWrite", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowAfterWrite", TransferMode.Streamed)]
public void SendAsync_ServiceModel_Closes_Connection_When_ObjectContent_CopyToAsync_Throws(string uri, TransferMode transferMode)
{
// Arrange
Task<HttpResponseMessage> task = new HttpClient().GetAsync(BaseUri(transferMode) + uri);
// Act & Assert
Assert.Throws<HttpRequestException>(() => task.Wait());
}
[Theory(Skip = "This currently fails on CI machine only")]
[InlineData("/SelfHostServerTest/ThrowBeforeWriteStream", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowBeforeWriteStream", TransferMode.Streamed)]
[InlineData("/SelfHostServerTest/ThrowAfterWriteStream", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowAfterWriteStream", TransferMode.Streamed)]
public void SendAsync_Direct_Throws_When_StreamContent_Throws(string uri, TransferMode transferMode)
{
// Arrange & Act & Assert
Assert.Throws<InvalidOperationException>(
() => new HttpClient(GetServer(transferMode)).GetAsync(BaseUri(transferMode) + uri).Wait());
}
[Theory]
[InlineData("/SelfHostServerTest/ThrowBeforeWriteStream", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowBeforeWriteStream", TransferMode.Streamed)]
[InlineData("/SelfHostServerTest/ThrowAfterWriteStream", TransferMode.Buffered)]
[InlineData("/SelfHostServerTest/ThrowAfterWriteStream", TransferMode.Streamed)]
public void SendAsync_ServiceModel_Throws_When_StreamContent_Throws(string uri, TransferMode transferMode)
{
// Arrange
Task task = new HttpClient().GetAsync(BaseUri(transferMode) + uri);
// Act & Assert
Assert.Throws<HttpRequestException>(() => task.Wait());
}
internal class ThrowsBeforeTaskObjectContent : ObjectContent
{
public ThrowsBeforeTaskObjectContent() : base(typeof(string), "testContent", new JsonMediaTypeFormatter())
{
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
throw new InvalidOperationException("ThrowBeforeTask");
}
}
internal class ThrowBeforeWriteObjectContent : ObjectContent
{
public ThrowBeforeWriteObjectContent()
: base(typeof(string), "testContent", new JsonMediaTypeFormatter())
{
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return Task.Factory.StartNew(() =>
{
throw new InvalidOperationException("ThrowBeforeWrite");
});
}
}
internal class ThrowAfterWriteObjectContent : ObjectContent
{
public ThrowAfterWriteObjectContent()
: base(typeof(string), "testContent", new JsonMediaTypeFormatter())
{
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return Task.Factory.StartNew(() =>
{
byte[] buffer =
Encoding.UTF8.GetBytes("ThrowAfterWrite");
stream.Write(buffer, 0, buffer.Length);
throw new InvalidOperationException("ThrowAfterWrite");
});
}
}
internal class ThrowBeforeWriteStream : StreamContent
{
public ThrowBeforeWriteStream() : base(new MemoryStream(Encoding.UTF8.GetBytes("ThrowBeforeWriteStream")))
{
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
throw new InvalidOperationException("ThrowBeforeWriteStream");
}
}
internal class ThrowAfterWriteStream : StreamContent
{
public ThrowAfterWriteStream() : base(new MemoryStream(Encoding.UTF8.GetBytes("ThrowAfterWriteStream")))
{
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
base.SerializeToStreamAsync(stream, context).Wait();
throw new InvalidOperationException("ThrowAfterWriteStream");
}
}
}
public class SelfHostServerTestController : ApiController
{
[HttpGet]
public string EchoString()
{
return "echoString";
}
[HttpGet]
public HttpResponseMessage EchoStream()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes("echoStream")))
};
}
[HttpGet]
public HttpResponseMessage ThrowBeforeTask()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = new HttpSelfHostServerTest.ThrowsBeforeTaskObjectContent()
};
}
[HttpGet]
public HttpResponseMessage ThrowBeforeWrite()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = new HttpSelfHostServerTest.ThrowBeforeWriteObjectContent()
};
}
[HttpGet]
public HttpResponseMessage ThrowAfterWrite()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = new HttpSelfHostServerTest.ThrowAfterWriteObjectContent()
};
}
[HttpGet]
public HttpResponseMessage ThrowBeforeWriteStream()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = new HttpSelfHostServerTest.ThrowBeforeWriteStream()
};
}
[HttpGet]
public HttpResponseMessage ThrowAfterWriteStream()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = new HttpSelfHostServerTest.ThrowAfterWriteStream()
};
}
}
}

View File

@@ -0,0 +1,244 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Specialized;
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.Text;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http.SelfHost
{
public class MaxHttpCollectionKeyTests
{
private HttpServer server = null;
private string baseAddress = null;
private HttpClient httpClient = null;
public MaxHttpCollectionKeyTests()
{
this.SetupHost();
}
public void SetupHost()
{
baseAddress = String.Format("http://localhost/");
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default", "{controller}/{action}", new { controller = "MaxHttpCollectionKeyType" });
server = new HttpServer(config);
httpClient = new HttpClient(server);
}
[Theory]
[InlineData("PostCustomer")]
[InlineData("PostFormData")]
public void PostManyKeysInFormUrlEncodedThrows(string actionName)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "MaxHttpCollectionKeyType/" + actionName));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GenerateHttpCollectionKeyInput(100), UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
MediaTypeFormatter.MaxHttpCollectionKeys = 99;
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
string expectedResponseValue = @"The number of keys in a NameValueCollection has exceeded the limit of '99'. You can adjust it by modifying the MaxHttpCollectionKeys property on the 'System.Net.Http.Formatting.MediaTypeFormatter' class.";
Assert.Equal(expectedResponseValue, response.Content.ReadAsStringAsync().Result);
}
[Theory]
[InlineData("PostCustomer")]
[InlineData("PostFormData")]
public void PostNotTooManyKeysInFormUrlEncodedWorks(string actionName)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "MaxHttpCollectionKeyType/" + actionName));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Post;
request.Content = new StringContent(GenerateHttpCollectionKeyInput(100), UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
MediaTypeFormatter.MaxHttpCollectionKeys = 1000;
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string expectedResponseValue = @"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/"">success from " + actionName + "</string>";
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);
Assert.Equal(expectedResponseValue, response.Content.ReadAsStringAsync().Result);
}
[Theory]
[InlineData("PostCustomerFromUri")]
[InlineData("GetWithQueryable")]
public void PostManyKeysInUriThrows(string actionName)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "MaxHttpCollectionKeyType/" + actionName + "/?" + GenerateHttpCollectionKeyInput(100)));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
if (actionName.StartsWith("Post"))
{
request.Method = HttpMethod.Post;
request.Content = new StringContent("", UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
}
else
{
request.Method = HttpMethod.Get;
}
MediaTypeFormatter.MaxHttpCollectionKeys = 99;
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
}
[Theory]
[InlineData("PostCustomerFromUri")]
[InlineData("GetWithQueryable")]
public void PostNotTooManyKeysInUriWorks(string actionName)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(Path.Combine(baseAddress, "MaxHttpCollectionKeyType/" + actionName + "/?" + GenerateHttpCollectionKeyInput(100)));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
if (actionName.StartsWith("Post"))
{
request.Method = HttpMethod.Post;
request.Content = new StringContent("", UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
}
else
{
request.Method = HttpMethod.Get;
}
MediaTypeFormatter.MaxHttpCollectionKeys = 1000;
// Action
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string expectedResponseValue = @"success from " + actionName;
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal("application/xml", response.Content.Headers.ContentType.MediaType);
Assert.True(response.Content.ReadAsStringAsync().Result.Contains(expectedResponseValue));
}
private static string GenerateHttpCollectionKeyInput(int num)
{
StringBuilder sb = new StringBuilder("a=0");
for (int i = 0; i < num; i++)
{
sb.Append("&");
sb.Append(i.ToString());
sb.Append("=0");
}
return sb.ToString();
}
}
public class MaxHttpCollectionKeyTypeController : ApiController
{
// Post strongly typed Customer
public string PostCustomer(Customer a)
{
if (!ModelState.IsValid)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
ModelBinding.ModelState value = null;
ModelState.TryGetValue("a", out value);
response.Content = new StringContent(value.Errors[0].ErrorMessage);
throw new HttpResponseException(response);
}
return "success from PostCustomer";
}
// Post form data
public string PostFormData(FormDataCollection a)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
}
try
{
NameValueCollection collection = a.ReadAsNameValueCollection();
}
catch (InvalidOperationException ex)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
response.Content = new StringContent(ex.Message);
throw new HttpResponseException(response);
}
return "success from PostFormData";
}
public string PostCustomerFromUri([FromUri]Customer a)
{
if (!ModelState.IsValid)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
ModelBinding.ModelState value = null;
ModelState.TryGetValue("a", out value);
response.Content = new StringContent(value.Errors[0].ErrorMessage);
throw new HttpResponseException(response);
}
return "success from PostCustomerFromUri";
}
[Queryable]
public IQueryable<string> GetWithQueryable()
{
return new List<string>(){"success from GetWithQueryable"}.AsQueryable();
}
public string PostJToken(JToken token)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
}
return "success from PostJToken";
}
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "ModelBindingItem(" + Name + "," + Age + ")";
}
}
}

View File

@@ -0,0 +1,2 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7F29EE87-6A63-43C6-B7FF-74DD06815830}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>System.Web.Http.SelfHost</RootNamespace>
<AssemblyName>System.Web.Http.SelfHost.Test</AssemblyName>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(WebStackRootPath)\bin\Debug\Test\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>$(WebStackRootPath)\bin\Release\Test\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'CodeCoverage' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(WebStackRootPath)\bin\CodeCoverage\Test\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Net.Http.2.0.20326.1\lib\net40\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Net.Http.2.0.20326.1\lib\net40\System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq" />
<Reference Include="xunit">
<HintPath>..\..\packages\xunit.1.9.0.1566\lib\xunit.dll</HintPath>
</Reference>
<Reference Include="xunit.extensions">
<HintPath>..\..\packages\xunit.extensions.1.9.0.1566\lib\xunit.extensions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Newtonsoft.Json.4.5.1\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MaxHttpCollectionKeyTests.cs" />
<Compile Include="DeeplyNestedTypeTests.cs" />
<Compile Include="HttpSelfHostConfigurationTest.cs" />
<Compile Include="HttpSelfHostServerTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\System.Net.Http.Formatting\System.Net.Http.Formatting.csproj">
<Project>{668E9021-CE84-49D9-98FB-DF125A9FCDB0}</Project>
<Name>System.Net.Http.Formatting</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\System.Web.Http.SelfHost\System.Web.Http.SelfHost.csproj">
<Project>{66492E69-CE4C-4FB1-9B1F-88DEE09D06F1}</Project>
<Name>System.Web.Http.SelfHost</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\System.Web.Http\System.Web.Http.csproj">
<Project>{DDC1CE0C-486E-4E35-BB3B-EAB61F8F9440}</Project>
<Name>System.Web.Http</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\System.Web.Mvc\System.Web.Mvc.csproj">
<Project>{3D3FFD8A-624D-4E9B-954B-E1C105507975}</Project>
<Name>System.Web.Mvc</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.TestCommon\Microsoft.TestCommon.csproj">
<Project>{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}</Project>
<Name>Microsoft.TestCommon</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Net.Http" version="2.0.20326.1" />
<package id="Moq" version="4.0.10827" />
<package id="Newtonsoft.Json" version="4.5.1" />
<package id="xunit" version="1.9.0.1566" />
<package id="xunit.extensions" version="1.9.0.1566" />
</packages>