2
votes

I'm using the Thinktecture.IdentityModel nuget package to enable CORS for WebAPI controllers in an MVC Web Application. At the moment, I'm only worried about POSTs but let me know about any problems with other verbs. This works when running through the IIS Express server.

When dealing with the AppHarbor deployment, it doesn't work. nginx doesn't seem to pass through the OPTIONS request to my code. What else is needed to get it running on AppHarbor?

Request

OPTIONS $path HTTP/1.1
Host: $servername Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://www.local
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17
Access-Control-Request-Headers: accept, origin, content-type
Accept: /
Referer: http://www.local/wordpress/2013/01/request-url-test/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Response

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 30 Jan 2013 02:34:14 GMT
Content-Length: 0
Connection: keep-alive
Allow: OPTIONS, TRACE, GET, HEAD, POST
Public: OPTIONS, TRACE, GET, HEAD, POST

My web.config is set up with the following default handlers:

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

Is WebDAV to blame?

After the suggestion of Jeffery To, I disabled WebDAV by following these instructions. Didn't even know WebDAV was installed on AH, but doing this did change my results.

Relevant Web.config sections

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules runAllManagedModulesForAllRequests="true">
  <remove name="WebDAVModule"/>
  <remove name="AspNetAppHarborIntegration" />
  <add name="AspNetAppHarborIntegration" type="Premotion.AspNet.AppHarbor.Integration.AppHarborModule, Premotion.AspNet.AppHarbor.Integration" />
</modules>

Request

OPTIONS $path HTTP/1.1
Host: $servername
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://www.local
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17
Access-Control-Request-Headers: accept, origin, content-type
Accept: /
Referer: http://www.local/wordpress/2013/01/request-url-test/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Response

HTTP/1.1 405 Method Not Allowed
Server: nginx
Date: Mon, 04 Feb 2013 17:09:19 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 76
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Expires: -1

2
Does this solution fix your issue?Jeffery To
@JefferyTo Not especially, since that solution shows adding the OPTIONS verb to the SimpleHandlerFactory-Integrated module. That verb is already configured for handlers in MVC4 projects by default (see edit).Simon Gill
What about disabling WebDAV?Jeffery To
@JefferyTo That did something - I'm looking into what else needs changing now. Any ideas of what that might be?Simon Gill

2 Answers

2
votes

WebDAV was to blame for the initial problem of not getting the full CORS headers in the response. The 405 error was a problem somewhere in the configuration of my app.

After some digging into the internals, it appears that the CORSMessageHandler for use with WebAPI (provided by Thinktecture) wasn't correctly identifying preflight requests and those requests were routed through to the WebAPI object itself.

I worked-around the issue by moving to the IIS module instead of the WebAPI one. This may make life more difficult in the future, but at least it works.

0
votes

I might be missing something here, but based on the example response you've included it seems like the OPTIONS method is actually sent to your application - the Allow and Public headers are included in the response.