12

I'm developing a JavaScript application that's meant to be run either from a web server (over http) or from the file system (on a file:// URL).

As part of this code, I need to use XMLHttpRequest to load files in the same directory as the page and in subdirectories of the page.

This code works fine ("PASS") when executed on a web server, but doesn't work ("FAIL") in Internet Explorer 8 when run off the file system:

<html><head>
<script>
window.onload = function() {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", window.location.href, false);
  xhr.send(null);
  if (/TestString/.test(xhr.responseText)) {
    document.body.innerHTML="<p>PASS</p>";
  }
}
</script>
<body><p>FAIL</p></body>

Of course, at first it fails because no scripts can run at all on the file system; the user is prompted a yellow bar, warning that "To help protect your security, Internet Explorer has restricted this webpage from running scripts or ActiveX controls that could access your computer."

But even once I click on the bar and "Allow Blocked Content" the page still fails; I get an "Access is Denied" error on the xhr.open call.

This puzzles me, because MSDN says that "For development purposes, the file:// protocol is allowed from the Local Machine zone." This local file should be part of the Local Machine Zone, right?

How can I get code like this to work? I'm fine with prompting the user with security warnings; I'm not OK with forcing them to turn off security in the control panel.

EDIT: I am not, in fact, loading an XML document in my case; I'm loading a plain text file (.txt).

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Dan Fabulich
  • 37,506
  • 41
  • 139
  • 175
  • Did you try var xhr = new ActiveXObject("MSXML2.XMLHTTP"); (see my answer below)? That shouldn't be limited to XML files. But it will be limited to IE. – Don Jan 26 '10 at 20:43
  • FWIW, I have the same problem in Chrome doing basically the same thing. – jyoungdev Jan 24 '13 at 15:36

5 Answers5

8

Hmm, could it be the difference between the native XMLHttpRequest object and the ActiveX one? I seem to remember something about that. That is, instead of

var xhr = new XMLHttpRequest();

try

var xhr = new ActiveXObject("MSXML2.XMLHTTP");

Obviously, put some checks in place to see if the browser supports ActiveX. Of course, this is limited to IE only, as well.

Don
  • 3,654
  • 1
  • 26
  • 47
8

How can I get code like this to work?

As suggested above, this looks like a fault in Microsoft XMLHttpRequest. jQuery (Jul 2011) also writes:-

Microsoft failed to properly implement the XMLHttpRequest in IE7 (can't request local files)

I confirm this failure for IE8 too.

A solution is to use new window.ActiveXObject( "Microsoft.XMLHTTP" ) for local files if XMLHttpRequest doesn't work.

The failure is in the xhr.open line so it can be caught there and then try ActiveXObject as follows:-

var xhr = new XMLHttpRequest()
try {
    xhr.open('GET', url, true)
}
catch(e) {
    try {
        xhr = new ActiveXObject('Microsoft.XMLHTTP')
        xhr.open('GET', url, true)
    }
    catch (e1) {
        throw new Error("Exception during GET request: " + e1)
    }
}

This code will at least use standard XMLHttpRequest for IE9 (untested) and future IE browsers if/when Microsoft fixes the fault. With the jQuery code above, non standard Microsoft.XMLHTTP will be used whenever ActiveXObject is available, even if Microsoft fix the fault.

Adriano Carneiro
  • 57,693
  • 12
  • 90
  • 123
Anon
  • 81
  • 1
  • 1
7

I just happened to stumble across exactly the same problem. As suggested above, the non-native ActiveX "constructor" works. I’m not really sure whether there are different policies applied to the two objects, but since jQuery mentions the same problem as well, it may be a genuine bug. Here is the relevant piece of code from the jQuery source (1.4.2, line 4948):

// Create the request object; Microsoft failed to properly
// implement the XMLHttpRequest in IE7 (can't request local files),
// so we use the ActiveXObject when it is available
// This function can be overriden by calling jQuery.ajaxSetup
xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
    function() {
        return new window.XMLHttpRequest();
    } :
    function() {
        try {
            return new window.ActiveXObject("Microsoft.XMLHTTP");
        } catch(e) {}
    }
Jan Zich
  • 14,993
  • 18
  • 61
  • 73
  • 1
    Ah, this explains why upgrading jQuery past v1.11.1 caused permission problems on IE11 at work when we used the .load method. I guess jQuery just stopped checking for this after a certain version. – General Grievance Mar 08 '18 at 04:22
1

I know this is old - but wanted to clarify what is going on with a little more detail, and offer a couple of potential options.

First off this is actually not a flaw within IE, but a security feature that exists in Chrome as well.

Basically, any resource URI with file:// prefix is not allowed to load any other resource URI with file:// prefix using XMLHttpRequest.

In IE you will see an Access Denied message. In Chrome you will see "Failed to load resource: Origin null is not allowed by Access-Control-Allow-Origin" More info -> Information on IE and Information on Chrome (look for --allow-file-access-from-files)

An interesting thing with IE is that if you are using the .NET Browser Control inside of a WinForm or Silverlight App, this feature is disabled, and you will not have the same issues.

There are a couple of workarounds that I am aware of - none of which are ideal, as they disable a measure of security protection

  • IE: The first, and most "benign", is that you can add the URI of the calling page to the Trusted Sites zone (Uncheck "Enable Protected Mode")
  • IE: following the link above there is a registry setting that you can modify which will disable this feature - but this would have to be done on each machine trying to load the resources
  • Chrome: The link above refers to using the command line switch when starting Chrome to disable the feature.

Once again, this is a security feature within browsers to mitigate potential threat vectors - similar to the Cross Domain scripting blocks.

Justin Greywolf
  • 650
  • 7
  • 17
0

Try this page. I resolved the problem by:

  1. Starting an http server in the workspace directory /home/user/web_ws through terminal:
    python -m SimpleHTTPServer
    It started Serving HTTP on 0.0.0.0 port 8000 ... with some GET requests..

  2. Then I loaded my web page (named check.html) in browser with web-address http://localhost:8000/check.html.
    So, my file:///home/user/web_ws/ was converted to http://localhost:8000/).

  3. Next thing was to set-up my workspace through Sources tab (from the Inspector dock). I just added my Workspace folder to the Sources workspace and all worked fine after that.

-Himanshu

(I'm not a web-developer, just have a little bit idea of html, xml, css, js, etc. and just happened to try sanity of a project of mine that uses xml files. If I'm not correct somewhere, do comment, Happy to learn ;-)

Himanshu Tanwar
  • 198
  • 1
  • 11