Sunday, October 3, 2010

Getting around the Firefox XMLHTTPRequest Cross Site Limitation

In one of our recent project, we had a module where we need to access a web service hosted on a third party domain into our SharePoint application. Well this appears as one of those mundane tasks of adding a reference to the web service and using the web service proxy in the C# code behind unless your client asks you to provide a postback free experience and he does not have his production SharePoint servers configured with AJAX configurations.

In this situation the only way you are left with is JavaScript hence we did the same. Now for accessing the third party web service we leveraged the XMLHttpRequest object to issue an HTTPGET request to the desired web method and accordingly use the response as returned back from the service.

Everything was working like a charm until we tested our app in Firefox. Bang here goes app!!

Below is the JavaScript script that issues an XMLHttpRequest request directly to the to the web service

Script_WebServiceCall

In Internet Explorer the above script successfully calls the HelloWorld web method and displays the result.

IE_WithoutProxy

However in Firefox you will receive an error with status code 0.

FF_WithoutProxy

Debugging this issue I found that I was always getting the xmlhttprequest.status code as 0 instead of 200. Now that was weird since the same code works fine in IE 7 & IE 8 but fails in Firefox. Moreover I couldn’t find any documentation for the 0 status code.

Googling around this issue I found some explanation here

The XMLHttpRequest object is subjected to the browser’s security “sandbox.” Any resources
requested by the XMLHttpRequest object must reside within the same domain from which the
calling script originated. This security restriction prevents the XMLHttpRequest object from
requesting resources outside the domain from which the script was originally served.
The strength of this security restriction varies by browser. Internet
Explorer shows an alert stating that a potential security risk exists but gives the user a choice
of whether to continue with the request. Firefox simply stops the request and shows an error
message ..."

Cutting the long story short it is no possible to access a web service on another domain/port via XMLHttpRequest object in Firefox.

So finally we decided to adopt an alternative of creating a server side proxy (managed code) which would take up the task of communicating with the web service. Further our JavaScript code would remain as is but one change i.e. instead of requesting the web service, the script will issue an XMLHttpRequest to server side proxy who is apparently on the same domain and this approach worked flawlessly.

Here is how the code behind for the proxy page would look like:

ProxyPage_CodeBehind

The above code is initiating the web service object (hellowrldsvc) and calling the required web method (HelloWorld). Further we are writing the result as returned by the web method back to the page response.

Here is the updated JavaScript:

Script_ProxyPageCall

Notice the url (as highlighted) is now pointing to the proxy page and the rest of the code is as is. Further upon executing the same, we get the result in IE and Firefox as shown below.

In IE:

IE_WithProxy

In Firefox:

FF_WithProxy

If your web method requires some parameter to execute, then you can pass them in page query string (as shown below) and further in the proxy page code behind read them using Page.Request.QueryString.

Script_ProxyPageCall_withQueryString

In case you are dealing with SharePoint, I would recommend you to deploy the proxy page as a Layout page and update the url accordingly.

Hope you will find this post helpful.

The associated code behind and the Visual Studio 2010 project can be downloaded from here:

3 comments:

  1. The cross-domain policy actually applies to all browsers, Internet Explorer included. You must have done something special (mark a site as trusted) to make it work.
    A workaround for modern browsers is to use CORS (cross-origin resource sharing).
    Thanks for sharing your proxy solution!

    ReplyDelete
  2. You are right Christophe, in IE it would just prompt you that this page is going to access an untrusted source but wont stop you like Firefox.

    Thanks for point out the CORS stuff!

    ReplyDelete
  3. I have learned so much from your post. I would definitely bookmark your site to be updated with your upcoming articles. Great job! So much information.

    ReplyDelete