__Scenario__:
User is using attribute routing and CORs together. He has a global CORS configuration and also a CORS configuration on a particular action.
__Issue__:
The CORS policy decorated on the action isn't being honored and always the global configuration is being considered. This issue does _not_ repro when using conventional routing.
__Reason__:
The root cause of this issue is due to a recent change in AttributeBasedPolicyProviderFactory.cs…specifically this(check highlighted comments) should be “targetRequest"
```
public virtual ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
HttpActionDescriptor actionDescriptor = null;
if (corsRequestContext.IsPreflight)
{
HttpRequestMessage targetRequest = new HttpRequestMessage(new HttpMethod(corsRequestContext.AccessControlRequestMethod), request.RequestUri);
try
{
foreach (var property in request.Properties)
{
// The RouteData and HttpContext from the preflight request properties contain information
// relevant to the preflight request and not the actual request, therefore we need to exclude them.
if (property.Key != HttpPropertyKeys.HttpRouteDataKey &&
property.Key != HttpContextBaseKey)
{
targetRequest.Properties.Add(property.Key, property.Value);
}
}
HttpConfiguration config = request.GetConfiguration(); //*********************HERE*********************************
if (config == null)
{
throw new InvalidOperationException(SRResources.NoConfiguration);
}
IHttpRouteData routeData = config.Routes.GetRouteData(request);//*********************HERE*********************************
if (routeData == null)
{
// No route data found for selecting action with EnableCorsAttribute, thus no ICorsPolicyProvider is returned
// and let the CorsMessageHandler flow the request to the normal Web API pipeline.
return null;
}
actionDescriptor = SelectAction(targetRequest, routeData, config);
}
```
__Setup__:
```
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
config.MapHttpAttributeRoutes();
appBuilder.UseWebApi(config);
}
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[AcceptVerbs("GET", "OPTIONS", RouteTemplate = "")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[AcceptVerbs("GET", "OPTIONS", RouteTemplate = "{id}")]
public string GetSingle(int id)
{
return "value";
}
[EnableCors("http://abc.com", "*", "*")]
[AcceptVerbs("POST", "OPTIONS", RouteTemplate = "")]
public string Post([FromBody]string value)
{
return value;
}
```
For the above setup, I am seeing that this request is passing through even though I have specifically mentioned to allow a particular origin(http://abc.com) on the action
```
Request:
Method: OPTIONS, RequestUri: 'http://kcthinkpad:9095/api/values', Version: 1.1, Content: <null>, Headers:
{
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
}
Response:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Access-Control-Allow-Origin: * //*********HERE*********
Access-Control-Allow-Headers: X-PINGOTHER //*********HERE*********
Date: Fri, 09 Aug 2013 14:54:55 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 0
}
----------------------------------
Request:
Method: OPTIONS, RequestUri: 'http://kcthinkpad:9095/api/values', Version: 1.1, Content: <null>, Headers:
{
Origin: http://foo.example
Access-Control-Request-Method: GET
Access-Control-Request-Headers: X-PINGOTHER
}
Response:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-PINGOTHER
Date: Fri, 09 Aug 2013 14:54:55 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 0
}
```
Comments: Please note: This issue was triggered by a path caused by HttpMethodConstraints which attribute routing was adding before Mike's today's check-in(https://aspnetwebstack.codeplex.com/SourceControl/changeset/6eb7f13ca6158800a18dcb299dca481277513cbd)...After this check-in this issue does not repro any more. However, please take a look at the codepath that I had highlighted in the bug above as it seems incorrect and wondering if some another mechanism can trigger this path, then we would be having a problem. Based on this, I would low-pri this one. Thanks.
User is using attribute routing and CORs together. He has a global CORS configuration and also a CORS configuration on a particular action.
__Issue__:
The CORS policy decorated on the action isn't being honored and always the global configuration is being considered. This issue does _not_ repro when using conventional routing.
__Reason__:
The root cause of this issue is due to a recent change in AttributeBasedPolicyProviderFactory.cs…specifically this(check highlighted comments) should be “targetRequest"
```
public virtual ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
HttpActionDescriptor actionDescriptor = null;
if (corsRequestContext.IsPreflight)
{
HttpRequestMessage targetRequest = new HttpRequestMessage(new HttpMethod(corsRequestContext.AccessControlRequestMethod), request.RequestUri);
try
{
foreach (var property in request.Properties)
{
// The RouteData and HttpContext from the preflight request properties contain information
// relevant to the preflight request and not the actual request, therefore we need to exclude them.
if (property.Key != HttpPropertyKeys.HttpRouteDataKey &&
property.Key != HttpContextBaseKey)
{
targetRequest.Properties.Add(property.Key, property.Value);
}
}
HttpConfiguration config = request.GetConfiguration(); //*********************HERE*********************************
if (config == null)
{
throw new InvalidOperationException(SRResources.NoConfiguration);
}
IHttpRouteData routeData = config.Routes.GetRouteData(request);//*********************HERE*********************************
if (routeData == null)
{
// No route data found for selecting action with EnableCorsAttribute, thus no ICorsPolicyProvider is returned
// and let the CorsMessageHandler flow the request to the normal Web API pipeline.
return null;
}
actionDescriptor = SelectAction(targetRequest, routeData, config);
}
```
__Setup__:
```
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
config.MapHttpAttributeRoutes();
appBuilder.UseWebApi(config);
}
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[AcceptVerbs("GET", "OPTIONS", RouteTemplate = "")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}
[AcceptVerbs("GET", "OPTIONS", RouteTemplate = "{id}")]
public string GetSingle(int id)
{
return "value";
}
[EnableCors("http://abc.com", "*", "*")]
[AcceptVerbs("POST", "OPTIONS", RouteTemplate = "")]
public string Post([FromBody]string value)
{
return value;
}
```
For the above setup, I am seeing that this request is passing through even though I have specifically mentioned to allow a particular origin(http://abc.com) on the action
```
Request:
Method: OPTIONS, RequestUri: 'http://kcthinkpad:9095/api/values', Version: 1.1, Content: <null>, Headers:
{
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
}
Response:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Access-Control-Allow-Origin: * //*********HERE*********
Access-Control-Allow-Headers: X-PINGOTHER //*********HERE*********
Date: Fri, 09 Aug 2013 14:54:55 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 0
}
----------------------------------
Request:
Method: OPTIONS, RequestUri: 'http://kcthinkpad:9095/api/values', Version: 1.1, Content: <null>, Headers:
{
Origin: http://foo.example
Access-Control-Request-Method: GET
Access-Control-Request-Headers: X-PINGOTHER
}
Response:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-PINGOTHER
Date: Fri, 09 Aug 2013 14:54:55 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 0
}
```
Comments: Please note: This issue was triggered by a path caused by HttpMethodConstraints which attribute routing was adding before Mike's today's check-in(https://aspnetwebstack.codeplex.com/SourceControl/changeset/6eb7f13ca6158800a18dcb299dca481277513cbd)...After this check-in this issue does not repro any more. However, please take a look at the codepath that I had highlighted in the bug above as it seems incorrect and wondering if some another mechanism can trigger this path, then we would be having a problem. Based on this, I would low-pri this one. Thanks.