- From: Michael A. Puls II <shadow2531@gmail.com>
- Date: Tue, 18 Aug 2009 03:19:03 -0400
- To: public-webapps@w3.org
Currently, xhr's this.status model doesn't work too well with file://.
One big reason for this is that browser implementations don't simulate
HTTP status codes for file:// operations. In short, this.status always
equals 0, which means you have to do something like this:
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200 || document.location.protocol === "file:")
{
}
}
};
req.open("GET", "local_file.txt");
req.send();
You could also try (this.status === 200 || this.status === 0) if you
assume that the status will only be 0 for "file:" and no other condition.
Even then, depending on the browser implementation, if the local file is
not found, you might get an exception thrown in one browser or no
exception thrown and just this.responseText set to "" in another.
Further, for file://, you can't tell the difference between a file not
found error and a cross-origin attempt error (or an empty file in some
cases). You also can't specifically tell if the error is because access to
the file is denied.
Although XHR wasn't designed for file:// and its behavior remains
undefined in the spec, I believe simulating HTTP status codes for file
operations could help big time with these problems.
I'm not saying file: support should be added to the XHR spec, but there
should be some 'file:// for XHR' guidelines that browsers could use.
file:// should really be a first class citizen, imo.
Example:
var req = new XMLHttpRequest();
req.onreadstatechange = function() {
switch (this.readyState) {
case 0: // Unsent state
break;
case 1: // Open state
break;
case 2: // Headers_Received state
break;
case 3: // Loading state
break;
case 4: // Done state
switch(this.status) {
case 200: // OK
break;
case 404: // Not Found
break;
case 401: // Authorization required
break;
case 403: // Forbidden
break;
case 405: // Method not allowed
break;
case 501: // Not implemented
break;
case 414: // Request URI too long
break;
case 415: // Unsupported mime type
break;
case 0: // Done state error flag is true for some reason
break;
default: // Unsupported status codes
}
break;
default: // Unsupported states
}
};
try {
req.open("GET", "local_file.txt");
req.send();
} catch(error) {
alert(error);
}
1. For file:// access, make sure this.readyState always reaches 4.
2. For file:// access, simulate the appropriate HTTP status code for the
result so that this.status and this.statusText can be used properly.
3. Don't have open() throw for "file not found" and use 404 for
this.status instead.
4. If file:// access isn't implemented (like in IE), don't have open()
throw. Instead, make this.status be 501.
5. If the request URI result in too long of a path, use status code 414.
6. If the request URI points to a certain type of file the *browser*
doesn't want to allow access to (maybe an .exe), use status code 415.
7. If a method besides "GET" is used for open(), don't throw and use
status code 405.
8. Don't have open() throw for cross-domain security restriction. Instead,
use status code 403.
9. If the user doesn't have access to the file, don't have open() throw
and instead use status code 401.
10. responseText and responseXML should be null unless the status is 200.
11. For any other errors on .open(), SYNTAX_ERR or SECURITY_ERR should be
throw.
Easier Alternative:
1. Make sure this.readyState always makes it to 4.
2. Make open() throw for everything. The only time it would not throw is
if the file is found and accessible.
3. Make this.status equal 200.
4. For #1, throw different types of errors for each case. File not found,
access denied, cross-origin attempt etc.
Ulimately though, what I think would be great is if you could use XHR on
HTTP or locally (on file://) while using the exact same code to load a
file.
For example, the following should work exactly the same on both file and
http.
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
alert(this.responseText);
} else if (this.status === 404) {
alert("file not found");
}
}
};
req.open("GET", "file_in_same_dir.txt");
req.send();
Also, some have suggested that DOM3 Load & Save and document.load are not
needed if you have XHR (and DOMParser for the XML part). However, current
browser implementions of XHR file:// support can't simulate DOM3 Load &
Save's local file loading support completely. The error handling just
isn't there.
I realize XHR isn't made for file://, but browsers are already shoehorning
file:// into XHR. Might as well make things better.
If XHR and file:// work nicely, then one could wrap things into a nice
localLocalFile() function. Currently though, file:// + XHR doesn't make
for a very good low-level API that you can wrap.
--
Michael
Received on Tuesday, 18 August 2009 07:19:55 UTC