4

I'm getting the error:

XMLHttpRequest cannot load http://www.scirra.com/handlers/arcadeProcessScore.ashx. Origin http://static1.scirra.net is not allowed by Access-Control-Allow-Origin.

On arcadeProcessScore.ashx I have the lines:

public void ProcessRequest (HttpContext context) {

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://static1.scirra.net");
    context.Response.AppendHeader("Access-Control-Allow-Origin", "https://static1.scirra.net");
    context.Response.ContentType = "text/plain";

Yet the error still persists.

I've also tried simply:

context.Response.AppendHeader("Access-Control-Allow-Origin", "*");

Which doesn't work either.

If I add <add name="Access-Control-Allow-Origin" value="*"/> at the web.config level it works, but obviously isn't the solution.

How can I let arcadeProcessScore.ashx accept requests from static1.scirra.net? Thanks for any help.

Tom Gullen
  • 61,249
  • 84
  • 283
  • 456

3 Answers3

5

I did some testing of my own, directly using an XmlHttpRequest to access a handler in my project. The setup I used was to publish the application on my local IIS (which is version 6.1, so there might be differences in behaviour to 7.5) and to have the Default.aspx page call my handler running in the development server in Visual Studio. Like this:

http://mymachine/WebTest/Default.aspx

-> XmlHttpRequest get request to

http://localhost:58025/WebTest/TestHandler.ashx

Code in the handler:

public void ProcessRequest (HttpContext context) {
    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "text/plain";
    context.Response.Write("Hello World " + DateTime.Now.ToString());
}

Using IE9, the behviour was the same regardless of whether or not I sent an Access-Control-Allow-Origin header back from the handler. IE9 gives warning, asking the user to confirm if the content should be loaded.

Both Chrome (version 21.0.1180.79 m) and FF (version 14.0.1) actually generates requests to the handler and respects the header that the handler sends back.

So this worked with Chrome and FF:

context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");

So did this:

context.Response.AppendHeader("Access-Control-Allow-Origin", "*");

But I have not been able to get either of them to show the content if I try to add several different allowed origins in the same response. For me, none of these worked:

  1. Add several response headers

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");
    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://someothermachine");
    
  2. Add one header, two origins comma separated

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine, http://someothermachine");
    
  3. Add one header, two origins space separated

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine http://someothermachine");
    
  4. Add one header, two origins space separated

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine; http://someothermachine");
    

To get it to work, what I did was to follow the advice given in this answer. My handler then looks like this:

public void ProcessRequest(HttpContext context)
{
    string[] allowedOrigins = new string[] { "http://mymachine", "http://someothermachine" };
    string origin = context.Request.Headers.Get("Origin");
    if (allowedOrigins.Contains(origin))
        context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "text/plain";
    context.Response.Write("Hello World " + DateTime.Now.ToString());
}

With this, both Chrome and FF accept the output from the handler from both origins.

Community
  • 1
  • 1
user1429080
  • 9,086
  • 4
  • 31
  • 54
  • 1
    This was part of my solution to my problem. Chrome was throwing the origin issue even though I was using code very similar to what is listed here. My issue was occurring because I had **both** code setting the Access-Control-Allow-Origin header **and** the line in my web config. Once I removed the line from my web config I was up and running. – Garry Dec 19 '12 at 00:53
3

The problem here with your code is that the Cross Origin response header is sent to the browser with the actual request, while it must be there before the actual request is made!

W3 recommends the user agent to implement a preflight request before submitting the actually Cross-Origin HTTP request, this means that either the response to the page containing the actual request, or the response to a simple request known as preflight request (which is made before the actual request) must contain Cross Origin response header when the actual request is made.

Cross Origin headers returned from the preflight request are stored in the preflight result cache. When a Cross-Origin HTTP request is made, the user agent checks for the Access-Control-Allow-Origin header in the preflight result cache, and if it is not there throws an exception stating:

can not load address, Origin address is not allowed by Access-Control-Allow-Origin.

When you put the Access-Control-Allow-Origin header in the web.config, any response returned from the server contains the Access-Control-Allow-Origin header, and the browser will submit the actual Cross-Domain request.

Your best bet is to make a simple ajax call (preflight request), before you call the actual cross domain request, and send whatever response headers needed with that preflight request.

Kamyar Nazeri
  • 25,786
  • 15
  • 50
  • 87
1

Could you wrap your web.config item in a location tag so that it only runs for your ashx location and no where else - would that mitigate the "objviously not the answer" issue?

<location path="~/path/to/handler/arcadeProcessScore.ashx">
<httpProtocol>
   <customHeaders>
      <clear />
      <add name="Access-Control-Allow-Origin" value="http://static1.scirra.net" />
   </customHeaders>
</httpProtocol>
</location>
Luke Baughan
  • 4,658
  • 3
  • 31
  • 54