Skip to content

Commit 8044f4e

Browse files
authored
Merge pull request #185 from itrofimow/master
Fix for #147
2 parents c40bca3 + e0257cd commit 8044f4e

File tree

5 files changed

+100
-6
lines changed

5 files changed

+100
-6
lines changed

src/System.Web.Http.Cors/CorsHttpConfigurationExtensions.cs

+27-5
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,38 @@ public static class CorsHttpConfigurationExtensions
2626
/// <param name="httpConfiguration">The <see cref="HttpConfiguration"/>.</param>
2727
public static void EnableCors(this HttpConfiguration httpConfiguration)
2828
{
29-
EnableCors(httpConfiguration, null);
29+
EnableCors(httpConfiguration, null, false);
30+
}
31+
32+
/// <summary>
33+
/// Enables the support for CORS.
34+
/// </summary>
35+
/// <param name="httpConfiguration">The <see cref="HttpConfiguration"/>.</param>
36+
/// <param name="rethrowExceptions">Indicates whether upstream exceptions should be rethrown</param>
37+
public static void EnableCors(this HttpConfiguration httpConfiguration, bool rethrowExceptions)
38+
{
39+
EnableCors(httpConfiguration, null, rethrowExceptions);
3040
}
3141

3242
/// <summary>
3343
/// Enables the support for CORS.
3444
/// </summary>
3545
/// <param name="httpConfiguration">The <see cref="HttpConfiguration"/>.</param>
3646
/// <param name="defaultPolicyProvider">The default <see cref="ICorsPolicyProvider"/>.</param>
37-
/// <exception cref="System.ArgumentNullException">httpConfiguration</exception>
3847
public static void EnableCors(this HttpConfiguration httpConfiguration, ICorsPolicyProvider defaultPolicyProvider)
48+
{
49+
EnableCors(httpConfiguration, defaultPolicyProvider, false);
50+
}
51+
52+
/// <summary>
53+
/// Enables the support for CORS.
54+
/// </summary>
55+
/// <param name="httpConfiguration">The <see cref="HttpConfiguration"/>.</param>
56+
/// <param name="defaultPolicyProvider">The default <see cref="ICorsPolicyProvider"/>.</param>
57+
/// <param name="rethrowExceptions">Indicates whether upstream exceptions should be rethrown</param>
58+
/// <exception cref="System.ArgumentNullException">httpConfiguration</exception>
59+
public static void EnableCors(this HttpConfiguration httpConfiguration, ICorsPolicyProvider defaultPolicyProvider,
60+
bool rethrowExceptions)
3961
{
4062
if (httpConfiguration == null)
4163
{
@@ -49,11 +71,11 @@ public static void EnableCors(this HttpConfiguration httpConfiguration, ICorsPol
4971
httpConfiguration.SetCorsPolicyProviderFactory(policyProviderFactory);
5072
}
5173

52-
AddCorsMessageHandler(httpConfiguration);
74+
AddCorsMessageHandler(httpConfiguration, rethrowExceptions);
5375
}
5476

5577
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Caller owns the disposable object")]
56-
private static void AddCorsMessageHandler(this HttpConfiguration httpConfiguration)
78+
private static void AddCorsMessageHandler(this HttpConfiguration httpConfiguration, bool rethrowExceptions)
5779
{
5880
object corsEnabled;
5981
if (!httpConfiguration.Properties.TryGetValue(CorsEnabledKey, out corsEnabled))
@@ -64,7 +86,7 @@ private static void AddCorsMessageHandler(this HttpConfiguration httpConfigurati
6486
if (!config.Properties.TryGetValue(CorsEnabledKey, out corsEnabled))
6587
{
6688
// Execute this in the Initializer to ensure that the CorsMessageHandler is added last.
67-
config.MessageHandlers.Add(new CorsMessageHandler(config));
89+
config.MessageHandlers.Add(new CorsMessageHandler(config, rethrowExceptions));
6890

6991
ITraceWriter traceWriter = config.Services.GetTraceWriter();
7092

src/System.Web.Http.Cors/CorsMessageHandler.cs

+18-1
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,32 @@ namespace System.Web.Http.Cors
1818
public class CorsMessageHandler : DelegatingHandler
1919
{
2020
private HttpConfiguration _httpConfiguration;
21+
private bool _rethrowExceptions;
2122

2223
/// <summary>
2324
/// Initializes a new instance of the <see cref="CorsMessageHandler"/> class.
2425
/// </summary>
2526
/// <param name="httpConfiguration">The <see cref="HttpConfiguration"/>.</param>
2627
/// <exception cref="System.ArgumentNullException">httpConfiguration</exception>
27-
public CorsMessageHandler(HttpConfiguration httpConfiguration)
28+
public CorsMessageHandler(HttpConfiguration httpConfiguration) : this(httpConfiguration, false)
29+
{
30+
}
31+
32+
/// <summary>
33+
/// Initializes a new instance of the <see cref="CorsMessageHandler"/> class.
34+
/// </summary>
35+
/// <param name="httpConfiguration">The <see cref="HttpConfiguration"/>.</param>
36+
/// <param name="rethrowExceptions">Indicates whether upstream exceptions should be rethrown</param>
37+
/// <exception cref="System.ArgumentNullException">httpConfiguration</exception>
38+
public CorsMessageHandler(HttpConfiguration httpConfiguration, bool rethrowExceptions)
2839
{
2940
if (httpConfiguration == null)
3041
{
3142
throw new ArgumentNullException("httpConfiguration");
3243
}
3344

3445
_httpConfiguration = httpConfiguration;
46+
_rethrowExceptions = rethrowExceptions;
3547
}
3648

3749
/// <summary>
@@ -60,6 +72,11 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
6072
}
6173
catch (Exception exception)
6274
{
75+
if (_rethrowExceptions)
76+
{
77+
throw;
78+
}
79+
6380
return HandleException(request, exception);
6481
}
6582
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace System.Web.Http.Cors
2+
{
3+
[EnableCors("*", "*", "*")]
4+
public class ThrowingController : ApiController
5+
{
6+
public string Get()
7+
{
8+
throw new Exception();
9+
}
10+
}
11+
}

test/System.Web.Http.Cors.Test/CorsMessageHandlerTest.cs

+43
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using System.Web.Cors;
10+
using System.Web.Http.ExceptionHandling;
1011
using System.Web.Http.Hosting;
1112
using Microsoft.TestCommon;
1213

@@ -180,6 +181,40 @@ public async Task SendAsync_HandlesExceptions_ThrownDuringPreflight()
180181
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
181182
}
182183

184+
[Fact]
185+
public async Task SendAsync_Preflight_RethrowsExceptions_WhenRethrowFlagIsTrue()
186+
{
187+
HttpConfiguration config = new HttpConfiguration();
188+
config.Routes.MapHttpRoute("default", "{controller}");
189+
HttpServer server = new HttpServer(config);
190+
CorsMessageHandler corsHandler = new CorsMessageHandler(config, true);
191+
corsHandler.InnerHandler = server;
192+
HttpMessageInvoker invoker = new HttpMessageInvoker(corsHandler);
193+
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/sample");
194+
request.SetConfiguration(config);
195+
request.Headers.Add(CorsConstants.Origin, "http://localhost");
196+
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "RandomMethod");
197+
198+
await Assert.ThrowsAsync<HttpResponseException>(() => invoker.SendAsync(request, CancellationToken.None));
199+
}
200+
201+
[Fact]
202+
public async Task SendAsync_RethrowsExceptions_WhenRethrowFlagIsTrue()
203+
{
204+
HttpConfiguration config = new HttpConfiguration();
205+
config.Routes.MapHttpRoute("default", "{controller}");
206+
config.Services.Replace(typeof(IExceptionHandler), new PassthroughExceptionHandler());
207+
HttpServer server = new HttpServer(config);
208+
CorsMessageHandler corsHandler = new CorsMessageHandler(config, true);
209+
corsHandler.InnerHandler = server;
210+
HttpMessageInvoker invoker = new HttpMessageInvoker(corsHandler);
211+
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/throwing");
212+
request.SetConfiguration(config);
213+
request.Headers.Add(CorsConstants.Origin, "http://localhost");
214+
215+
await Assert.ThrowsAsync<Exception>(() => invoker.SendAsync(request, CancellationToken.None));
216+
}
217+
183218
[Fact]
184219
public Task HandleCorsRequestAsync_NullConfig_Throws()
185220
{
@@ -238,5 +273,13 @@ public Task HandleCorsPreflightRequestAsync_NullContext_Throws()
238273
() => corsHandler.HandleCorsPreflightRequestAsync(new HttpRequestMessage(), null, CancellationToken.None),
239274
"corsRequestContext");
240275
}
276+
277+
private class PassthroughExceptionHandler : IExceptionHandler
278+
{
279+
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
280+
{
281+
throw context.Exception;
282+
}
283+
}
241284
}
242285
}

test/System.Web.Http.Cors.Test/System.Web.Http.Cors.Test.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<Compile Include="Controllers\PerControllerConfigController.cs" />
8383
<Compile Include="Controllers\SampleController.cs" />
8484
<Compile Include="Controllers\DefaultController.cs" />
85+
<Compile Include="Controllers\ThrowingController.cs" />
8586
<Compile Include="CorsMessageHandlerTest.cs" />
8687
<Compile Include="DisableCorsAttributeTest.cs" />
8788
<Compile Include="EnableCorsAttributeTest.cs" />

0 commit comments

Comments
 (0)