Question

I tried to write a bit of code to retrieve an image file (from Wikimedia Commons), store it locally and then display it. Here my code:

<!DOCTYPE html> 
<html> 
<head>
<script>

window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;

function onError(e) {
  console.log('Error', e);
}

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://upload.wikimedia.org/wikipedia/fr/2/26/10_francs_Mathieu_1987_F365-28_revers.jpg', true);
xhr.responseType = 'blob';

xhr.onload = function(e) {

window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {alert(fs.root.name);}, onError);

  window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
    fs.root.getFile('image.jpg', {create: true}, function(fileEntry) {
      fileEntry.createWriter(function(writer) {

        writer.onwrite = function(e) {};
        writer.onerror = function(e) {};

        var blob = new Blob([xhr.response], {type: 'image/jpeg'});

        writer.write(blob);

      }, onError);
    }, onError);
  }, onError);

  window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
    fs.root.getFile('image.jpg', {create: false}, function(fileEntry) {
        fileEntry.file(function(file) {
            var reader = new FileReader();
            reader.onloadend = function(event) {
                var img = document.createElement("img");
                img.src = event.target.result;

                document.body.parentNode.insertBefore(img, document.body.nextSibling);
            };
            reader.readAsDataURL(file);
        }, onError);
    }, onError);
  }, onError);

};

xhr.send();
</script>
</head> 
<body>

</body>
</html>

Nothing is displayed. Chrome's console doesn't display any error message, so I have no idea why it's not working. Any clue?

Edit :

I have just seen I actually get a FileError, code 10, which means QUOTA_EXCEEDED_ERR, even if I start my Google Chrome with these parameters:

"C:\Program Files\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files --unlimited-quota-for-files

Actually, I get the same error with or without the --unlimited-quota-for-files parameter, which is weird. But I get a File Error 2 without --allow-file-access-from-files

Was it helpful?

Solution 3

I added a call to window.webkitStorageInfo.requestQuota, and now it works. I can't get why it is necessary, as I started Chrome with the --unlimited-quota-for-files option.

Here the working code:

<!DOCTYPE html> 
<html> 
<head>
<script>

window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;

function onError(e) {
  console.log('Error', e);
}

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://upload.wikimedia.org/wikipedia/fr/2/26/10_francs_Mathieu_1987_F365-28_revers.jpg', true);
xhr.responseType = 'blob';

xhr.onload = function(e) {
  window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
  window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
    fs.root.getFile('image.jpg', {create: true}, function(fileEntry) {
      fileEntry.createWriter(function(writer) {

        writer.onwrite = function(e) {};
        writer.onerror = function(e) {};

        var blob = new Blob([xhr.response], {type: 'image/jpeg'});

        writer.write(blob);

      }, function(e) {
  console.log('Error', e);
});
    }, function(e) {
  console.log('Error', e);
});
  }, function(e) {
  console.log('Error', e);
});
}, function(e) {
  console.log('Error', e);
});

  window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
    fs.root.getFile('image.jpg', {create: false}, function(fileEntry) {
        fileEntry.file(function(file) {
            var reader = new FileReader();
            reader.onloadend = function(event) {
                var img = document.createElement("img");
                img.src = event.target.result;

                document.body.parentNode.insertBefore(img, document.body.nextSibling);
            };
            reader.readAsDataURL(file);
        }, function(e) {
  console.log('Error', e);
});
    }, function(e) {
  console.log('Error', e);
});
  }, function(e) {
  console.log('Error', e);
});

};

xhr.send();
</script>
</head> 
<body>

</body>
</html>

OTHER TIPS

In answer to your questions about why launching with "--unlimited-quota-for-files" won't work, I think you're confusing two different things. That parameter simply removed the quota limit, it does not automatically pre-approve scripts to usurp space in the sandbox without permission. If you were using "temporary" file system request, then it would allocate it without prompt (see link at the end of my answer).

But as you experienced by needing to call the requestQuota() method, Chrome will not allow the allocation of persistent file system storage without explicit user permission. There are a few reasons for this, but security as the best: namely that if Chrome were to allocate persistent file system storage on demand (without user knowledge) to any script that asked for it, then a malicious script could quick easily fill a user's hard drive, crash Chrome memory due to many thousands of objects, and cause general mayhem. Such a vulnerability could also trigger buffer overflows by hammering the memory like that.

Bottom line: Chrome only allows persistent file system storage with user approval. More from Google: Managing HTML5 Offline Storage:Persistent storage

If anyone stumbles across this the --unlimited-quota-for-files is no longer a valid flag. However, there is a list of current chromium flags maintained here.

--unlimited-storage would be the new flag to run, I believe.

Overrides per-origin quota settings to unlimited storage for any apps/origins. This should be used only for testing purpose.

I think you had to update to the quota request because the flag didn't override anything (but I don't actually know when the flag itself was deprecated). Because it didn't work as it previously did (assuming your code either worked before, or you got it from a tutorial) I think the browser fell-back on the quota system when the overide didn't happen and saw the quota was exceeded with what you were doing, thus throwing the exception.

You got the File Error without the --allow-file-access-from-files because it'd be a security issue if the browser was allowed to access those files under normal operation, hence the File Error should've been of type SECURITY_ERR.

The information in the following link is old, but the tactic is similar to the code in question(the flag being --unlimited-storage now instead).See this article for more details.

All said, In an actual application the Quota request is a must and the OP's solution at the time of this writing contained the correct code. Currently the javascript for the quota and fs request would look as follows:

navigator.webkitPersistentStorage.requestQuota(1024*1024, function(mB){
  window.requestFileSystem(PERSISTENT, mB, function(fs){
       //fs write/read, ect. code goes here. Or set a global variable to the value fs
       globalFS = fs; //to be accessed later in code, so you don't have to keep requesting.
  }, onError);
}, onError);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top