Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read file:// URLs in IE XMLHttpRequest

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).

like image 922
Dan Fabulich Avatar asked Jan 26 '10 19:01

Dan Fabulich


People also ask

What is the correct XMLHttpRequest open () method format?

The async parameter of the open() method should be set to true: xhttp.

How do I use XMLHttpRequest?

To send an HTTP request, create an XMLHttpRequest object, open a URL, and send the request. After the transaction completes, the object will contain useful information such as the response body and the HTTP status of the result.

What is Xmlhttp?

XMLHttpRequest (XHR) is a JavaScript API to create AJAX requests. Its methods provide the ability to send network requests between the browser and a server.

Is XMLHttpRequest part of AJAX?

XMLHttpRequest is used heavily in AJAX programming. Despite its name, XMLHttpRequest can be used to retrieve any type of data, not just XML. If your communication needs to involve receiving event data or message data from a server, consider using server-sent events through the EventSource interface.


4 Answers

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.

like image 80
Anon Avatar answered Oct 19 '22 11:10

Anon


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.

like image 30
Justin Greywolf Avatar answered Oct 11 '22 21:10

Justin Greywolf


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.

like image 8
Don Avatar answered Oct 19 '22 12:10

Don


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) {}
    }
like image 7
Jan Zich Avatar answered Oct 19 '22 10:10

Jan Zich