2

I'm building a simple ServiceStack app and intending to host it on AzureWebSites. That's working fine. I need CORS to make the app work. In IIS Express and IIS 7.5 locally, this works fine - but not on Azure or AppHarbor.

The actual AJAX GET and POST requests work fine, the problem is the pre-flight OPTIONS checks return an empty response; no headers, nothing.

The code is on GitHub. You can see in the git commit history some things I've tried.

I've enabled Failed Request Logging- but that doesn't help. I'm not getting a 400+ series error code - I'm getting no response at all.

EDIT: Thanks to @paaschpa I've started looking at the problem from different machines. Added one more response from a Linux machine. It shows that cURL is getting back something odd (see below) causing it to output debugging as per this SO question: Why is cURL returning "additional stuff not fine"?

When I test Azure from my Rackspace Linux machine, I get this:

kyleh@media:~$ curl -X curl -X OPTIONS -H "Origin: http://www.example.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: X-Requested-With" --verbose http://sstodo.azurewebsites.net/items
* About to connect() to sstodo.azurewebsites.net port 80 (#0)
*   Trying 23.101.118.145...
* connected
* Connected to sstodo.azurewebsites.net (23.101.118.145) port 80 (#0)
> OPTIONS /items HTTP/1.1
> User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.26.0 OpenSSL/1.0.1e zlib/1.2.3.4 libidn/1.25 libssh2/1.4.2 librtmp/2.3
> Host: sstodo.azurewebsites.net
> Accept: */*
> Origin: http://www.example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
> 
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Length: 0
< Vary: Accept
< Server: Microsoft-IIS/8.0
< X-Powered-By: ServiceStack/4.036 Win32NT/.NET
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
< Access-Control-Allow-Headers: Content-Type
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Set-Cookie: ARRAffinity=f1d67e2939c9eab291aa7a92c2c5cffe872dc89340409c771374fbf6bc961bd3;Path=/;Domain=sstodo.azurewebsites.net
< Date: Sun, 01 Feb 2015 02:57:55 GMT
< 
* Connection #0 to host sstodo.azurewebsites.net left intact
* Closing connection #0

When I test the site locally, the result looks right. Here's the local result (VS / IIS Express):

curl -X OPTIONS 
 -H "Origin: http://www.example.com" 
 -H "Access-Control-Request-Method: POST" 
 -H "Access-Control-Request-Headers: X-Requested-With"
 --verbose http://localhost:1061/items
* timeout on name lookup is not supported
* About to connect() to localhost port 1061 (#0)
*   Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 1061 (#0)
> OPTIONS /items HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost:1061
> Accept: */*
> Origin: http://www.example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 200 OK
< Cache-Control: private
< Vary: Accept
< Server: Microsoft-IIS/8.0
< X-Powered-By: ServiceStack/4.036 Win32NT/.NET
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
< Access-Control-Allow-Headers: Content-Type
< X-AspNet-Version: 4.0.30319
< X-SourceFiles: =?UTF-8?B?QzpccHJvamVjdHNcc2VydmljZXN0YWNrLXRvZG8tYmFja2VuZFxUb0RvQmFja2VuZFxUb0RvQmFja2VuZFxpdGVtcw==?=
< X-Powered-By: ASP.NET
< Date: Thu, 22 Jan 2015 23:51:29 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
* Closing connection #0

Here's the result in IIS7.5 locally:

curl -H "Origin: http://www.example.com" -H "Access-Control-Request-Method: P
OST" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS --verbose
 http://localhost/sstodo/items
* timeout on name lookup is not supported
* About to connect() to localhost port 80 (#0)
*   Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 80 (#0)
> OPTIONS /sstodo/items HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost
> Accept: */*
> Origin: http://www.example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 200 OK
< Cache-Control: private
< Vary: Accept
< Server: Microsoft-IIS/7.5
< X-Powered-By: ServiceStack/4.036 Win32NT/.NET
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
< Access-Control-Allow-Headers: Content-Type
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Sat, 24 Jan 2015 02:44:55 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
* Closing connection #0

When I run the test against AzureWebSites (and AppHarbor) it does not.

curl -X OPTIONS 
 -H "Origin: http://www.example.com" 
 -H "Access-Control-Request-Method: POST" 
 -H "Access-Control-Request-Headers: X-Requested-With" 
 --verbose http://sstodo.azurewebsites.net/items
* timeout on name lookup is not supported
* About to connect() to sstodo.azurewebsites.net port 80 (#0)
*   Trying 23.101.118.145...
* connected
* Connected to sstodo.azurewebsites.net (23.101.118.145) port 80 (#0)
> OPTIONS /items HTTP/1.1
> User-Agent: curl/7.26.0
> Host: sstodo.azurewebsites.net
> Accept: */*
> Origin: http://www.example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
>
* Empty reply from server
* Connection #0 to host sstodo.azurewebsites.net left intact
curl: (52) Empty reply from server
* Closing connection #0

Here's AppHarbor:

curl -X OPTIONS 
 -H "Origin: http://www.example.com" 
 -H "Access-Control-Request-Method: POST" 
 -H "Access-Control-Request-Headers: X-Requested-With" 
 --verbose http://sstodo.apphb.com/items
* timeout on name lookup is not supported
* About to connect() to sstodo.apphb.com port 80 (#0)
*   Trying 50.17.211.206...
* connected
* Connected to sstodo.apphb.com (50.17.211.206) port 80 (#0)
> OPTIONS /items HTTP/1.1
> User-Agent: curl/7.26.0
> Host: sstodo.apphb.com
> Accept: */*
> Origin: http://www.example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
>
* Empty reply from server
* Connection #0 to host sstodo.apphb.com left intact
curl: (52) Empty reply from server
* Closing connection #0

I'm at a bit of a loss for direction. In my mental model, I should be able to repro the issue on my local environment. All the documentation I see for Azure and AppHarbor both indicate that they're not blocking the OPTIONS calls, but that doesn't appear to be the case.

I don't care so much about how the site works in cURL of course.

Community
  • 1
  • 1
Kyle
  • 953
  • 3
  • 16
  • 32
  • Have you tried this - http://stackoverflow.com/questions/18981339/http-options-request-on-azure-websites-fails-due-to-cors ? Why don't you use Azure MobileService , as this is service stack you are developing, I mean for that you are hosting as website? – Arindam Nayak Jan 26 '15 at 09:08
  • I've tried that answer. It's really for PHP sites with a 405 error, not m condition. However, it links to a note about trace logging, which could be helpful. I'll explore that. – Kyle Jan 26 '15 at 14:24
  • OPTIONS preflight request always results in 405 error, thought it will be helpful, or atleast try to add `system.webServer-httpProtocol-customHeaders"Access-Control-Allow-Origin"` and other headers mentioned in recent answer for the question ( the link which i had given earlier). – Arindam Nayak Jan 26 '15 at 14:57
  • ServiceStack adds those headers for me, and I've also tried adding them as suggested in the answer. – Kyle Jan 26 '15 at 16:14
  • If you are ready to move to Azure Mobile Service, definitely I can help you on that. Last option - try adding `allowedHeaders` in `AppHost.cs` with value = `X-Requested-With`. – Arindam Nayak Jan 26 '15 at 16:47
  • Thanks Arindam Nayak. Why do I need to move? ServiceStack can build websites and services both, so I'm not sure the mobile services would be best for me. – Kyle Jan 27 '15 at 03:30
  • Yes, I agree you can implement both using website. But Azure provides PaaS solution for this service implementation, i.e. just create DB, config few thing, you are ready to expose CRUD operation as service, you can read more, that decision is upto you. In the mean time, if i find any helpful thing for question, I will post them as answer. – Arindam Nayak Jan 27 '15 at 05:09

3 Answers3

3

I'm betting you ran into the same issue I did; the "Web Security" module in the Cisco VPN client running on your OS X laptop was intercepting your HTTP requests and silently dropping OPTIONS requests made as part of the CORS preflight. What a great "feature" for this VPN software. It even does this when you're not using the VPN.

Switching to https fixes this because the proxy is not able to read your requests and so not able to drop OPTIONS.

More info about this problem here: http://www.bennadel.com/blog/2559-cisco-anyconnect-vpn-client-may-block-cors-ajax-options-requests.htm

You can uninstall the web security module with: sudo /opt/cisco/anyconnect/bin/websecurity_uninstall.sh

Pete Hodgson
  • 14,566
  • 4
  • 36
  • 46
1

Well...not sure this helps but I have a 'works from my machine' for you. Screenshot below...

enter image description here

If you fixed your own issue, I'd be curious to see the fix.

paaschpa
  • 4,786
  • 9
  • 15
  • Hmm.. Won't I feel silly if it was something local. Thought I checked proxy settings already but it's worth another look. Thanks! – Kyle Jan 29 '15 at 17:39
  • Maybe update curl? It looks like I'm running 7.40.0 and you're running 7.26.0. All other inputs looks pretty much the same. Also, this simpler request -> `curl -X OPTIONS --verbose http://sstodo.azurewebsites.net/items` – paaschpa Jan 29 '15 at 19:05
  • I'm noticing mine connects to 127.0.0.1. I don't have that in hosts file anywhere, but I wonder if I have something in the environment telling cURL to use a (no longer present) http proxy – Kyle Jan 29 '15 at 19:42
  • **I'm noticing mine connects to 127.0.0.1** - This only happens when you make a Request to http://localhost:1061/items, right? When you make a Request to http://sstodo.azurewebsites.net/items there shouldn't be any reason (that I'm aware of) that your Request goes through 127.0.0.1 – paaschpa Jan 29 '15 at 21:00
  • Agreed. I upgraded to the same version though and I'm getting same behaviour – Kyle Jan 29 '15 at 22:08
  • This is still a very "on again, off again" thing. Very flakey, some times it works from some systems not from others. – Kyle Feb 19 '15 at 20:51
  • as a note, found another so question talking about how HTTPS helps with pre-flight... this seems to be resolving issues... – Kyle Feb 19 '15 at 20:56
1

In the end, what worked was switching to HTTPS.

I can't say that I understand why, but using HTTPS always resolves the issue.

Kyle
  • 953
  • 3
  • 16
  • 32