Cross Domain XHR with Firefox 2

By now know you know that trying to do an XMLHttpRequest (XHR or AJAX) call to a domain that is different from the domain of the hosted JavaScript in Firefox will throw an exception.

Error: uncaught exception: Permission denied to call method XMLHttpRequest.open

If you don’t want a history of the past solutions, page down to see the final solution.

The web has solutions to this problem, but most of them involve changing your JavaScript code, which I thought to be less than ideal. A common solution involves setting the UniversalBrowserRead security property in your JavaScript code [Dion Almaer, of Ajaxian fame]:

netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');

The problem with that solution (obviously) lies in single browser proprietary JavaScript polluting your code. And you have to set this property inside the scope of any usage (ie: inside your library file that does your AJAX calls and inside your callbacks, etc).

Why can’t it just be as easy as Internet Explorer? They just pop-up a little security dialog asking you if you want to allow this access (which is also what the enablePrivilege function does as well).

Another solution involves setting the capability.policy.default.XMLHttpRequest.open preference inside your prefs.js Firefox preference file [Mike Dirolf]. This worked as desired and allowed the AJAX call, but anytime you attempt to access the resulting XML you received a nice exception as well. It turns out this is the solution we wanted, it’s just incomplete.

The Final Solution

  1. Close Firefox. It will overwrite your changes to the prefs.js file if you have it open.
  2. Optional step: This approach will open up your Firefox security quite a bit, so I’d recommend setting up a separate profile in Firefox to use when testing. It will not pop up a security dialog when a cross-domain AJAX call is made.
  3. Find your prefs.js file. In Windows, it is typically located in the C:\Documents and Settings\{YOUR_USERNAME}\ApplicationData\Mozilla\Firefox\Profiles\{YOUR_TEST_USER_PROFILE_ID}\prefs.js
  4. Open it up and add the following lines:
    user_pref("capability.policy.default.XMLHttpRequest.open", "allAccess");
    user_pref("capability.policy.default.CDATASection.nodeValue", "allAccess");
    user_pref("capability.policy.default.Element.attributes", "allAccess");
    user_pref("capability.policy.default.Element.childNodes", "allAccess");
    user_pref("capability.policy.default.Element.firstChild", "allAccess");
    user_pref("capability.policy.default.Element.getElementsByTagName", "allAccess");
    user_pref("capability.policy.default.Element.tagName", "allAccess");
    user_pref("capability.policy.default.HTMLCollection.length", "allAccess");
    user_pref("capability.policy.default.HTMLCollection.item", "allAccess");
    user_pref("capability.policy.default.Text.nodeValue", "allAccess");
    user_pref("capability.policy.default.XMLDocument.documentElement", "allAccess");
    user_pref("capability.policy.default.XMLDocument.getElementsByTagName", "allAccess");
    user_pref("capability.policy.default.XMLHttpRequest.channel", "allAccess");
    user_pref("capability.policy.default.XMLHttpRequest.open", "allAccess");
    user_pref("capability.policy.default.XMLHttpRequest.responseText", "allAccess");
    user_pref("capability.policy.default.XMLHttpRequest.responseXML", "allAccess");
    user_pref("capability.policy.default.XMLHttpRequest.send", "allAccess");
    user_pref("capability.policy.default.XMLHttpRequest.setRequestHeader", "allAccess");

This code was copied (with the exception of 1 line) from a source repository at [kryogenix.org]
used in jackfield. It wasn’t intended to be used for this purpose, but it works.

If you still get Error: uncaught exception: Permission denied to call method _________ errors, you can add the method to your prefs.js. I would appreciate a comment with any commonly used methods not included above. Thanks.

Update: Because this article is deprecated (applies to an older version of Firefox), I’m updating the blog title in the interest of minimizing the number of disappointed users. Some might think this is a stupid thing to do, since it’s the most popular page on my blog, but I’m more interested in helping people than getting traffic.

VN:F [1.8.1_1037]
Rating: 4.1/5 (7 votes cast)
Cross Domain XHR with Firefox 24.157
This entry was posted in JavaScript, Web Browsers and tagged , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Thanks for reading. If you found this article useful, and you've read through some of my previous articles, you might as well Subscribe to my content subscribe to my blog. You'll save me some bandwidth that way.

18 Comments

  1. alberto
    Posted October 30, 2007 at 4:03 am | Permalink

    this method works as well but when I need to read the response xml i get this exception:

    uncaught exception: Permission denied to get property XMLDocument.firstChild

    any solution??
    i don’t want to use ie6/7 again for this purpose…

  2. Zach Leatherman
    Posted October 30, 2007 at 4:56 pm | Permalink

    If you read the solution carefully you will see that you can add that exact property to your prefs.js like so:

    user_pref(“capability.policy.default.XMLDocument.firstChild”, “allAccess”);

    Anytime you get a “Permission denied” exception, this solution should work

  3. Shaun
    Posted January 26, 2008 at 7:16 am | Permalink

    Rather than set these preferences on the default profile, set them on a custom one that’s only available for your development site:

    user_pref("capability.policy.XMLHttpRequestToAnySite.sites", "http://YOURDEVHOSTHERE");
    user_pref("capability.policy.policynames", "XMLHttpRequestToAnySite");

    Here’s the final list I ended up using, which includes a few new ones than the OP:


    user_pref("capability.policy.XMLHttpRequestToAnySite.CDATASection.nodeValue", "allAccess");

    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.attributes", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.childNodes", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.firstChild", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.getAttribute", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.getElementsByTagName", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.nodeType", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.nodeName", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Element.tagName", "allAccess");

    user_pref("capability.policy.XMLHttpRequestToAnySite.HTMLCollection.length", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.HTMLCollection.item", "allAccess");

    user_pref("capability.policy.XMLHttpRequestToAnySite.ProcessingInstruction.nodeType", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.ProcessingInstruction.nodeName", "allAccess");

    user_pref("capability.policy.XMLHttpRequestToAnySite.Text.nodeType", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Text.nodeName", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Text.data", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.Text.nodeValue", "allAccess");

    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLDocument.documentElement", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLDocument.getElementsByTagName", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLDocument.nodeType", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLDocument.nodeName", "allAccess");

    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLHttpRequest.channel", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLHttpRequest.responseText", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLHttpRequest.responseXML", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLHttpRequest.send", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLHttpRequest.setRequestHeader", "allAccess");
    user_pref("capability.policy.XMLHttpRequestToAnySite.XMLHttpRequest.open", "allAccess");

  4. Zach Leatherman
    Posted February 6, 2008 at 6:27 pm | Permalink

    Great comment Shaun! That will definitely tighten the security up.

  5. Posted February 10, 2008 at 4:30 pm | Permalink

    Shaun or Zach, how would I do the same for UniversalXPConnect? I’m trying to make myself a Firefox favelet that would search this French dictionnary automatically with my clipboard text:
    http://atilf.atilf.fr/dendien/scripts/tlfiv4/showps.exe?p=combi.htm

    I’m so close but I’m still getting this error:
    uncaught exception: Un script de « http://atilf.atilf.fr » s'est vu refuser des privilèges UniversalXPConnect.

    I’ve tried these with no luck in user.js:
    user_pref("capability.principal.codebase.p0.granted", "UniversalXPConnect");
    user_pref("capability.principal.codebase.p0.id", "http://atilf.atilf.fr");
    user_pref("capability.principal.codebase.p0.subjectName", "");

    user_pref("capability.principal.codebase.p1.granted", "UniversalXPConnect");
    user_pref("capability.principal.codebase.p1.id", "http://dell");
    user_pref("capability.principal.codebase.p1.subjectName", "");

    user_pref("capability.policy.policynames", "allowclipboard");
    user_pref("capability.policy.allowclipboard.sites", "file:// http://dell http://atilf.atilf.fr");
    user_pref("capability.policy.allowclipboard.Clipboard.cutcopy", "allAccess");
    user_pref("capability.policy.allowclipboard.Clipboard.paste", "allAccess");

    /*
    user_pref("capability.policy.allowclipboard.UniversalXPConnect.QueryInterface", "allAccess");
    user_pref("capability.policy.allowclipboard.UniversalXPConnect.createInstance", "allAccess");
    user_pref("capability.policy.allowclipboard.UniversalXPConnect.equals", "allAccess");
    user_pref("capability.policy.allowclipboard.UniversalXPConnect.getService", "allAccess");
    user_pref("capability.policy.allowclipboard.UniversalXPConnect.initialize", "allAccess");
    */

    and my favelet:
    function getClipboardText() {

    if (window.clipboardData) // IE
    return (window.clipboardData.getData('Text'));

    if (!window.netscape) // promt for text if not Mozilla
    return prompt();

    // ask permission to Mozilla
    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

    // go on with XUL code
    var clip = Components
    .classes['@mozilla.org/widget/clipboard;1']
    .createInstance(Components.interfaces.nsIClipboard),
    trans = Components
    .classes['@mozilla.org/widget/transferable;1']
    .createInstance(Components.interfaces.nsITransferable),
    str = {},
    len = {};

    trans.addDataFlavor('text/unicode');
    clip.getData(trans, clip.kGlobalClipboard);
    trans.getTransferData('text/unicode', str, len);

    str = Components.interfaces.nsISupportsWString
    ? str.value.QueryInterface(Components.interfaces.nsISupportsWString)
    : str.value.QueryInterface(Components.interfaces.nsISupportsString);

    return(str.data.substring(0, len.value / 2));
    }

    var clip = getClipboardText();

    console.log(clip);

    //document.form1.elements.mot.value = clip;

    //verif1();

    Thanks for the XHR code. I’ve added it to my FF dev profile. Now I can code cross-domain ajax.

  6. Posted February 15, 2008 at 9:54 pm | Permalink

    Problem solved. A Firefox search engine xml file has been made for this dictionnary (and more):
    http://www.cnrtl.fr/portail/#footerright

  7. Jeremy
    Posted May 9, 2008 at 5:58 pm | Permalink

    If you want to ensure that what you are developing works for other users who will not want to do this to their firefox use this:

    try{
    // IE understands this
    var xml = $(response.responseXML)
    var codes = xml.documentElement.getElementsByTagName(“code”)
    }catch(e){
    //firefox understands this
    try{
    var xml = (new DOMParser()).parseFromString( response.responseXML, “text/xml”);
    var codes = xml.documentElement.getElementsByTagName(“code”)
    }catch(ee){
    }
    }

  8. Zach Leatherman
    Posted May 9, 2008 at 10:25 pm | Permalink

    Dude, what?

    To me that says:
    I can parse an XML document.
    OR if I can’t, try a new way.

    That doesn’t have anything to do with XHR, other than supplying using it to supply an XML document.

  9. Zach Leatherman
    Posted May 10, 2008 at 1:10 pm | Permalink

    Also, please keep in mind that this is NOT a production solution. It’s a development solution for individual development machines.

  10. Arian Hojat
    Posted June 18, 2008 at 9:37 am | Permalink

    Heard this was a viable production solution:
    use php to pull the xml, and feed it into the javascript.

    http://www.phpfour.com/blog/2008/03/06/cross-domain-ajax-using-php/

  11. Zach Leatherman
    Posted June 18, 2008 at 5:24 pm | Permalink

    Sure, this method is a client-side only solution. It’s fairly trivial (and common) to use a server side language to act as a proxy for your ajax calls.

  12. mark
    Posted July 9, 2008 at 12:46 pm | Permalink

    hi board!

    y have this error,
    Permiso para obtener la propiedad Element.childNodes denegado

    in english
    Permission denied to get property Element.childNodes

    and i create prefs.js file, and i have this error yet… i am using V 3.0

    tks for u help.

  13. Sean
    Posted August 12, 2008 at 6:31 am | Permalink

    I’ve read that the above technique will not work under Firefox 3. My tests seem to confirm this. And, there’s this thread:

    http://groups.google.com/group/mozilla.dev.apps.firefox/browse_thread/thread/0b3db90e1b452f33/d4fd6124df529739

    So, is it game over?

  14. Zach Leatherman
    Posted August 12, 2008 at 7:19 am | Permalink

    Never say die.

    http://developer.mozilla.org/en/docs/Cross-Site_XMLHttpRequest

    Looks like you could make a plugin that enables this for the web :) Have at it!

  15. venkat
    Posted February 12, 2009 at 7:30 am | Permalink

    Hi,

    Many thanks to you. But my firefox doent get updated with the new user prefs. im running 3.0.6. Any clues.

  16. Zach Leatherman
    Posted February 12, 2009 at 11:16 am | Permalink

    If you’re having trouble modifying your prefs, you probably still have Firefox open. You must close Firefox when editing prefs.js. Also, the above code was tested only with Firefox 2, as stated below the headline.

  17. Animal
    Posted May 9, 2009 at 10:40 am | Permalink

    Sorry, but NONE of this works.

  18. Zach Leatherman
    Posted May 10, 2009 at 9:58 am | Permalink

    Again, please keep in mind that this post should be considered deprecated, as it does not apply to the current version of Firefox.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Additional comments powered by BackType