Adding Base interfaces for Cors.Core
This commit is contained in:
parent
dd870750ec
commit
8e399cd83d
11
CORS.sln
11
CORS.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22604.0
|
||||
VisualStudioVersion = 14.0.22529.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{84FE6872-A610-4CEC-855F-A84CBF1F40FC}"
|
||||
EndProject
|
||||
|
|
@ -12,6 +12,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cors.Core", "src\Microsoft.AspNet.Cors.Core\Microsoft.AspNet.Cors.Core.kproj", "{C573AEE1-8D54-4A83-8D6B-61C85E8F713E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F32074C7-087C-46CC-A913-422BFD2D6E0A}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cors.Core.Test", "test\Microsoft.AspNet.Cors.Core.Test\Microsoft.AspNet.Cors.Core.Test.kproj", "{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -22,11 +26,16 @@ Global
|
|||
{C573AEE1-8D54-4A83-8D6B-61C85E8F713E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C573AEE1-8D54-4A83-8D6B-61C85E8F713E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C573AEE1-8D54-4A83-8D6B-61C85E8F713E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C573AEE1-8D54-4A83-8D6B-61C85E8F713E} = {84FE6872-A610-4CEC-855F-A84CBF1F40FC}
|
||||
{B4F83A06-EB8E-4186-84C4-C6DAF7EB03D4} = {F32074C7-087C-46CC-A913-422BFD2D6E0A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"sources": ["src"]
|
||||
"sources": ["src", "test"]
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// CORS-related constants.
|
||||
/// </summary>
|
||||
public static class CorsConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// The HTTP method for the CORS preflight request.
|
||||
/// </summary>
|
||||
public static readonly string PreflightHttpMethod = "OPTIONS";
|
||||
|
||||
/// <summary>
|
||||
/// The Origin request header.
|
||||
/// </summary>
|
||||
public static readonly string Origin = "Origin";
|
||||
|
||||
/// <summary>
|
||||
/// The value for the Access-Control-Allow-Origin response header to allow all origins.
|
||||
/// </summary>
|
||||
public static readonly string AnyOrigin = "*";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Request-Method request header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlRequestMethod = "Access-Control-Request-Method";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Request-Headers request header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlRequestHeaders = "Access-Control-Request-Headers";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Allow-Origin response header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Allow-Headers response header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Expose-Headers response header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Allow-Methods response header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlAllowMethods = "Access-Control-Allow-Methods";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Allow-Credentials response header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
|
||||
|
||||
/// <summary>
|
||||
/// The Access-Control-Max-Age response header.
|
||||
/// </summary>
|
||||
public static readonly string AccessControlMaxAge = "Access-Control-Max-Age";
|
||||
|
||||
internal static readonly string[] SimpleRequestHeaders =
|
||||
{
|
||||
"Origin",
|
||||
"Accept",
|
||||
"Accept-Language",
|
||||
"Content-Language",
|
||||
};
|
||||
|
||||
internal static readonly string[] SimpleResponseHeaders =
|
||||
{
|
||||
"Cache-Control",
|
||||
"Content-Language",
|
||||
"Content-Type",
|
||||
"Expires",
|
||||
"Last-Modified",
|
||||
"Pragma"
|
||||
};
|
||||
|
||||
internal static readonly string[] SimpleMethods =
|
||||
{
|
||||
"GET",
|
||||
"HEAD",
|
||||
"POST"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// 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.Collections.Generic;
|
||||
using Microsoft.AspNet.Cors.Core;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides programmatic configuration for Cors.
|
||||
/// </summary>
|
||||
public class CorsOptions
|
||||
{
|
||||
private IDictionary<string, CorsPolicy> PolicyMap { get; } = new Dictionary<string, CorsPolicy>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new policy.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the policy.</param>
|
||||
/// <param name="policy">The <see cref="CorsPolicy"/> policy to be added.</param>
|
||||
public void AddPolicy([NotNull] string name, [NotNull] CorsPolicy policy)
|
||||
{
|
||||
PolicyMap[name] = policy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new policy.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the policy.</param>
|
||||
/// <param name="configurePolicy">A delegate which can use a policy builder to build a policy.</param>
|
||||
public void AddPolicy([NotNull] string name, [NotNull] Action<CorsPolicyBuilder> configurePolicy)
|
||||
{
|
||||
var policyBuilder = new CorsPolicyBuilder();
|
||||
configurePolicy(policyBuilder);
|
||||
PolicyMap[name] = policyBuilder.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the policy based on the <paramref name="name"/>
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the policy to lookup.</param>
|
||||
/// <returns>The <see cref="CorsPolicy"/> if the policy was added.<c>null</c> otherwise.</returns>
|
||||
public CorsPolicy GetPolicy([NotNull] string name)
|
||||
{
|
||||
return PolicyMap.ContainsKey(name) ? PolicyMap[name] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the policy for Cross-Origin requests based on the CORS specifications.
|
||||
/// </summary>
|
||||
public class CorsPolicy
|
||||
{
|
||||
private TimeSpan? _preflightMaxAge;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if all headers are allowed.
|
||||
/// </summary>
|
||||
public bool AllowAnyHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Headers == null || Headers.Count != 1 || Headers.Count == 1 && Headers[0] != "*")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if all methods are allowed.
|
||||
/// </summary>
|
||||
public bool AllowAnyMethod
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Methods == null || Methods.Count != 1 || Methods.Count == 1 && Methods[0] != "*")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if all origins are allowed.
|
||||
/// </summary>
|
||||
public bool AllowAnyOrigin
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Origins == null || Origins.Count != 1 || Origins.Count == 1 && Origins[0] != "*")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the headers that the resource might use and can be exposed.
|
||||
/// </summary>
|
||||
public IList<string> ExposedHeaders { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the headers that are supported by the resource.
|
||||
/// </summary>
|
||||
public IList<string> Headers { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the methods that are supported by the resource.
|
||||
/// </summary>
|
||||
public IList<string> Methods { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the origins that are allowed to access the resource.
|
||||
/// </summary>
|
||||
public IList<string> Origins { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="TimeSpan"/> for which the results of a preflight request can be cached.
|
||||
/// </summary>
|
||||
public TimeSpan? PreflightMaxAge
|
||||
{
|
||||
get
|
||||
{
|
||||
return _preflightMaxAge;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value < TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", Resources.PreflightMaxAgeOutOfRange);
|
||||
}
|
||||
|
||||
_preflightMaxAge = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the resource supports user credentials in the request.
|
||||
/// </summary>
|
||||
public bool SupportsCredentials { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("AllowAnyHeader: ");
|
||||
builder.Append(AllowAnyHeader);
|
||||
builder.Append(", AllowAnyMethod: ");
|
||||
builder.Append(AllowAnyMethod);
|
||||
builder.Append(", AllowAnyOrigin: ");
|
||||
builder.Append(AllowAnyOrigin);
|
||||
builder.Append(", PreflightMaxAge: ");
|
||||
builder.Append(PreflightMaxAge.HasValue ?
|
||||
PreflightMaxAge.Value.TotalSeconds.ToString() : "null");
|
||||
builder.Append(", SupportsCredentials: ");
|
||||
builder.Append(SupportsCredentials);
|
||||
builder.Append(", Origins: {");
|
||||
builder.Append(string.Join(",", Origins));
|
||||
builder.Append("}");
|
||||
builder.Append(", Methods: {");
|
||||
builder.Append(string.Join(",", Methods));
|
||||
builder.Append("}");
|
||||
builder.Append(", Headers: {");
|
||||
builder.Append(string.Join(",", Headers));
|
||||
builder.Append("}");
|
||||
builder.Append(", ExposedHeaders: {");
|
||||
builder.Append(string.Join(",", ExposedHeaders));
|
||||
builder.Append("}");
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
// 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.Linq;
|
||||
using Microsoft.AspNet.Cors.Core;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Cors
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes methods to build a policy.
|
||||
/// </summary>
|
||||
public class CorsPolicyBuilder
|
||||
{
|
||||
private readonly CorsPolicy _policy = new CorsPolicy();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="CorsPolicyBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="origins">list of origins which can be added.</param>
|
||||
public CorsPolicyBuilder(params string[] origins)
|
||||
{
|
||||
AddOrigins(origins);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="CorsPolicyBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="policy">The policy which will be used to intialize the builder.</param>
|
||||
public CorsPolicyBuilder(CorsPolicy policy)
|
||||
{
|
||||
Combine(policy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <paramref name="origins"/> to the policy.
|
||||
/// </summary>
|
||||
/// <param name="origins">The origins that are allowed.</param>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AddOrigins(params string[] origins)
|
||||
{
|
||||
foreach (var req in origins)
|
||||
{
|
||||
_policy.Origins.Add(req);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <paramref name="headers"/> to the policy.
|
||||
/// </summary>
|
||||
/// <param name="headers">The headers which need to be allowed in the request.</param>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AddHeaders(params string[] headers)
|
||||
{
|
||||
foreach (var req in headers)
|
||||
{
|
||||
_policy.Headers.Add(req);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <paramref name="exposedHeaders"/> to the policy.
|
||||
/// </summary>
|
||||
/// <param name="exposedHeaders">The headers which need to be exposed to the client.</param>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AddExposedHeaders(params string[] exposedHeaders)
|
||||
{
|
||||
foreach (var req in exposedHeaders)
|
||||
{
|
||||
_policy.ExposedHeaders.Add(req);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <paramref name="methods"/> to the policy.
|
||||
/// </summary>
|
||||
/// <param name="methods">The methods which need to be added to the policy.</param>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AddMethods(params string[] methods)
|
||||
{
|
||||
foreach (var req in methods)
|
||||
{
|
||||
_policy.Methods.Add(req);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the policy to allow credentials.
|
||||
/// </summary>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AllowCredentials()
|
||||
{
|
||||
_policy.SupportsCredentials = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the policy to not allow credentials.
|
||||
/// </summary>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder DisallowCredentials()
|
||||
{
|
||||
_policy.SupportsCredentials = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the policy allows any origin.
|
||||
/// </summary>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AllowAnyOrigin()
|
||||
{
|
||||
_policy.Origins.Clear();
|
||||
_policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the policy allows any method.
|
||||
/// </summary>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AllowAnyMethod()
|
||||
{
|
||||
_policy.Methods.Clear();
|
||||
_policy.Methods.Add("*");
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the policy allows any header.
|
||||
/// </summary>
|
||||
/// <returns>The current policy builder</returns>
|
||||
public CorsPolicyBuilder AllowAnyHeader()
|
||||
{
|
||||
_policy.Headers.Clear();
|
||||
_policy.Headers.Add("*");
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the preflightMaxAge for the underlying policy.
|
||||
/// </summary>
|
||||
/// <param name="preflightMaxAge">A positive <see cref="TimeSpan"/> indicating the time a preflight
|
||||
/// request can be cached.</param>
|
||||
/// <returns></returns>
|
||||
public CorsPolicyBuilder SetPreflightMaxAge(TimeSpan preflightMaxAge)
|
||||
{
|
||||
_policy.PreflightMaxAge = preflightMaxAge;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a new <see cref="CorsPolicy"/> using the entries added.
|
||||
/// </summary>
|
||||
/// <returns>The constructed <see cref="CorsPolicy"/>.</returns>
|
||||
public CorsPolicy Build()
|
||||
{
|
||||
return _policy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines the given <paramref name="policy"/> to the existing properties in the builder.
|
||||
/// </summary>
|
||||
/// <param name="policy">The policy which needs to be combined.</param>
|
||||
/// <returns>The current policy builder</returns>
|
||||
private CorsPolicyBuilder Combine([NotNull] CorsPolicy policy)
|
||||
{
|
||||
AddOrigins(policy.Origins.ToArray());
|
||||
AddHeaders(policy.Headers.ToArray());
|
||||
AddExposedHeaders(policy.ExposedHeaders.ToArray());
|
||||
AddMethods(policy.Methods.ToArray());
|
||||
SetPreflightMaxAge(policy.PreflightMaxAge.Value);
|
||||
|
||||
if (policy.SupportsCredentials)
|
||||
{
|
||||
AllowCredentials();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisallowCredentials();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Results returned by <see cref="ICorsService"/>.
|
||||
/// </summary>
|
||||
public class CorsResult
|
||||
{
|
||||
private TimeSpan? _preflightMaxAge;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the allowed origin.
|
||||
/// </summary>
|
||||
public string AllowedOrigin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the resource supports user credentials.
|
||||
/// </summary>
|
||||
public bool SupportsCredentials { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed methods.
|
||||
/// </summary>
|
||||
public IList<string> AllowedMethods { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed headers.
|
||||
/// </summary>
|
||||
public IList<string> AllowedHeaders { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed headers that can be exposed on the response.
|
||||
/// </summary>
|
||||
public IList<string> AllowedExposedHeaders { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating if a 'Vary' header with the value 'Origin' is required.
|
||||
/// </summary>
|
||||
public bool VaryByOrigin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="TimeSpan"/> for which the results of a preflight request can be cached.
|
||||
/// </summary>
|
||||
public TimeSpan? PreflightMaxAge
|
||||
{
|
||||
get
|
||||
{
|
||||
return _preflightMaxAge;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value < TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", Resources.PreflightMaxAgeOutOfRange);
|
||||
}
|
||||
_preflightMaxAge = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("AllowCredentials: ");
|
||||
builder.Append(SupportsCredentials);
|
||||
builder.Append(", PreflightMaxAge: ");
|
||||
builder.Append(PreflightMaxAge.HasValue ?
|
||||
PreflightMaxAge.Value.TotalSeconds.ToString() : "null");
|
||||
builder.Append(", AllowOrigin: ");
|
||||
builder.Append(AllowedOrigin);
|
||||
builder.Append(", AllowExposedHeaders: {");
|
||||
builder.Append(string.Join(",", AllowedExposedHeaders));
|
||||
builder.Append("}");
|
||||
builder.Append(", AllowHeaders: {");
|
||||
builder.Append(string.Join(",", AllowedHeaders));
|
||||
builder.Append("}");
|
||||
builder.Append(", AllowMethods: {");
|
||||
builder.Append(string.Join(",", AllowedMethods));
|
||||
builder.Append("}");
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="ICorsService"/>.
|
||||
/// </summary>
|
||||
public class CorsService : ICorsService
|
||||
{
|
||||
private readonly CorsOptions _options;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="CorsService"/>.
|
||||
/// </summary>
|
||||
/// <param name="options">The option model representing <see cref="CorsOptions"/>.</param>
|
||||
public CorsService([NotNull] IOptions<CorsOptions> options)
|
||||
{
|
||||
_options = options.Options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a policy using the <paramref name="policyName"/> and then evaluates the policy using the passed in
|
||||
/// <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <param name="policyName"></param>
|
||||
/// <returns>A <see cref="CorsResult"/> which contains the result of policy evaluation and can be
|
||||
/// used by the caller to set apporpriate response headers.</returns>
|
||||
public CorsResult EvaluatePolicy([NotNull] HttpContext context, string policyName)
|
||||
{
|
||||
var policy = _options.GetPolicy(policyName);
|
||||
return EvaluatePolicy(context, policy);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CorsResult EvaluatePolicy([NotNull] HttpContext context, [NotNull] CorsPolicy policy)
|
||||
{
|
||||
var corsResult = new CorsResult();
|
||||
var accessControlRequestMethod = context.Request.Headers.Get(CorsConstants.AccessControlRequestMethod);
|
||||
if (string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.Ordinal) &&
|
||||
accessControlRequestMethod != null)
|
||||
{
|
||||
EvaluatePreflightRequest(context, policy, corsResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
EvaluateRequest(context, policy, corsResult);
|
||||
}
|
||||
|
||||
return corsResult;
|
||||
}
|
||||
|
||||
public virtual void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result)
|
||||
{
|
||||
var origin = context.Request.Headers.Get(CorsConstants.Origin);
|
||||
if (origin == null || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddOriginToResult(origin, policy, result);
|
||||
result.SupportsCredentials = policy.SupportsCredentials;
|
||||
AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
|
||||
}
|
||||
|
||||
public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result)
|
||||
{
|
||||
var origin = context.Request.Headers.Get(CorsConstants.Origin);
|
||||
if (origin == null || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var accessControlRequestMethod = context.Request.Headers.Get(CorsConstants.AccessControlRequestMethod);
|
||||
if (accessControlRequestMethod == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var requestHeaders =
|
||||
context.Request.Headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders);
|
||||
|
||||
if (!policy.AllowAnyMethod && !policy.Methods.Contains(accessControlRequestMethod))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!policy.AllowAnyHeader &&
|
||||
requestHeaders != null &&
|
||||
!requestHeaders.All(header => policy.Headers.Contains(header, StringComparer.Ordinal)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddOriginToResult(origin, policy, result);
|
||||
result.SupportsCredentials = policy.SupportsCredentials;
|
||||
result.PreflightMaxAge = policy.PreflightMaxAge;
|
||||
result.AllowedMethods.Add(accessControlRequestMethod);
|
||||
AddHeaderValues(result.AllowedHeaders, requestHeaders);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void ApplyResult(CorsResult result, HttpResponse response)
|
||||
{
|
||||
var headers = response.Headers;
|
||||
|
||||
if (result.AllowedOrigin != null)
|
||||
{
|
||||
headers.Add(CorsConstants.AccessControlAllowOrigin, new[] { result.AllowedOrigin });
|
||||
}
|
||||
|
||||
if (result.VaryByOrigin)
|
||||
{
|
||||
headers.Set("Vary", "Origin");
|
||||
}
|
||||
|
||||
if (result.SupportsCredentials)
|
||||
{
|
||||
headers.Add(CorsConstants.AccessControlAllowCredentials, new[] { "true" });
|
||||
}
|
||||
|
||||
if (result.AllowedMethods.Count > 0)
|
||||
{
|
||||
// Filter out simple methods
|
||||
var nonSimpleAllowMethods = result.AllowedMethods
|
||||
.Where(m =>
|
||||
!CorsConstants.SimpleMethods.Contains(m, StringComparer.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
if (nonSimpleAllowMethods.Length > 0)
|
||||
{
|
||||
headers.Add(CorsConstants.AccessControlAllowMethods, nonSimpleAllowMethods);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.AllowedHeaders.Count > 0)
|
||||
{
|
||||
// Filter out simple request headers
|
||||
var nonSimpleAllowRequestHeaders = result.AllowedHeaders
|
||||
.Where(header =>
|
||||
!CorsConstants.SimpleRequestHeaders.Contains(header, StringComparer.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
if (nonSimpleAllowRequestHeaders.Length > 0)
|
||||
{
|
||||
headers.Add(CorsConstants.AccessControlAllowHeaders, nonSimpleAllowRequestHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.AllowedExposedHeaders.Count > 0)
|
||||
{
|
||||
// Filter out simple response headers
|
||||
var nonSimpleAllowResponseHeaders = result.AllowedExposedHeaders
|
||||
.Where(header =>
|
||||
!CorsConstants.SimpleResponseHeaders.Contains(header, StringComparer.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
if (nonSimpleAllowResponseHeaders.Length > 0)
|
||||
{
|
||||
headers.Add(CorsConstants.AccessControlExposeHeaders, nonSimpleAllowResponseHeaders.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
if (result.PreflightMaxAge.HasValue)
|
||||
{
|
||||
headers.Set(
|
||||
CorsConstants.AccessControlMaxAge,
|
||||
result.PreflightMaxAge.Value.TotalSeconds.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void AddOriginToResult(string origin, CorsPolicy policy, CorsResult result)
|
||||
{
|
||||
if (policy.AllowAnyOrigin)
|
||||
{
|
||||
if (policy.SupportsCredentials)
|
||||
{
|
||||
result.AllowedOrigin = origin;
|
||||
result.VaryByOrigin = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AllowedOrigin = CorsConstants.AnyOrigin;
|
||||
}
|
||||
}
|
||||
else if (policy.Origins.Contains(origin))
|
||||
{
|
||||
result.AllowedOrigin = origin;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddHeaderValues(IList<string> target, IEnumerable<string> headerValues)
|
||||
{
|
||||
if (headerValues == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var current in headerValues)
|
||||
{
|
||||
target.Add(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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 Microsoft.AspNet.Cors;
|
||||
using Microsoft.AspNet.Cors.Core;
|
||||
using Microsoft.Framework.ConfigurationModel;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.Framework.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IServiceCollection"/> extensions for enabling CORS support.
|
||||
/// </summary>
|
||||
public static class CorsServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Can be used to configure services in the <paramref name="serviceCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection which needs to be configured.</param>
|
||||
/// <param name="configure">A delegate which is run to configure the services.</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection ConfigureCors(
|
||||
[NotNull] this IServiceCollection serviceCollection,
|
||||
[NotNull] Action<CorsOptions> configure)
|
||||
{
|
||||
return serviceCollection.Configure(configure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add services needed to support CORS to the given <paramref name="serviceCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection to which CORS services are added.</param>
|
||||
/// <returns>The updated <see cref="IServiceCollection"/>.</returns>
|
||||
public static IServiceCollection AddCors(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddOptions();
|
||||
serviceCollection.AddTransient<ICorsService, CorsService>();
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
|
||||
public class DisableCorsAttribute : Attribute, IDisableCorsMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public class EnableCorsAttribute : Attribute, IEnableCorsMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EnableCorsAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="policyName">The name of the policy to be applied.</param>
|
||||
public EnableCorsAttribute(string policyName)
|
||||
{
|
||||
PolicyName = policyName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string PolicyName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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 Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A type which can evaluate a policy for a particular <see cref="HttpContext"/>.
|
||||
/// </summary>
|
||||
public interface ICorsService
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates the given <paramref name="policy"/> using the passed in <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="HttpContext"/> associated with the call.</param>
|
||||
/// <param name="policy">The <see cref="CorsPolicy"/> which needs to be evaluated.</param>
|
||||
/// <returns>A <see cref="CorsResult"/> which contains the result of policy evaluation and can be
|
||||
/// used by the caller to set apporpriate response headers.</returns>
|
||||
CorsResult EvaluatePolicy([NotNull] HttpContext context, [NotNull] CorsPolicy policy);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds CORS-specific response headers to the given <paramref name="response"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">The <see cref="CorsResult"/> used to read the allowed values.</param>
|
||||
/// <param name="response">The <see cref="HttpResponse"/> associated with the current call.</param>
|
||||
void ApplyResult([NotNull] CorsResult result, [NotNull] HttpResponse response);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface which can be used to identify a type which provides metdata to disable cors for a resource.
|
||||
/// </summary>
|
||||
public interface IDisableCorsMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface which can be used to identify a type which provides metadata needed for enabling CORS support.
|
||||
/// </summary>
|
||||
public interface IEnableCorsMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the policy which needs to be applied.
|
||||
/// </summary>
|
||||
string PolicyName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNet.Cors.Core
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNet.Cors.Core.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The collection of headers '{0}' is not allowed.
|
||||
/// </summary>
|
||||
internal static string HeadersNotAllowed
|
||||
{
|
||||
get { return GetString("HeadersNotAllowed"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collection of headers '{0}' is not allowed.
|
||||
/// </summary>
|
||||
internal static string FormatHeadersNotAllowed(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("HeadersNotAllowed"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method '{0}' is not allowed.
|
||||
/// </summary>
|
||||
internal static string MethodNotAllowed
|
||||
{
|
||||
get { return GetString("MethodNotAllowed"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method '{0}' is not allowed.
|
||||
/// </summary>
|
||||
internal static string FormatMethodNotAllowed(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MethodNotAllowed"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The request does not contain the Origin header.
|
||||
/// </summary>
|
||||
internal static string NoOriginHeader
|
||||
{
|
||||
get { return GetString("NoOriginHeader"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The request does not contain the Origin header.
|
||||
/// </summary>
|
||||
internal static string FormatNoOriginHeader()
|
||||
{
|
||||
return GetString("NoOriginHeader");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The origin '{0}' is not allowed.
|
||||
/// </summary>
|
||||
internal static string OriginNotAllowed
|
||||
{
|
||||
get { return GetString("OriginNotAllowed"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The origin '{0}' is not allowed.
|
||||
/// </summary>
|
||||
internal static string FormatOriginNotAllowed(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("OriginNotAllowed"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PreflightMaxAge must be greater than or equal to 0.
|
||||
/// </summary>
|
||||
internal static string PreflightMaxAgeOutOfRange
|
||||
{
|
||||
get { return GetString("PreflightMaxAgeOutOfRange"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PreflightMaxAge must be greater than or equal to 0.
|
||||
/// </summary>
|
||||
internal static string FormatPreflightMaxAgeOutOfRange()
|
||||
{
|
||||
return GetString("PreflightMaxAgeOutOfRange");
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="HeadersNotAllowed" xml:space="preserve">
|
||||
<value>The collection of headers '{0}' is not allowed.</value>
|
||||
</data>
|
||||
<data name="MethodNotAllowed" xml:space="preserve">
|
||||
<value>The method '{0}' is not allowed.</value>
|
||||
</data>
|
||||
<data name="NoOriginHeader" xml:space="preserve">
|
||||
<value>The request does not contain the Origin header.</value>
|
||||
</data>
|
||||
<data name="OriginNotAllowed" xml:space="preserve">
|
||||
<value>The origin '{0}' is not allowed.</value>
|
||||
</data>
|
||||
<data name="PreflightMaxAgeOutOfRange" xml:space="preserve">
|
||||
<value>PreflightMaxAge must be greater than or equal to 0.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"dependencies": {
|
||||
},
|
||||
"version": "1.0.0-*",
|
||||
"dependencies": {
|
||||
"Microsoft.Framework.ConfigurationModel.Interfaces": "1.0.0-*",
|
||||
"Microsoft.Framework.DependencyInjection.Interfaces": "1.0.0-*",
|
||||
"Microsoft.Framework.OptionsModel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Http": "1.0.0-*",
|
||||
"Microsoft.Framework.NotNullAttribute.Internal": { "version": "1.0.0-*", "type": "build" }
|
||||
},
|
||||
|
||||
"frameworks" : {
|
||||
"dnx451" : {
|
||||
|
|
@ -14,4 +19,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core.Test
|
||||
{
|
||||
public class CorsPolicyBuilderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_WithPolicy_AddsTheGivenPolicy()
|
||||
{
|
||||
// Arrange
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add("http://existing.com");
|
||||
policy.Headers.Add("Existing");
|
||||
policy.Methods.Add("GET");
|
||||
policy.ExposedHeaders.Add("ExistingExposed");
|
||||
policy.SupportsCredentials = true;
|
||||
policy.PreflightMaxAge = TimeSpan.FromSeconds(12);
|
||||
|
||||
// Act
|
||||
var builder = new CorsPolicyBuilder(policy);
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
|
||||
Assert.False(corsPolicy.AllowAnyHeader);
|
||||
Assert.False(corsPolicy.AllowAnyMethod);
|
||||
Assert.False(corsPolicy.AllowAnyOrigin);
|
||||
Assert.True(corsPolicy.SupportsCredentials);
|
||||
Assert.Equal(policy.Headers, corsPolicy.Headers);
|
||||
Assert.Equal(policy.Methods, corsPolicy.Methods);
|
||||
Assert.Equal(policy.Origins, corsPolicy.Origins);
|
||||
Assert.Equal(policy.ExposedHeaders, corsPolicy.ExposedHeaders);
|
||||
Assert.Equal(TimeSpan.FromSeconds(12), corsPolicy.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNoOrigin()
|
||||
{
|
||||
// Arrange & Act
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.False(corsPolicy.AllowAnyHeader);
|
||||
Assert.False(corsPolicy.AllowAnyMethod);
|
||||
Assert.False(corsPolicy.AllowAnyOrigin);
|
||||
Assert.False(corsPolicy.SupportsCredentials);
|
||||
Assert.Empty(corsPolicy.ExposedHeaders);
|
||||
Assert.Empty(corsPolicy.Headers);
|
||||
Assert.Empty(corsPolicy.Methods);
|
||||
Assert.Empty(corsPolicy.Origins);
|
||||
Assert.Null(corsPolicy.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("http://example.com,http://example2.com")]
|
||||
public void Constructor_WithParamsOrigin_InitializesOrigin(string origin)
|
||||
{
|
||||
// Arrange
|
||||
var origins = origin.Split(',');
|
||||
|
||||
// Act
|
||||
var builder = new CorsPolicyBuilder(origins);
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.False(corsPolicy.AllowAnyHeader);
|
||||
Assert.False(corsPolicy.AllowAnyMethod);
|
||||
Assert.False(corsPolicy.AllowAnyOrigin);
|
||||
Assert.False(corsPolicy.SupportsCredentials);
|
||||
Assert.Empty(corsPolicy.ExposedHeaders);
|
||||
Assert.Empty(corsPolicy.Headers);
|
||||
Assert.Empty(corsPolicy.Methods);
|
||||
Assert.Equal(origins.ToList(), corsPolicy.Origins);
|
||||
Assert.Null(corsPolicy.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddOrigins_AddsOrigins()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AddOrigins("http://example.com", "http://example2.com");
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.False(corsPolicy.AllowAnyOrigin);
|
||||
Assert.Equal(new List<string>() { "http://example.com", "http://example2.com" }, corsPolicy.Origins);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowAnyOrigin_AllowsAny()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AllowAnyOrigin();
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.True(corsPolicy.AllowAnyOrigin);
|
||||
Assert.Equal(new List<string>() { "*" }, corsPolicy.Origins);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void AddMethods_AddsMethods()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AddMethods("PUT", "GET");
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.False(corsPolicy.AllowAnyOrigin);
|
||||
Assert.Equal(new List<string>() { "PUT", "GET" }, corsPolicy.Methods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowAnyMethod_AllowsAny()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AllowAnyMethod();
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.True(corsPolicy.AllowAnyMethod);
|
||||
Assert.Equal(new List<string>() { "*" }, corsPolicy.Methods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddHeaders_AddsHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AddHeaders("example1", "example2");
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.False(corsPolicy.AllowAnyHeader);
|
||||
Assert.Equal(new List<string>() { "example1", "example2" }, corsPolicy.Headers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowAnyHeaders_AllowsAny()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AllowAnyHeader();
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.True(corsPolicy.AllowAnyHeader);
|
||||
Assert.Equal(new List<string>() { "*" }, corsPolicy.Headers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddExposedHeaders_AddsExposedHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AddExposedHeaders("exposed1", "exposed2");
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.Equal(new List<string>() { "exposed1", "exposed2" }, corsPolicy.ExposedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetPreFlightMaxAge_SetsThePreFlightAge()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.SetPreflightMaxAge(TimeSpan.FromSeconds(12));
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.Equal(TimeSpan.FromSeconds(12), corsPolicy.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowCredential_SetsSupportsCredentials_ToTrue()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.AllowCredentials();
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.True(corsPolicy.SupportsCredentials);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DisallowCredential_SetsSupportsCredentials_ToFalse()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new CorsPolicyBuilder();
|
||||
|
||||
// Act
|
||||
builder.DisallowCredentials();
|
||||
|
||||
// Assert
|
||||
var corsPolicy = builder.Build();
|
||||
Assert.False(corsPolicy.SupportsCredentials);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core.Test
|
||||
{
|
||||
public class CorsPolicyTest
|
||||
{
|
||||
[Fact]
|
||||
public void Default_Constructor()
|
||||
{
|
||||
// Arrange & Act
|
||||
var corsPolicy = new CorsPolicy();
|
||||
|
||||
// Assert
|
||||
Assert.False(corsPolicy.AllowAnyHeader);
|
||||
Assert.False(corsPolicy.AllowAnyMethod);
|
||||
Assert.False(corsPolicy.AllowAnyOrigin);
|
||||
Assert.False(corsPolicy.SupportsCredentials);
|
||||
Assert.Empty(corsPolicy.ExposedHeaders);
|
||||
Assert.Empty(corsPolicy.Headers);
|
||||
Assert.Empty(corsPolicy.Methods);
|
||||
Assert.Empty(corsPolicy.Origins);
|
||||
Assert.Null(corsPolicy.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SettingNegativePreflightMaxAge_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var policy = new CorsPolicy();
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
policy.PreflightMaxAge = TimeSpan.FromSeconds(-12);
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"PreflightMaxAge must be greater than or equal to 0.\r\nParameter name: value",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_ReturnsThePropertyValues()
|
||||
{
|
||||
// Arrange
|
||||
var corsPolicy = new CorsPolicy
|
||||
{
|
||||
PreflightMaxAge = TimeSpan.FromSeconds(12),
|
||||
SupportsCredentials = true
|
||||
};
|
||||
corsPolicy.Headers.Add("foo");
|
||||
corsPolicy.Headers.Add("bar");
|
||||
corsPolicy.Origins.Add("http://example.com");
|
||||
corsPolicy.Origins.Add("http://example.org");
|
||||
corsPolicy.Methods.Add("GET");
|
||||
|
||||
// Act
|
||||
var policyString = corsPolicy.ToString();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
@"AllowAnyHeader: False, AllowAnyMethod: False, AllowAnyOrigin: False, PreflightMaxAge: 12,"+
|
||||
" SupportsCredentials: True, Origins: {http://example.com,http://example.org}, Methods: {GET},"+
|
||||
" Headers: {foo,bar}, ExposedHeaders: {}",
|
||||
policyString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core.Test
|
||||
{
|
||||
public class CorsResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void Default_Constructor()
|
||||
{
|
||||
// Arrange & Act
|
||||
var result = new CorsResult();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedHeaders);
|
||||
Assert.Empty(result.AllowedExposedHeaders);
|
||||
Assert.Empty(result.AllowedMethods);
|
||||
Assert.False(result.SupportsCredentials);
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
Assert.Null(result.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SettingNegativePreflightMaxAge_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
result.PreflightMaxAge = TimeSpan.FromSeconds(-1);
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"PreflightMaxAge must be greater than or equal to 0.\r\nParameter name: value",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_ReturnsThePropertyValues()
|
||||
{
|
||||
// Arrange
|
||||
var corsResult = new CorsResult
|
||||
{
|
||||
SupportsCredentials = true,
|
||||
PreflightMaxAge = TimeSpan.FromSeconds(30),
|
||||
AllowedOrigin = "*"
|
||||
};
|
||||
corsResult.AllowedExposedHeaders.Add("foo");
|
||||
corsResult.AllowedHeaders.Add("bar");
|
||||
corsResult.AllowedHeaders.Add("baz");
|
||||
corsResult.AllowedMethods.Add("GET");
|
||||
|
||||
// Act
|
||||
var result = corsResult.ToString();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
@"AllowCredentials: True, PreflightMaxAge: 30, AllowOrigin: *," +
|
||||
" AllowExposedHeaders: {foo}, AllowHeaders: {bar,baz}, AllowMethods: {GET}",
|
||||
result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,904 @@
|
|||
// 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 Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Cors.Core.Test
|
||||
{
|
||||
public class CorsServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void EvaluatePolicy_NoOrigin_ReturnsInvalidResult()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext("GET", origin: null);
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, new CorsPolicy());
|
||||
|
||||
// Assert
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
Assert.False(result.VaryByOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_NoMatchingOrigin_ReturnsInvalidResult()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add("bar");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
Assert.False(result.VaryByOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_EmptyOriginsPolicy_ReturnsInvalidResult()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy();
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
Assert.False(result.VaryByOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_AllowAnyOrigin_DoesNotSupportCredentials_EmitsWildcardForOrigin()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
SupportsCredentials = false
|
||||
};
|
||||
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("*", result.AllowedOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_AllowAnyOrigin_SupportsCredentials_AddsSpecificOrigin()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
SupportsCredentials = true
|
||||
};
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("http://example.com", result.AllowedOrigin);
|
||||
Assert.True(result.VaryByOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_DoesNotSupportCredentials_AllowCredentialsReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
SupportsCredentials = false
|
||||
};
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.SupportsCredentials);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_SupportsCredentials_AllowCredentialsReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
SupportsCredentials = true
|
||||
};
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.SupportsCredentials);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_NoExposedHeaders_NoAllowExposedHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedExposedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_OneExposedHeaders_HeadersAllowed()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.ExposedHeaders.Add("foo");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, result.AllowedExposedHeaders.Count);
|
||||
Assert.Contains("foo", result.AllowedExposedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_ManyExposedHeaders_HeadersAllowed()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(origin: "http://example.com");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.ExposedHeaders.Add("foo");
|
||||
policy.ExposedHeaders.Add("bar");
|
||||
policy.ExposedHeaders.Add("baz");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.AllowedExposedHeaders.Count);
|
||||
Assert.Contains("foo", result.AllowedExposedHeaders);
|
||||
Assert.Contains("bar", result.AllowedExposedHeaders);
|
||||
Assert.Contains("baz", result.AllowedExposedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_MethodNotAllowed_ReturnsInvalidResult()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("GET");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedMethods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_MethodAllowed_ReturnsAllowMethods()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("PUT");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Contains("PUT", result.AllowedMethods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_OriginAllowed_ReturnsOrigin()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Origins.Add("http://example.com");
|
||||
policy.Methods.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("http://example.com", result.AllowedOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_SupportsCredentials_AllowCredentialsReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
SupportsCredentials = true
|
||||
};
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.SupportsCredentials);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_NoPreflightMaxAge_NoPreflightMaxAgeSet()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
PreflightMaxAge = null
|
||||
};
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_PreflightMaxAge_PreflightMaxAgeSet()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy
|
||||
{
|
||||
PreflightMaxAge = TimeSpan.FromSeconds(10)
|
||||
};
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(TimeSpan.FromSeconds(10), result.PreflightMaxAge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_AnyMethod_ReturnsRequestMethod()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "GET");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, result.AllowedMethods.Count);
|
||||
Assert.Contains("GET", result.AllowedMethods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_ListedMethod_ReturnsSubsetOfListedMethods()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("PUT");
|
||||
policy.Methods.Add("DELETE");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, result.AllowedMethods.Count);
|
||||
Assert.Contains("PUT", result.AllowedMethods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_NoHeadersRequested_AllowedAllHeaders_ReturnsEmptyHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT");
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
policy.Headers.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_HeadersRequested_AllowAllHeaders_ReturnsRequestedHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(
|
||||
method: "OPTIONS",
|
||||
origin: "http://example.com",
|
||||
accessControlRequestMethod: "PUT",
|
||||
accessControlRequestHeaders: new[] { "foo", "bar" });
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
policy.Headers.Add("*");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.AllowedHeaders.Count);
|
||||
Assert.Contains("foo", result.AllowedHeaders);
|
||||
Assert.Contains("bar", result.AllowedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_HeadersRequested_AllowSomeHeaders_ReturnsSubsetOfListedHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(
|
||||
method: "OPTIONS",
|
||||
origin: "http://example.com",
|
||||
accessControlRequestMethod: "PUT",
|
||||
accessControlRequestHeaders: new[] { "Content-Type" });
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
policy.Headers.Add("foo");
|
||||
policy.Headers.Add("bar");
|
||||
policy.Headers.Add("Content-Type");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, result.AllowedHeaders.Count);
|
||||
Assert.Contains("Content-Type", result.AllowedHeaders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EvaluatePolicy_PreflightRequest_HeadersRequested_NotAllHeaderMatches_ReturnsInvalidResult()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
var requestContext = GetHttpContext(
|
||||
method: "OPTIONS",
|
||||
origin: "http://example.com",
|
||||
accessControlRequestMethod: "PUT",
|
||||
accessControlRequestHeaders: new[] { "match", "noMatch" });
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add(CorsConstants.AnyOrigin);
|
||||
policy.Methods.Add("*");
|
||||
policy.Headers.Add("match");
|
||||
policy.Headers.Add("foo");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(requestContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedHeaders);
|
||||
Assert.Empty(result.AllowedMethods);
|
||||
Assert.Empty(result.AllowedExposedHeaders);
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EaluatePolicy_DoesCaseSensitiveComparison()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
var policy = new CorsPolicy();
|
||||
policy.Methods.Add("POST");
|
||||
var httpContext = GetHttpContext(origin: null, accessControlRequestMethod: "post");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(httpContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedHeaders);
|
||||
Assert.Empty(result.AllowedMethods);
|
||||
Assert.Empty(result.AllowedExposedHeaders);
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryValidateOrigin_DoesCaseSensitiveComparison()
|
||||
{
|
||||
// Arrange
|
||||
var corsService = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
var policy = new CorsPolicy();
|
||||
policy.Origins.Add("http://Example.com");
|
||||
var httpContext = GetHttpContext(origin: "http://example.com");
|
||||
|
||||
// Act
|
||||
var result = corsService.EvaluatePolicy(httpContext, policy);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.AllowedHeaders);
|
||||
Assert.Empty(result.AllowedMethods);
|
||||
Assert.Empty(result.AllowedExposedHeaders);
|
||||
Assert.Null(result.AllowedOrigin);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_ReturnsNoHeaders_ByDefault()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(httpContext.Response.Headers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_AllowOrigin_AllowOriginHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
AllowedOrigin = "http://example.com"
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("http://example.com", httpContext.Response.Headers["Access-Control-Allow-Origin"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_NoAllowOrigin_AllowOriginHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
AllowedOrigin = null
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Allow-Origin", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_AllowCredentials_AllowCredentialsHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
SupportsCredentials = true
|
||||
};
|
||||
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
var httpContext = new DefaultHttpContext();
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("true", httpContext.Response.Headers["Access-Control-Allow-Credentials"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_AddVaryHeader_VaryHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
VaryByOrigin = true
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Origin", httpContext.Response.Headers["Vary"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_NoAllowCredentials_AllowCredentialsHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
SupportsCredentials = false
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Allow-Credentials", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_NoAllowMethods_AllowMethodsHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
// AllowMethods is empty by default
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Allow-Methods", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_OneAllowMethods_AllowMethodsHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedMethods.Add("PUT");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("PUT", httpContext.Response.Headers["Access-Control-Allow-Methods"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_SomeSimpleAllowMethods_AllowMethodsHeaderAddedForNonSimpleMethods()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedMethods.Add("PUT");
|
||||
result.AllowedMethods.Add("get");
|
||||
result.AllowedMethods.Add("DELETE");
|
||||
result.AllowedMethods.Add("POST");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Access-Control-Allow-Methods", httpContext.Response.Headers.Keys);
|
||||
var methods = httpContext.Response.Headers["Access-Control-Allow-Methods"].Split(',');
|
||||
Assert.Equal(2, methods.Length);
|
||||
Assert.Contains("PUT", methods);
|
||||
Assert.Contains("DELETE", methods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_SimpleAllowMethods_AllowMethodsHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedMethods.Add("GET");
|
||||
result.AllowedMethods.Add("HEAD");
|
||||
result.AllowedMethods.Add("POST");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Allow-Methods", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_NoAllowHeaders_AllowHeadersHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
// AllowHeaders is empty by default
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_OneAllowHeaders_AllowHeadersHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedHeaders.Add("foo");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", httpContext.Response.Headers["Access-Control-Allow-Headers"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_ManyAllowHeaders_AllowHeadersHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedHeaders.Add("foo");
|
||||
result.AllowedHeaders.Add("bar");
|
||||
result.AllowedHeaders.Add("baz");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys);
|
||||
string[] headerValues = httpContext.Response.Headers["Access-Control-Allow-Headers"].Split(',');
|
||||
Assert.Equal(3, headerValues.Length);
|
||||
Assert.Contains("foo", headerValues);
|
||||
Assert.Contains("bar", headerValues);
|
||||
Assert.Contains("baz", headerValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_SomeSimpleAllowHeaders_AllowHeadersHeaderAddedForNonSimpleHeaders()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedHeaders.Add("Content-Language");
|
||||
result.AllowedHeaders.Add("foo");
|
||||
result.AllowedHeaders.Add("bar");
|
||||
result.AllowedHeaders.Add("Accept");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys);
|
||||
string[] headerValues = httpContext.Response.Headers["Access-Control-Allow-Headers"].Split(',');
|
||||
Assert.Equal(2, headerValues.Length);
|
||||
Assert.Contains("foo", headerValues);
|
||||
Assert.Contains("bar", headerValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_SimpleAllowHeaders_AllowHeadersHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedHeaders.Add("Accept");
|
||||
result.AllowedHeaders.Add("Accept-Language");
|
||||
result.AllowedHeaders.Add("Content-Language");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_NoAllowExposedHeaders_ExposedHeadersHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
// AllowExposedHeaders is empty by default
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Expose-Headers", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_OneAllowExposedHeaders_ExposedHeadersHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedExposedHeaders.Add("foo");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", httpContext.Response.Headers["Access-Control-Expose-Headers"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_ManyAllowExposedHeaders_ExposedHeadersHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult();
|
||||
result.AllowedExposedHeaders.Add("foo");
|
||||
result.AllowedExposedHeaders.Add("bar");
|
||||
result.AllowedExposedHeaders.Add("baz");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Access-Control-Expose-Headers", httpContext.Response.Headers.Keys);
|
||||
string[] exposedHeaderValues = httpContext.Response.Headers["Access-Control-Expose-Headers"].Split(',');
|
||||
Assert.Equal(3, exposedHeaderValues.Length);
|
||||
Assert.Contains("foo", exposedHeaderValues);
|
||||
Assert.Contains("bar", exposedHeaderValues);
|
||||
Assert.Contains("baz", exposedHeaderValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_NoPreflightMaxAge_MaxAgeHeaderNotAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
PreflightMaxAge = null
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("Access-Control-Max-Age", httpContext.Response.Headers.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyResult_PreflightMaxAge_MaxAgeHeaderAdded()
|
||||
{
|
||||
// Arrange
|
||||
var result = new CorsResult
|
||||
{
|
||||
PreflightMaxAge = TimeSpan.FromSeconds(30)
|
||||
};
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var service = new CorsService(Mock.Of<IOptions<CorsOptions>>());
|
||||
|
||||
// Act
|
||||
service.ApplyResult(result, httpContext.Response);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("30", httpContext.Response.Headers["Access-Control-Max-Age"]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static HttpContext GetHttpContext(
|
||||
string method = null,
|
||||
string origin = null,
|
||||
string accessControlRequestMethod = null,
|
||||
string[] accessControlRequestHeaders = null)
|
||||
{
|
||||
var context = new DefaultHttpContext();
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
context.Request.Method = method;
|
||||
}
|
||||
|
||||
if (origin != null)
|
||||
{
|
||||
context.Request.Headers.Add(CorsConstants.Origin, new[] { origin });
|
||||
}
|
||||
|
||||
if (accessControlRequestMethod != null)
|
||||
{
|
||||
context.Request.Headers.Add(CorsConstants.AccessControlRequestMethod, new[] { accessControlRequestMethod });
|
||||
}
|
||||
|
||||
if (accessControlRequestHeaders != null)
|
||||
{
|
||||
context.Request.Headers.Add(CorsConstants.AccessControlRequestHeaders, accessControlRequestHeaders);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>b4f83a06-eb8e-4186-84c4-c6daf7eb03d4</ProjectGuid>
|
||||
<RootNamespace>Microsoft.AspNet.Cors.Core.Test</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
|
||||
"dependencies": {
|
||||
"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-*"
|
||||
},
|
||||
|
||||
"commands": {
|
||||
"test": "xunit.runner.kre"
|
||||
},
|
||||
|
||||
"frameworks" : {
|
||||
"dnx451" : {
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue