diff --git a/CORS.sln b/CORS.sln
index 62bed30..f3d81e9 100644
--- a/CORS.sln
+++ b/CORS.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.22529.0
+VisualStudioVersion = 14.0.22711.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{84FE6872-A610-4CEC-855F-A84CBF1F40FC}"
EndProject
@@ -16,6 +16,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F32074C7-0
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cors.Core.Test", "test\Microsoft.AspNet.Cors.Core.Test\Microsoft.AspNet.Cors.Core.Test.xproj", "{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cors", "src\Microsoft.AspNet.Cors\Microsoft.AspNet.Cors.xproj", "{41349FCD-D1C4-47A6-82D0-D16D00A8D59D}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cors.Test", "test\Microsoft.AspNet.Cors.Test\Microsoft.AspNet.Cors.Test.xproj", "{F05BE96F-F869-4408-A480-96935B4835EE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{EEF80A8E-F334-4C66-9537-8D24D002149D}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UseOptions", "samples\UseOptions\UseOptions.xproj", "{8DC90D0F-9660-42AD-BE08-4A7643A8F46E}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UsePolicyBuilder", "samples\UsePolicyBuilder\UsePolicyBuilder.xproj", "{6916DB8A-0246-45F8-9C64-9B05556C1A5D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -30,6 +40,22 @@ Global
{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {41349FCD-D1C4-47A6-82D0-D16D00A8D59D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {41349FCD-D1C4-47A6-82D0-D16D00A8D59D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {41349FCD-D1C4-47A6-82D0-D16D00A8D59D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {41349FCD-D1C4-47A6-82D0-D16D00A8D59D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F05BE96F-F869-4408-A480-96935B4835EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F05BE96F-F869-4408-A480-96935B4835EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F05BE96F-F869-4408-A480-96935B4835EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F05BE96F-F869-4408-A480-96935B4835EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8DC90D0F-9660-42AD-BE08-4A7643A8F46E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8DC90D0F-9660-42AD-BE08-4A7643A8F46E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8DC90D0F-9660-42AD-BE08-4A7643A8F46E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8DC90D0F-9660-42AD-BE08-4A7643A8F46E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6916DB8A-0246-45F8-9C64-9B05556C1A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6916DB8A-0246-45F8-9C64-9B05556C1A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6916DB8A-0246-45F8-9C64-9B05556C1A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6916DB8A-0246-45F8-9C64-9B05556C1A5D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -37,5 +63,9 @@ Global
GlobalSection(NestedProjects) = preSolution
{C573AEE1-8D54-4A83-8D6B-61C85E8F713E} = {84FE6872-A610-4CEC-855F-A84CBF1F40FC}
{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
+ {41349FCD-D1C4-47A6-82D0-D16D00A8D59D} = {84FE6872-A610-4CEC-855F-A84CBF1F40FC}
+ {F05BE96F-F869-4408-A480-96935B4835EE} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
+ {8DC90D0F-9660-42AD-BE08-4A7643A8F46E} = {EEF80A8E-F334-4C66-9537-8D24D002149D}
+ {6916DB8A-0246-45F8-9C64-9B05556C1A5D} = {EEF80A8E-F334-4C66-9537-8D24D002149D}
EndGlobalSection
EndGlobal
diff --git a/samples/UseOptions/Project_Readme.html b/samples/UseOptions/Project_Readme.html
new file mode 100644
index 0000000..b693be4
--- /dev/null
+++ b/samples/UseOptions/Project_Readme.html
@@ -0,0 +1,204 @@
+
+
+
+
+ Welcome to ASP.NET 5
+
+
+
+
+
+
+
+
+
This application consists of:
+
+ - Sample pages using ASP.NET MVC 6
+ - Grunt and Bower for managing client-side resources
+ - Theming using Bootstrap
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/UseOptions/Startup.cs b/samples/UseOptions/Startup.cs
new file mode 100644
index 0000000..5c29d7f
--- /dev/null
+++ b/samples/UseOptions/Startup.cs
@@ -0,0 +1,23 @@
+using System;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.Http;
+using Microsoft.Framework.DependencyInjection;
+
+namespace UseOptions
+{
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddCors();
+ services.ConfigureCors(
+ options =>
+ options.AddPolicy("allowSingleOrigin", builder => builder.WithOrigins("http://example.com")));
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseCors("allowSingleOrigin");
+ }
+ }
+}
diff --git a/samples/UseOptions/UseOptions.xproj b/samples/UseOptions/UseOptions.xproj
new file mode 100644
index 0000000..0ad1f53
--- /dev/null
+++ b/samples/UseOptions/UseOptions.xproj
@@ -0,0 +1,19 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 8dc90d0f-9660-42ad-be08-4a7643a8f46e
+ UseOptions
+ ..\artifacts\obj\$(MSBuildProjectName)
+ ..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+ 5442
+
+
+
\ No newline at end of file
diff --git a/samples/UseOptions/project.json b/samples/UseOptions/project.json
new file mode 100644
index 0000000..6bcdc93
--- /dev/null
+++ b/samples/UseOptions/project.json
@@ -0,0 +1,30 @@
+{
+ "webroot": "wwwroot",
+ "version": "1.0.0-*",
+ "dependencies": {
+ "Microsoft.AspNet.Cors": "1.0.0-*",
+ "Microsoft.AspNet.Diagnostics": "1.0.0-*",
+ "Microsoft.AspNet.Server.IIS": "1.0.0-*",
+ "Microsoft.AspNet.Server.WebListener": "1.0.0-*",
+ "Microsoft.Framework.Logging.Console": "1.0.0-*"
+ },
+ "commands": {
+ "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
+ },
+ "frameworks": {
+ "dnx451": {},
+ "dnxcore50": {}
+ },
+ "bundleExclude": [
+ "node_modules",
+ "bower_components",
+ "**.kproj",
+ "**.user",
+ "**.vspscc"
+ ],
+ "exclude": [
+ "wwwroot",
+ "node_modules",
+ "bower_components"
+ ]
+}
\ No newline at end of file
diff --git a/samples/UsePolicyBuilder/Project_Readme.html b/samples/UsePolicyBuilder/Project_Readme.html
new file mode 100644
index 0000000..b693be4
--- /dev/null
+++ b/samples/UsePolicyBuilder/Project_Readme.html
@@ -0,0 +1,204 @@
+
+
+
+
+ Welcome to ASP.NET 5
+
+
+
+
+
+
+
+
+
This application consists of:
+
+ - Sample pages using ASP.NET MVC 6
+ - Grunt and Bower for managing client-side resources
+ - Theming using Bootstrap
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/UsePolicyBuilder/Startup.cs b/samples/UsePolicyBuilder/Startup.cs
new file mode 100644
index 0000000..de8233c
--- /dev/null
+++ b/samples/UsePolicyBuilder/Startup.cs
@@ -0,0 +1,21 @@
+using System;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.Cors.Core;
+using Microsoft.AspNet.Http;
+using Microsoft.Framework.DependencyInjection;
+
+namespace UsePolicy
+{
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddCors();
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseCors(policy => policy.WithOrigins("http://example.com"));
+ }
+ }
+}
diff --git a/samples/UsePolicyBuilder/UsePolicyBuilder.xproj b/samples/UsePolicyBuilder/UsePolicyBuilder.xproj
new file mode 100644
index 0000000..cf8bbbd
--- /dev/null
+++ b/samples/UsePolicyBuilder/UsePolicyBuilder.xproj
@@ -0,0 +1,19 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 6916db8a-0246-45f8-9c64-9b05556c1a5d
+ UseOptions
+ ..\artifacts\obj\$(MSBuildProjectName)
+ ..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+ 12497
+
+
+
\ No newline at end of file
diff --git a/samples/UsePolicyBuilder/project.json b/samples/UsePolicyBuilder/project.json
new file mode 100644
index 0000000..6bcdc93
--- /dev/null
+++ b/samples/UsePolicyBuilder/project.json
@@ -0,0 +1,30 @@
+{
+ "webroot": "wwwroot",
+ "version": "1.0.0-*",
+ "dependencies": {
+ "Microsoft.AspNet.Cors": "1.0.0-*",
+ "Microsoft.AspNet.Diagnostics": "1.0.0-*",
+ "Microsoft.AspNet.Server.IIS": "1.0.0-*",
+ "Microsoft.AspNet.Server.WebListener": "1.0.0-*",
+ "Microsoft.Framework.Logging.Console": "1.0.0-*"
+ },
+ "commands": {
+ "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
+ },
+ "frameworks": {
+ "dnx451": {},
+ "dnxcore50": {}
+ },
+ "bundleExclude": [
+ "node_modules",
+ "bower_components",
+ "**.kproj",
+ "**.user",
+ "**.vspscc"
+ ],
+ "exclude": [
+ "wwwroot",
+ "node_modules",
+ "bower_components"
+ ]
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors.Core/CorsOptions.cs b/src/Microsoft.AspNet.Cors.Core/CorsOptions.cs
index 7d76181..0a94c70 100644
--- a/src/Microsoft.AspNet.Cors.Core/CorsOptions.cs
+++ b/src/Microsoft.AspNet.Cors.Core/CorsOptions.cs
@@ -13,8 +13,27 @@ namespace Microsoft.AspNet.Cors.Core
///
public class CorsOptions
{
+ private string _defaultPolicyName = "__DefaultCorsPolicy";
private IDictionary PolicyMap { get; } = new Dictionary();
+ public string DefaultPolicyName
+ {
+ get
+ {
+ return _defaultPolicyName;
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ _defaultPolicyName = value;
+ }
+ }
+
///
/// Adds a new policy.
///
diff --git a/src/Microsoft.AspNet.Cors.Core/CorsPolicyBuilder.cs b/src/Microsoft.AspNet.Cors.Core/CorsPolicyBuilder.cs
index 8330300..b9dd7d9 100644
--- a/src/Microsoft.AspNet.Cors.Core/CorsPolicyBuilder.cs
+++ b/src/Microsoft.AspNet.Cors.Core/CorsPolicyBuilder.cs
@@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Cors
/// list of origins which can be added.
public CorsPolicyBuilder(params string[] origins)
{
- AddOrigins(origins);
+ WithOrigins(origins);
}
///
@@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Cors
///
/// The origins that are allowed.
/// The current policy builder
- public CorsPolicyBuilder AddOrigins(params string[] origins)
+ public CorsPolicyBuilder WithOrigins(params string[] origins)
{
foreach (var req in origins)
{
@@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Cors
///
/// The headers which need to be allowed in the request.
/// The current policy builder
- public CorsPolicyBuilder AddHeaders(params string[] headers)
+ public CorsPolicyBuilder WithHeaders(params string[] headers)
{
foreach (var req in headers)
{
@@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Cors
///
/// The headers which need to be exposed to the client.
/// The current policy builder
- public CorsPolicyBuilder AddExposedHeaders(params string[] exposedHeaders)
+ public CorsPolicyBuilder WithExposedHeaders(params string[] exposedHeaders)
{
foreach (var req in exposedHeaders)
{
@@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Cors
///
/// The methods which need to be added to the policy.
/// The current policy builder
- public CorsPolicyBuilder AddMethods(params string[] methods)
+ public CorsPolicyBuilder WithMethods(params string[] methods)
{
foreach (var req in methods)
{
@@ -173,10 +173,10 @@ namespace Microsoft.AspNet.Cors
/// The current policy builder
private CorsPolicyBuilder Combine([NotNull] CorsPolicy policy)
{
- AddOrigins(policy.Origins.ToArray());
- AddHeaders(policy.Headers.ToArray());
- AddExposedHeaders(policy.ExposedHeaders.ToArray());
- AddMethods(policy.Methods.ToArray());
+ WithOrigins(policy.Origins.ToArray());
+ WithHeaders(policy.Headers.ToArray());
+ WithExposedHeaders(policy.ExposedHeaders.ToArray());
+ WithMethods(policy.Methods.ToArray());
SetPreflightMaxAge(policy.PreflightMaxAge.Value);
if (policy.SupportsCredentials)
diff --git a/src/Microsoft.AspNet.Cors.Core/CorsServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Cors.Core/CorsServiceCollectionExtensions.cs
index adb38d1..544b426 100644
--- a/src/Microsoft.AspNet.Cors.Core/CorsServiceCollectionExtensions.cs
+++ b/src/Microsoft.AspNet.Cors.Core/CorsServiceCollectionExtensions.cs
@@ -36,6 +36,7 @@ namespace Microsoft.Framework.DependencyInjection
{
serviceCollection.AddOptions();
serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
return serviceCollection;
}
}
diff --git a/src/Microsoft.AspNet.Cors.Core/DefaultCorsPolicyProvider.cs b/src/Microsoft.AspNet.Cors.Core/DefaultCorsPolicyProvider.cs
new file mode 100644
index 0000000..307744e
--- /dev/null
+++ b/src/Microsoft.AspNet.Cors.Core/DefaultCorsPolicyProvider.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
+using Microsoft.Framework.Internal;
+using Microsoft.Framework.OptionsModel;
+
+namespace Microsoft.AspNet.Cors.Core
+{
+ ///
+ public class DefaultCorsPolicyProvider : ICorsPolicyProvider
+ {
+ private readonly CorsOptions _options;
+
+ ///
+ /// Creates a new instance of .
+ ///
+ /// The options configured for the application.
+ public DefaultCorsPolicyProvider(IOptions options)
+ {
+ _options = options.Options;
+ }
+
+ ///
+ public Task GetPolicyAsync(HttpContext context, string policyName)
+ {
+ return Task.FromResult(_options.GetPolicy(policyName ?? _options.DefaultPolicyName));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors.Core/ICorsPolicyProvider.cs b/src/Microsoft.AspNet.Cors.Core/ICorsPolicyProvider.cs
new file mode 100644
index 0000000..b837230
--- /dev/null
+++ b/src/Microsoft.AspNet.Cors.Core/ICorsPolicyProvider.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
+using Microsoft.Framework.Internal;
+
+namespace Microsoft.AspNet.Cors.Core
+{
+ ///
+ /// A type which can provide a for a particular .
+ ///
+ public interface ICorsPolicyProvider
+ {
+ ///
+ /// Gets a from the given
+ ///
+ /// The associated with this call.
+ /// An optional policy name to look for.
+ /// A
+ Task GetPolicyAsync([NotNull] HttpContext context, string policyName);
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Cors.Core/Properties/Resources.Designer.cs
index f50fb00..8b6e085 100644
--- a/src/Microsoft.AspNet.Cors.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Cors.Core/Properties/Resources.Designer.cs
@@ -10,70 +10,6 @@ namespace Microsoft.AspNet.Cors.Core
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Cors.Core.Resources", typeof(Resources).GetTypeInfo().Assembly);
- ///
- /// The collection of headers '{0}' is not allowed.
- ///
- internal static string HeadersNotAllowed
- {
- get { return GetString("HeadersNotAllowed"); }
- }
-
- ///
- /// The collection of headers '{0}' is not allowed.
- ///
- internal static string FormatHeadersNotAllowed(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("HeadersNotAllowed"), p0);
- }
-
- ///
- /// The method '{0}' is not allowed.
- ///
- internal static string MethodNotAllowed
- {
- get { return GetString("MethodNotAllowed"); }
- }
-
- ///
- /// The method '{0}' is not allowed.
- ///
- internal static string FormatMethodNotAllowed(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("MethodNotAllowed"), p0);
- }
-
- ///
- /// The request does not contain the Origin header.
- ///
- internal static string NoOriginHeader
- {
- get { return GetString("NoOriginHeader"); }
- }
-
- ///
- /// The request does not contain the Origin header.
- ///
- internal static string FormatNoOriginHeader()
- {
- return GetString("NoOriginHeader");
- }
-
- ///
- /// The origin '{0}' is not allowed.
- ///
- internal static string OriginNotAllowed
- {
- get { return GetString("OriginNotAllowed"); }
- }
-
- ///
- /// The origin '{0}' is not allowed.
- ///
- internal static string FormatOriginNotAllowed(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("OriginNotAllowed"), p0);
- }
-
///
/// PreflightMaxAge must be greater than or equal to 0.
///
diff --git a/src/Microsoft.AspNet.Cors.Core/Resources.resx b/src/Microsoft.AspNet.Cors.Core/Resources.resx
index ef0e5b5..6b9ebaa 100644
--- a/src/Microsoft.AspNet.Cors.Core/Resources.resx
+++ b/src/Microsoft.AspNet.Cors.Core/Resources.resx
@@ -117,19 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- The collection of headers '{0}' is not allowed.
-
-
- The method '{0}' is not allowed.
-
-
- The request does not contain the Origin header.
-
-
- The origin '{0}' is not allowed.
-
-
+
PreflightMaxAge must be greater than or equal to 0.
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors/CorsMiddleware.cs b/src/Microsoft.AspNet.Cors/CorsMiddleware.cs
new file mode 100644
index 0000000..21c079e
--- /dev/null
+++ b/src/Microsoft.AspNet.Cors/CorsMiddleware.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.Cors.Core;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.WebUtilities;
+using Microsoft.Framework.Internal;
+using Microsoft.Framework.OptionsModel;
+
+namespace Microsoft.AspNet.Cors
+{
+ ///
+ /// An ASP.NET middleware for handling CORS.
+ ///
+ public class CorsMiddleware
+ {
+ private readonly RequestDelegate _next;
+ private readonly ICorsService _corsService;
+ private readonly ICorsPolicyProvider _corsPolicyProvider;
+ private readonly CorsPolicy _policy;
+ private readonly string _corsPolicyName;
+
+ ///
+ /// Instantiates a new .
+ ///
+ /// The next middleware in the pipeline.
+ /// An instance of .
+ /// A policy provider which can get an .
+ /// An optional name of the policy to be fetched.
+ public CorsMiddleware(
+ [NotNull] RequestDelegate next,
+ [NotNull] ICorsService corsService,
+ [NotNull] ICorsPolicyProvider policyProvider,
+ string policyName)
+ {
+ _next = next;
+ _corsService = corsService;
+ _corsPolicyProvider = policyProvider;
+ _corsPolicyName = policyName;
+ }
+
+ ///
+ /// Instantiates a new .
+ ///
+ /// The next middleware in the pipeline.
+ /// An instance of .
+ /// An instance of the which can be applied.
+ public CorsMiddleware(
+ [NotNull] RequestDelegate next,
+ [NotNull] ICorsService corsService,
+ [NotNull] CorsPolicy policy)
+ {
+ _next = next;
+ _corsService = corsService;
+ _policy = policy;
+ }
+
+ ///
+ public async Task Invoke(HttpContext context)
+ {
+ if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
+ {
+ var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
+ if (corsPolicy != null)
+ {
+ var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
+ _corsService.ApplyResult(corsResult, context.Response);
+
+ var accessControlRequestMethod =
+ context.Request.Headers.Get(CorsConstants.AccessControlRequestMethod);
+ if (string.Equals(
+ context.Request.Method,
+ CorsConstants.PreflightHttpMethod,
+ StringComparison.Ordinal) &&
+ accessControlRequestMethod != null)
+ {
+ // Since there is a policy which was identified,
+ // always respond to preflight requests.
+ context.Response.StatusCode = StatusCodes.Status204NoContent;
+ return;
+ }
+ }
+ }
+
+ await _next(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors/CorsMiddlewareExtensions.cs b/src/Microsoft.AspNet.Cors/CorsMiddlewareExtensions.cs
new file mode 100644
index 0000000..88e529d
--- /dev/null
+++ b/src/Microsoft.AspNet.Cors/CorsMiddlewareExtensions.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Cors;
+using Microsoft.AspNet.Cors.Core;
+using Microsoft.Framework.Internal;
+
+namespace Microsoft.AspNet.Builder
+{
+ ///
+ /// The extensions for adding CORS middleware support.
+ ///
+ public static class CorsMiddlewareExtensions
+ {
+ ///
+ /// Adds a CORS middleware to your web application pipeline to allow cross domain requests.
+ ///
+ /// The IApplicationBuilder passed to your Configure method
+ /// The policy name of a configured policy.
+ /// The original app parameter
+ public static IApplicationBuilder UseCors([NotNull]this IApplicationBuilder app, string policyName)
+ {
+ return app.UseMiddleware(policyName);
+ }
+
+ ///
+ /// Adds a CORS middleware to your web application pipeline to allow cross domain requests.
+ ///
+ /// The IApplicationBuilder passed to your Configure method.
+ /// A delegate which can use a policy builder to build a policy.
+ /// The original app parameter
+ public static IApplicationBuilder UseCors(
+ [NotNull] this IApplicationBuilder app,
+ [NotNull] Action configurePolicy)
+ {
+ var policyBuilder = new CorsPolicyBuilder();
+ configurePolicy(policyBuilder);
+ return app.UseMiddleware(policyBuilder.Build());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors/Microsoft.AspNet.Cors.xproj b/src/Microsoft.AspNet.Cors/Microsoft.AspNet.Cors.xproj
new file mode 100644
index 0000000..34f1a25
--- /dev/null
+++ b/src/Microsoft.AspNet.Cors/Microsoft.AspNet.Cors.xproj
@@ -0,0 +1,20 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 41349fcd-d1c4-47a6-82d0-d16d00a8d59d
+ Microsoft.AspNet.Cors
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Cors/project.json b/src/Microsoft.AspNet.Cors/project.json
new file mode 100644
index 0000000..bf9e28e
--- /dev/null
+++ b/src/Microsoft.AspNet.Cors/project.json
@@ -0,0 +1,21 @@
+{
+ "version": "1.0.0-*",
+ "dependencies": {
+ "Microsoft.AspNet.Cors.Core": "1.0.0-*",
+ "Microsoft.AspNet.RequestContainer": "1.0.0-*",
+ "Microsoft.AspNet.WebUtilities": "1.0.0-*",
+ "Microsoft.Framework.NotNullAttribute.Internal": { "version": "1.0.0-*", "type": "build" }
+ },
+
+ "frameworks" : {
+ "dnx451" : {
+ "dependencies": {
+ }
+ },
+ "dnxcore50" : {
+ "dependencies": {
+ "System.Runtime": "4.0.20-beta-*"
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Cors.Core.Test/CorsPolicyBuilderTests.cs b/test/Microsoft.AspNet.Cors.Core.Test/CorsPolicyBuilderTests.cs
index 3a7a722..2b6d424 100644
--- a/test/Microsoft.AspNet.Cors.Core.Test/CorsPolicyBuilderTests.cs
+++ b/test/Microsoft.AspNet.Cors.Core.Test/CorsPolicyBuilderTests.cs
@@ -83,13 +83,13 @@ namespace Microsoft.AspNet.Cors.Core.Test
}
[Fact]
- public void AddOrigins_AddsOrigins()
+ public void WithOrigins_AddsOrigins()
{
// Arrange
var builder = new CorsPolicyBuilder();
// Act
- builder.AddOrigins("http://example.com", "http://example2.com");
+ builder.WithOrigins("http://example.com", "http://example2.com");
// Assert
var corsPolicy = builder.Build();
@@ -114,13 +114,13 @@ namespace Microsoft.AspNet.Cors.Core.Test
[Fact]
- public void AddMethods_AddsMethods()
+ public void WithMethods_AddsMethods()
{
// Arrange
var builder = new CorsPolicyBuilder();
// Act
- builder.AddMethods("PUT", "GET");
+ builder.WithMethods("PUT", "GET");
// Assert
var corsPolicy = builder.Build();
@@ -144,13 +144,13 @@ namespace Microsoft.AspNet.Cors.Core.Test
}
[Fact]
- public void AddHeaders_AddsHeaders()
+ public void WithHeaders_AddsHeaders()
{
// Arrange
var builder = new CorsPolicyBuilder();
// Act
- builder.AddHeaders("example1", "example2");
+ builder.WithHeaders("example1", "example2");
// Assert
var corsPolicy = builder.Build();
@@ -174,13 +174,13 @@ namespace Microsoft.AspNet.Cors.Core.Test
}
[Fact]
- public void AddExposedHeaders_AddsExposedHeaders()
+ public void WithExposedHeaders_AddsExposedHeaders()
{
// Arrange
var builder = new CorsPolicyBuilder();
// Act
- builder.AddExposedHeaders("exposed1", "exposed2");
+ builder.WithExposedHeaders("exposed1", "exposed2");
// Assert
var corsPolicy = builder.Build();
diff --git a/test/Microsoft.AspNet.Cors.Core.Test/DefaultCorsPolicyProviderTests.cs b/test/Microsoft.AspNet.Cors.Core.Test/DefaultCorsPolicyProviderTests.cs
new file mode 100644
index 0000000..a04297b
--- /dev/null
+++ b/test/Microsoft.AspNet.Cors.Core.Test/DefaultCorsPolicyProviderTests.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http.Core;
+using Microsoft.Framework.OptionsModel;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Cors.Core.Test
+{
+ public class DefaultPolicyProviderTests
+ {
+ [Fact]
+ public async Task UsesTheDefaultPolicyName()
+ {
+ // Arrange
+ var options = new CorsOptions();
+ var policy = new CorsPolicy();
+ options.AddPolicy(options.DefaultPolicyName, policy);
+
+ var mockOptions = new Mock>();
+ mockOptions
+ .SetupGet(o => o.Options)
+ .Returns(options);
+ var policyProvider = new DefaultCorsPolicyProvider(mockOptions.Object);
+
+ // Act
+ var actualPolicy = await policyProvider.GetPolicyAsync(new DefaultHttpContext(), policyName: null);
+
+ // Assert
+ Assert.Same(policy, actualPolicy);
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData("policyName")]
+ public async Task GetsNamedPolicy(string policyName)
+ {
+ // Arrange
+ var options = new CorsOptions();
+ var policy = new CorsPolicy();
+ options.AddPolicy(policyName, policy);
+
+ var mockOptions = new Mock>();
+ mockOptions
+ .SetupGet(o => o.Options)
+ .Returns(options);
+ var policyProvider = new DefaultCorsPolicyProvider(mockOptions.Object);
+
+ // Act
+ var actualPolicy = await policyProvider.GetPolicyAsync(new DefaultHttpContext(), policyName);
+
+ // Assert
+ Assert.Same(policy, actualPolicy);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Cors.Core.Test/project.json b/test/Microsoft.AspNet.Cors.Core.Test/project.json
index 3391960..4c01305 100644
--- a/test/Microsoft.AspNet.Cors.Core.Test/project.json
+++ b/test/Microsoft.AspNet.Cors.Core.Test/project.json
@@ -5,11 +5,11 @@
"Microsoft.AspNet.Cors.Core": "1.0.0-*",
"Microsoft.AspNet.Http.Core": "1.0.0-*",
"Moq": "4.2.1312.1622",
- "xunit.runner.kre": "1.0.0-*"
+ "xunit.runner.aspnet": "2.0.0-aspnet-*"
},
"commands": {
- "test": "xunit.runner.kre"
+ "test": "xunit.runner.aspnet"
},
"frameworks" : {
diff --git a/test/Microsoft.AspNet.Cors.Test/CorsMiddlewareTests.cs b/test/Microsoft.AspNet.Cors.Test/CorsMiddlewareTests.cs
new file mode 100644
index 0000000..fc7da7b
--- /dev/null
+++ b/test/Microsoft.AspNet.Cors.Test/CorsMiddlewareTests.cs
@@ -0,0 +1,214 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.Cors.Core;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Http.Core;
+using Microsoft.AspNet.TestHost;
+using Microsoft.Framework.DependencyInjection;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Cors.Test
+{
+ public class CorsMiddlewareTests
+ {
+ [Fact]
+ public async Task CorsRequest_MatchPolicy_SetsResponseHeaders()
+ {
+ // Arrange
+ using (var server = TestServer.Create(app =>
+ {
+ app.UseServices(services => services.AddCors());
+ app.UseCors(builder =>
+ builder.WithOrigins("http://localhost:5001")
+ .WithMethods("PUT")
+ .WithHeaders("Header1")
+ .WithExposedHeaders("AllowedHeader"));
+ app.Run(async context =>
+ {
+ await context.Response.WriteAsync("Cross origin response");
+ });
+ }))
+ {
+ // Act
+ // Actual request.
+ var response = await server.CreateRequest("/")
+ .AddHeader(CorsConstants.Origin, "http://localhost:5001")
+ .SendAsync("PUT");
+
+ // Assert
+ response.EnsureSuccessStatusCode();
+ Assert.Equal(2, response.Headers.Count());
+ Assert.Equal("Cross origin response", await response.Content.ReadAsStringAsync());
+ Assert.Equal("http://localhost:5001", response.Headers.GetValues(CorsConstants.AccessControlAllowOrigin).FirstOrDefault());
+ Assert.Equal("AllowedHeader", response.Headers.GetValues(CorsConstants.AccessControlExposeHeaders).FirstOrDefault());
+ }
+ }
+
+ [Fact]
+ public async Task PreFlight_MatchesPolicy_SetsResponseHeaders()
+ {
+ // Arrange
+ var policy = new CorsPolicy();
+ policy.Origins.Add("http://localhost:5001");
+ policy.Methods.Add("PUT");
+ policy.Headers.Add("Header1");
+ policy.ExposedHeaders.Add("AllowedHeader");
+
+ using (var server = TestServer.Create(app =>
+ {
+ app.UseServices(services =>
+ {
+ services.AddCors();
+ services.ConfigureCors(options =>
+ {
+ options.AddPolicy("customPolicy", policy);
+ });
+ });
+ app.UseCors("customPolicy");
+ app.Run(async context =>
+ {
+ await context.Response.WriteAsync("Cross origin response");
+ });
+ }))
+ {
+ // Act
+ // Preflight request.
+ var response = await server.CreateRequest("/")
+ .AddHeader(CorsConstants.Origin, "http://localhost:5001")
+ .AddHeader(CorsConstants.AccessControlRequestMethod, "PUT")
+ .SendAsync(CorsConstants.PreflightHttpMethod);
+
+ // Assert
+ response.EnsureSuccessStatusCode();
+ Assert.Equal(2, response.Headers.Count());
+ Assert.Equal("http://localhost:5001", response.Headers.GetValues(CorsConstants.AccessControlAllowOrigin).FirstOrDefault());
+ Assert.Equal("PUT", response.Headers.GetValues(CorsConstants.AccessControlAllowMethods).FirstOrDefault());
+ }
+ }
+
+ [Fact]
+ public async Task PreFlightRequest_DoesNotMatchPolicy_DoesNotSetHeaders()
+ {
+ // Arrange
+ using (var server = TestServer.Create(app =>
+ {
+ app.UseServices(services => services.AddCors());
+ app.UseCors(builder =>
+ builder.WithOrigins("http://localhost:5001")
+ .WithMethods("PUT")
+ .WithHeaders("Header1")
+ .WithExposedHeaders("AllowedHeader"));
+ app.Run(async context =>
+ {
+ await context.Response.WriteAsync("Cross origin response");
+ });
+ }))
+ {
+ // Act
+ // Preflight request.
+ var response = await server.CreateRequest("/")
+ .AddHeader(CorsConstants.Origin, "http://localhost:5002")
+ .AddHeader(CorsConstants.AccessControlRequestMethod, "PUT")
+ .SendAsync(CorsConstants.PreflightHttpMethod);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
+ Assert.Empty(response.Headers);
+ }
+ }
+
+ [Fact]
+ public async Task CorsRequest_DoesNotMatchPolicy_DoesNotSetHeaders()
+ {
+ // Arrange
+ using (var server = TestServer.Create(app =>
+ {
+ app.UseServices(services => services.AddCors());
+ app.UseCors(builder =>
+ builder.WithOrigins("http://localhost:5001")
+ .WithMethods("PUT")
+ .WithHeaders("Header1")
+ .WithExposedHeaders("AllowedHeader"));
+ app.Run(async context =>
+ {
+ await context.Response.WriteAsync("Cross origin response");
+ });
+ }))
+ {
+ // Act
+ // Actual request.
+ var response = await server.CreateRequest("/")
+ .AddHeader(CorsConstants.Origin, "http://localhost:5002")
+ .SendAsync("PUT");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Empty(response.Headers);
+ }
+ }
+
+ [Fact]
+ public async Task Uses_PolicyProvider_AsFallback()
+ {
+ // Arrange
+ var corsService = Mock.Of();
+ var mockProvider = new Mock();
+ mockProvider.Setup(o => o.GetPolicyAsync(It.IsAny(), It.IsAny()))
+ .Returns(Task.FromResult(null))
+ .Verifiable();
+
+ var middleware = new CorsMiddleware(
+ Mock.Of(),
+ corsService,
+ mockProvider.Object,
+ policyName: null);
+
+ var httpContext = new DefaultHttpContext();
+ httpContext.Request.Headers.Add(CorsConstants.Origin, new[] { "http://example.com" });
+
+ // Act
+ await middleware.Invoke(httpContext);
+
+ // Assert
+ mockProvider.Verify(
+ o => o.GetPolicyAsync(It.IsAny(), It.IsAny()),
+ Times.Once);
+ }
+
+ [Fact]
+ public async Task DoesNotSetHeaders_ForNoPolicy()
+ {
+ // Arrange
+ var corsService = Mock.Of();
+ var mockProvider = new Mock();
+ mockProvider.Setup(o => o.GetPolicyAsync(It.IsAny(), It.IsAny()))
+ .Returns(Task.FromResult(null))
+ .Verifiable();
+
+ var middleware = new CorsMiddleware(
+ Mock.Of(),
+ corsService,
+ mockProvider.Object,
+ policyName: null);
+
+ var httpContext = new DefaultHttpContext();
+ httpContext.Request.Headers.Add(CorsConstants.Origin, new[] { "http://example.com" });
+
+ // Act
+ await middleware.Invoke(httpContext);
+
+ // Assert
+ Assert.Equal(200, httpContext.Response.StatusCode);
+ Assert.Empty(httpContext.Response.Headers);
+ mockProvider.Verify(
+ o => o.GetPolicyAsync(It.IsAny(), It.IsAny()),
+ Times.Once);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Cors.Test/Microsoft.AspNet.Cors.Test.xproj b/test/Microsoft.AspNet.Cors.Test/Microsoft.AspNet.Cors.Test.xproj
new file mode 100644
index 0000000..e1e0c40
--- /dev/null
+++ b/test/Microsoft.AspNet.Cors.Test/Microsoft.AspNet.Cors.Test.xproj
@@ -0,0 +1,20 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ f05be96f-f869-4408-a480-96935b4835ee
+ Microsoft.AspNet.Cors.Test
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Cors.Test/project.json b/test/Microsoft.AspNet.Cors.Test/project.json
new file mode 100644
index 0000000..a75b306
--- /dev/null
+++ b/test/Microsoft.AspNet.Cors.Test/project.json
@@ -0,0 +1,17 @@
+{
+ "version": "1.0.0-*",
+ "dependencies": {
+ "Microsoft.AspNet.Cors": "1.0.0-*",
+ "Microsoft.AspNet.TestHost": "1.0.0-*",
+ "Moq": "4.2.1312.1622",
+ "xunit.runner.aspnet": "2.0.0-aspnet-*"
+ },
+ "commands": {
+ "test": "xunit.runner.aspnet"
+ },
+ "frameworks": {
+ "dnx451": {
+ "dependencies": {}
+ }
+ }
+}
\ No newline at end of file