teemarks
teemarks

Reputation: 23

CORS Custom Headers

I am running a small web app using AngularJS, running on an IIS8.5 server, and using DreamFactory for the API. I am running into an issue with CORS when trying to make $http requests in a service.

The errors keep suggesting that the Access-Control-Allow-Headers values are empty in the web.config file; however, that is not the case.

I receive this error when trying to send an API request: "Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response." I also get the X-DreamFactory-API-Key listed in the error when that is uncommented in the header request.

My $http call looks like this:

$http({
                    method: 'POST',
                    headers: {
                        'X-DreamFactory-API-Key':'apiKey'
                    },...

My web.config file has:

<httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="Content-Type, Accept, Origin, X-Requested-With, X-DreamFactory-API-Key" /> <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" /> <add name="Access-Control-Allow-Credentials" value="true" /> </customHeaders> </httpProtocol>

This is the configuration at the root level, which has been pushed down to the site level.

I have also setup CORS in the Dreamfactory admin console.

Does anyone have ANY clue as to what is happening and how to fix this? Thanks.

Upvotes: 1

Views: 1515

Answers (1)

jValdron
jValdron

Reputation: 3418

As you've realized, pre-flight CORS in ASP.NET doesn't work too well. I haven't used DreamFactory and I'm on IIS 7.5, however, the same most likely apply.

I solved this using a custom HttpModule.

public class CorsModule : IHttpModule
{
    public void Dispose() {
        // There's nothing to dispose here, but the dispose implementation is required.
    }

    public void Init(HttpApplication context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        // Without this .NET sends a weird status code, can't remember what exactly.
        context.PreSendRequestHeaders += delegate
        {
            if (context.Request.HttpMethod == "OPTIONS")
            {
                var response = context.Response;
                response.StatusCode = (int)HttpStatusCode.OK;
            }
        };

        // Bind to the Application_BeginRequest event. This is the important part right here.
        context.BeginRequest += this.Application_BeginRequest;
    }

    private void Application_BeginRequest(Object source, EventArgs e)
    {   
        // Personally I only needed to send those headers in the OPTIONS method. 
        // You might need to change this for your needs.
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Authorization, Origin, Content-Type, Accept, X-Requested-With, SOAPAction");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }

The only thing that I needed in my web.config is the Access-Control-Allow-Origin, Access-Control-Allow-Credentials and a reference to my HttpModule:

<modules>
    <add name="CorsModule" type="MyNamespace.CorsModule, MyAssembly" />
</modules>

Upvotes: 1

Related Questions