- 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