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,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Http;
namespace System.Web.Http
{
public class DuplicateController : ApiController
{
public string GetAction()
{
return "dup";
}
}
}
namespace System.Web.Http2
{
public class DuplicateController : ApiController
{
public string GetAction()
{
return "dup2";
}
}
}

View File

@ -0,0 +1,109 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace System.Web.Http
{
public class ExceptionController : ApiController
{
public static string ResponseExceptionHeaderKey = "responseExceptionStatusCode";
public HttpResponseMessage Unavailable()
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
}
public Task<HttpResponseMessage> AsyncUnavailable()
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
}
public Task<HttpResponseMessage> AsyncUnavailableDelegate()
{
return Task.Factory.StartNew<HttpResponseMessage>(() => { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable)); });
}
public HttpResponseMessage ArgumentNull()
{
throw new ArgumentNullException("foo");
}
public Task<HttpResponseMessage> AsyncArgumentNull()
{
return Task.Factory.StartNew<HttpResponseMessage>(() => { throw new ArgumentNullException("foo"); });
}
[HttpGet]
public string GetException()
{
return "foo";
}
[HttpGet]
public string GetString()
{
return "bar";
}
public T GenericAction<T>() where T : User
{
return null;
}
[AuthorizationFilterThrows]
public void AuthorizationFilter() { }
[ActionFilterThrows]
public void ActionFilter() { }
[ExceptionFilterThrows]
public void ExceptionFilter() { throw new ArgumentException("exception"); }
private class AuthorizationFilterThrows : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
TryThrowHttpResponseException(actionContext);
throw new ArgumentException("authorization");
}
}
private class ActionFilterThrows : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
TryThrowHttpResponseException(actionContext);
throw new ArgumentException("action");
}
}
private class ExceptionFilterThrows : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
TryThrowHttpResponseException(actionExecutedContext.ActionContext);
throw actionExecutedContext.Exception;
}
}
private static void TryThrowHttpResponseException(HttpActionContext actionContext)
{
IEnumerable<string> values;
if (actionContext.ControllerContext.Request.Headers.TryGetValues(ResponseExceptionHeaderKey, out values))
{
string statusString = values.First() as string;
if (!String.IsNullOrEmpty(statusString))
{
HttpStatusCode status = (HttpStatusCode)Enum.Parse(typeof(HttpStatusCode), statusString);
throw new HttpResponseException(actionContext.Request.CreateResponse(status, "HttpResponseExceptionMessage"));
}
}
}
}
}

View File

@ -0,0 +1,257 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net;
using System.Net.Http;
using System.Web.Http.Dispatcher;
using System.Web.Http.Properties;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http
{
public class ExceptionHandlingTest
{
[Theory]
[InlineData("Unavailable")]
[InlineData("AsyncUnavailable")]
[InlineData("AsyncUnavailableDelegate")]
public void ThrowingHttpResponseException_FromAction_GetsReturnedToClient(string actionName)
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
}
);
}
[Theory]
[InlineData("ArgumentNull")]
[InlineData("AsyncArgumentNull")]
public void ThrowingArgumentNullException_FromAction_GetsReturnedToClient(string actionName)
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
ExceptionSurrogate exception = response.Content.ReadAsAsync<ExceptionSurrogate>().Result;
Assert.Equal(typeof(ArgumentNullException).FullName, exception.ExceptionType.ToString());
}
);
}
[Theory]
[InlineData("ArgumentNull")]
[InlineData("AsyncArgumentNull")]
public void ThrowingArgumentNullException_FromAction_GetsReturnedToClientParsedAsJson(string actionName)
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
dynamic json = JToken.Parse(response.Content.ReadAsStringAsync().Result);
string result = json.ExceptionType;
Assert.Equal(typeof(ArgumentNullException).FullName, result);
}
);
}
[Theory]
[InlineData("AuthorizationFilter")]
[InlineData("ActionFilter")]
[InlineData("ExceptionFilter")]
public void ThrowingArgumentException_FromFilter_GetsReturnedToClient(string actionName)
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
ExceptionSurrogate exception = response.Content.ReadAsAsync<ExceptionSurrogate>().Result;
Assert.Equal(typeof(ArgumentException).FullName, exception.ExceptionType.ToString());
}
);
}
[Theory]
[InlineData("AuthorizationFilter", HttpStatusCode.Forbidden)]
[InlineData("ActionFilter", HttpStatusCode.NotAcceptable)]
[InlineData("ExceptionFilter", HttpStatusCode.NotImplemented)]
public void ThrowingHttpResponseException_FromFilter_GetsReturnedToClient(string actionName, HttpStatusCode responseExceptionStatusCode)
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
request.Headers.Add(ExceptionController.ResponseExceptionHeaderKey, responseExceptionStatusCode.ToString());
ScenarioHelper.RunTest(
controllerName,
"/{action}",
request,
(response) =>
{
Assert.Equal(responseExceptionStatusCode, response.StatusCode);
Assert.Equal("HttpResponseExceptionMessage", response.Content.ReadAsAsync<string>().Result);
}
);
}
// TODO: add tests that throws from custom model binders
[Fact]
public void Service_ReturnsNotFound_WhenControllerNameDoesNotExist()
{
string controllerName = "randomControllerThatCannotBeFound";
string requestUrl = String.Format("{0}/{1}", ScenarioHelper.BaseAddress, controllerName);
ScenarioHelper.RunTest(
controllerName,
"",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.Equal(
String.Format(SRResources.DefaultControllerFactory_ControllerNameNotFound, controllerName),
response.Content.ReadAsAsync<string>().Result);
}
);
}
[Fact]
public void Service_ReturnsNotFound_WhenActionNameDoesNotExist()
{
string controllerName = "Exception";
string actionName = "actionNotFound";
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.Equal(
String.Format(SRResources.ApiControllerActionSelector_ActionNameNotFound, controllerName, actionName),
response.Content.ReadAsAsync<string>().Result);
}
);
}
[Fact]
public void Service_ReturnsMethodNotAllowed_WhenActionsDoesNotSupportTheRequestHttpMethod()
{
string controllerName = "Exception";
string actionName = "GetString";
HttpMethod requestMethod = HttpMethod.Post;
string requestUrl = String.Format("{0}/{1}/{2}", ScenarioHelper.BaseAddress, controllerName, actionName);
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(requestMethod, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
Assert.Equal(
String.Format(SRResources.ApiControllerActionSelector_HttpMethodNotSupported, requestMethod.Method),
response.Content.ReadAsAsync<string>().Result);
}
);
}
[Fact]
public void Service_ReturnsInternalServerError_WhenMultipleActionsAreFound()
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}", ScenarioHelper.BaseAddress, controllerName);
ScenarioHelper.RunTest(
controllerName,
"",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.Contains(
String.Format(SRResources.ApiControllerActionSelector_AmbiguousMatch, String.Empty),
response.Content.ReadAsAsync<string>().Result);
}
);
}
[Fact]
public void Service_ReturnsInternalServerError_WhenMultipleControllersAreFound()
{
string controllerName = "Duplicate";
string requestUrl = String.Format("{0}/{1}", ScenarioHelper.BaseAddress, controllerName);
ScenarioHelper.RunTest(
controllerName,
"",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.Contains(
String.Format(SRResources.DefaultControllerFactory_ControllerNameAmbiguous_WithRouteTemplate, controllerName, "{controller}", String.Empty),
response.Content.ReadAsAsync<string>().Result);
}
);
}
[Fact]
public void GenericMethod_Throws_InvalidOperationException()
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default", "Exception/{action}", new { controller = "Exception" });
HttpServer server = new HttpServer(config);
HttpClient client = new HttpClient(server);
// Ensure that the behavior is repeatable and other action is still callable after the error
for (int i = 0; i < 10; i++)
{
// Make sure other action can be called
HttpResponseMessage response = client.GetAsync("http://localhost/Exception/GetString").Result;
Assert.True(response.IsSuccessStatusCode,
String.Format("Successful status code was expected but got '{0}' instead. Error: {1}", response.StatusCode, response.Content.ReadAsStringAsync().Result));
// Make a request to generic method and verify the exception
response = client.PostAsync("http://localhost/Exception/GenericAction", null).Result;
Type controllerType = typeof(ExceptionController);
ExceptionSurrogate exception = response.Content.ReadAsAsync<ExceptionSurrogate>().Result;
Assert.Equal(typeof(InvalidOperationException).FullName, exception.ExceptionType);
Assert.Equal(
String.Format(
SRResources.ReflectedHttpActionDescriptor_CannotCallOpenGenericMethods,
controllerType.GetMethod("GenericAction"),
controllerType.FullName),
exception.Message);
}
}
}
}

View File

@ -0,0 +1,226 @@
// 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.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http.ExceptionHandling
{
public class HttpResponseExceptionTest
{
[Theory]
[InlineData("DoNotThrow")]
[InlineData("ActionMethod")]
// TODO : 332683 - HttpResponseExceptions in message handlers
//[InlineData("RequestMessageHandler")]
//[InlineData("ResponseMessageHandler")]
[InlineData("RequestAuthorization")]
[InlineData("BeforeActionExecuted")]
[InlineData("AfterActionExecuted")]
[InlineData("ContentNegotiatorNegotiate")]
[InlineData("ActionMethodAndExceptionFilter")]
[InlineData("MediaTypeFormatterReadFromStreamAsync")]
public void HttpResponseExceptionWithExplicitStatusCode(string throwAt)
{
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(ScenarioHelper.BaseAddress + "/ExceptionTests/ReturnString");
request.Method = HttpMethod.Post;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Content = new StringContent("\"" + throwAt + "\"", Encoding.UTF8, "application/json");
ScenarioHelper.RunTest(
"ExceptionTests",
"/{action}",
request,
response =>
{
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.Equal(response.Content.Headers.ContentType.MediaType, "application/json");
if (throwAt == "DoNotThrow")
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("Hello World!", response.Content.ReadAsAsync<string>(new List<MediaTypeFormatter>() { new JsonMediaTypeFormatter() }).Result);
}
else
{
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.Equal(String.Format("Error at {0}", throwAt),
response.Content.ReadAsAsync<string>(new List<MediaTypeFormatter>() { new JsonMediaTypeFormatter() }).Result);
}
},
config =>
{
config.Services.Replace(typeof(IContentNegotiator), new CustomContentNegotiator(throwAt));
config.MessageHandlers.Add(new CustomMessageHandler(throwAt));
config.Filters.Add(new CustomActionFilterAttribute(throwAt));
config.Filters.Add(new CustomAuthorizationFilterAttribute(throwAt));
config.Filters.Add(new CustomExceptionFilterAttribute(throwAt));
config.Formatters.Clear();
config.Formatters.Add(new CustomJsonMediaTypeFormatter(throwAt));
}
);
}
}
public class CustomMessageHandler : DelegatingHandler
{
private string _throwAt;
public CustomMessageHandler(string throwAt)
{
_throwAt = throwAt;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "RequestMessageHandler");
return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((tsk) =>
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "ResponseMessageHandler");
HttpResponseMessage response = tsk.Result;
return response;
});
}
}
public class ExceptionTestsController : ApiController
{
[HttpPost]
public string ReturnString([FromBody] string throwAt)
{
string message = "Hello World!";
// check if the test wants to throw from here
ExceptionTestsUtility.CheckForThrow(throwAt, "ActionMethod");
// NOTE: this indicates that we want to throw from here & after this gets intercepted
// by the ExceptionFilter, we want to throw from there too
ExceptionTestsUtility.CheckForThrow(throwAt, "ActionMethodAndExceptionFilter");
return message;
}
}
public class CustomAuthorizationFilterAttribute : AuthorizationFilterAttribute
{
private string _throwAt;
public CustomAuthorizationFilterAttribute(string throwAt)
{
_throwAt = throwAt;
}
public override void OnAuthorization(HttpActionContext context)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "RequestAuthorization");
}
}
public class CustomActionFilterAttribute : ActionFilterAttribute
{
private string _throwAt;
public CustomActionFilterAttribute(string throwAt)
{
_throwAt = throwAt;
}
public override void OnActionExecuting(HttpActionContext context)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "BeforeActionExecuted");
}
public override void OnActionExecuted(HttpActionExecutedContext context)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "AfterActionExecuted");
}
}
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
private string _throwAt;
public CustomExceptionFilterAttribute(string throwAt)
{
_throwAt = throwAt;
}
public override void OnException(HttpActionExecutedContext context)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "ActionMethodAndExceptionFilter");
}
}
public class CustomContentNegotiator : System.Net.Http.Formatting.DefaultContentNegotiator
{
private string _throwAt;
public CustomContentNegotiator(string throwAt)
{
_throwAt = throwAt;
}
public override ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "ContentNegotiatorNegotiate");
return base.Negotiate(type, request, formatters);
}
}
public class CustomJsonMediaTypeFormatter : JsonMediaTypeFormatter
{
private string _throwAt;
public CustomJsonMediaTypeFormatter(string throwAt)
{
_throwAt = throwAt;
}
public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "MediaTypeFormatterReadFromStreamAsync");
return base.ReadFromStreamAsync(type, stream, contentHeaders, formatterLogger);
}
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext transportContext)
{
ExceptionTestsUtility.CheckForThrow(_throwAt, "MediaTypeFormatterWriteToStreamAsync");
return base.WriteToStreamAsync(type, value, stream, contentHeaders, transportContext);
}
}
public static class ExceptionTestsUtility
{
public static void CheckForThrow(string throwAt, string stage)
{
if (throwAt == stage)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new ObjectContent<string>(String.Format("Error at {0}", stage), new JsonMediaTypeFormatter())
};
throw new HttpResponseException(response);
}
}
}
}

View File

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http
{
public class IncludeErrorDetailTest
{
public static IEnumerable<object[]> Data
{
get
{
return new object[][]
{
new object[] { "localhost", null, true },
new object[] { "127.0.0.1", null, true },
new object[] { "www.foo.com", null, false },
new object[] { "localhost", IncludeErrorDetailPolicy.LocalOnly, true },
new object[] { "www.foo.com", IncludeErrorDetailPolicy.LocalOnly, false },
new object[] { "localhost", IncludeErrorDetailPolicy.Always, true },
new object[] { "www.foo.com", IncludeErrorDetailPolicy.Always, true },
new object[] { "localhost", IncludeErrorDetailPolicy.Never, false },
new object[] { "www.foo.com", IncludeErrorDetailPolicy.Never, false }
};
}
}
[Theory]
[PropertyData("Data")]
public void ThrowingOnActionIncludesErrorDetail(string hostName, IncludeErrorDetailPolicy? includeErrorDetail, bool shouldIncludeErrorDetail)
{
string controllerName = "Exception";
string requestUrl = String.Format("{0}/{1}/{2}", "http://" + hostName, controllerName, "ArgumentNull");
ScenarioHelper.RunTest(
controllerName,
"/{action}",
new HttpRequestMessage(HttpMethod.Post, requestUrl),
(response) =>
{
if (shouldIncludeErrorDetail)
{
AssertResponseIncludesErrorDetail(response);
}
else
{
AssertResponseDoesNotIncludeErrorDetail(response);
}
},
(config) =>
{
if (includeErrorDetail.HasValue)
{
config.IncludeErrorDetailPolicy = includeErrorDetail.Value;
}
}
);
}
private void AssertResponseIncludesErrorDetail(HttpResponseMessage response)
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
dynamic json = JToken.Parse(response.Content.ReadAsStringAsync().Result);
string result = json.ExceptionType;
Assert.Equal(typeof(ArgumentNullException).FullName, result);
}
private void AssertResponseDoesNotIncludeErrorDetail(HttpResponseMessage response)
{
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.Null(response.Content);
}
}
}