Morvael Morvael - 3 months ago 19
HTTP Question

CORS request preflight request, ending in user code

I have a set of WCF web services running on an internal only interface, which are called by a number of other websites (also internal only). The domain names match, it's just a different port number.

I'm making AJAX POST requests to these web services and as they are technically not the same origin (different port) I'm using CORS.

All is fine in IE, (as I believe that IE doesn't treat ports as different origins) however both Opera and Firefox send a preflight OPTIONS request.

I have configured the web services to accept these requests through the web.config file:

<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="*" />


I have also set the interface on my services to accept any HTTP verb:

[OperationContract(Name = "H2dbDataExport")]
[WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
string H2dbDataExport(string action, string username, exportDetails data);


However this results in the underlying service being called, and as it doesn't find any of the details it would expect in the POST request replies with the standard "You sent something wrong" response.

If I change the service to only accept POST request - which is really the only response it will respond to with anything same via:

[WebInvoke(Method = "POST", etc.......


Then the preflight OPTIONS gets a "405 - Method not allowed" response.

What am I doing wrong? Am I supposed to be configuring my services to reply to the OPTIONS request, and if so what would the correct response be?

I'm assuming that I could just pick up the request type in the service and reply with 200 - OK, if the verb was OPTIONS then resend the actual POST - but if I manually did this surely the browser will just send the OPTIONS again as its a new request.

EDIT:

I just found this post, concernign removing the WEbDAV handler:
CORS 405 (Method Not Allowed)

But it didn't help.

There was also a post concerning moving the OPTIONSHttpVerb handler to the top of the list and giving it "Read" permissions, but this also didn't help.

EDIT 2:
Actually moving the OPTIONSHttpVerb did help, it no longer calls the web service, but IIS does respond with a 200 - OK. However this response still end up in the client code in the browser, so of no help.

OPTIONS response

HTTP/1.1 200 OK
Allow: OPTIONS, TRACE, GET, HEAD, POST
Server: Microsoft-IIS/7.5
Public: OPTIONS, TRACE, GET, HEAD, POST
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Date: Fri, 05 Jun 2015 10:34:29 GMT
Content-Length: 0

Answer

Looks like it was all my own fault. I was using a wild-card for:

<add name="Access-Control-Allow-Headers" value="*" />

Which apparently isn't permitted. If the request specifies the Access-Control-Request-Headers then the server must reply with the same list.

http://stackoverflow.com/a/13147554/1286358

http://www.html5rocks.com/en/tutorials/cors/

So I simply checked out what headers were sent with the OPTIONS request and set those to be accepted.

There was this line in the preflight request:

Access-Control-Request-Headers: accept, content-type

So I changed the web.config to match:

<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="accept, content-type" />

And it now works.

This also allowed me to change the service back to (correctly) only accepting POST requests.

[WebInvoke(Method = "POST", etc.......

Hope that helps some-one else.

Comments