filerjs / filer

Node-like file system for browsers
BSD 2-Clause "Simplified" License
618 stars 154 forks source link

Does not skip browser tests when IndexedDB is not supported #434

Open 0xazure opened 6 years ago

0xazure commented 6 years ago

While attempting to verify #433, I ran into an interesting issue when running the in-browser tests using Firefox 63.0b2 (64-bit).

Skipping provider tests for `WebSQL'--not supported in current environment.  providers.base.js:13:4
TypeError: this.db is null, can't access property "transaction" of it  indexeddb.js:22:6

IndexedDB is not always supported in every browser context. Notably, Incognito in Chrome supports IndexedDB, but Private Browsing Mode in Firefox does not.

In the above error message, the tests are not run for the WebSQL provider as intended in Private Browsing Mode, but it does not skip the tests for IndexedDB as it should.

humphd commented 6 years ago

If the issue relates to Private Browsing and Firefox, the problem is that the browser reports that indexDB is available, but throws when you try to access it. We've filed this with Mozilla, and it's in their queue, but hasn't been addressed yet. Chrome allows the tests to work in a private tab, but then deletes the DB. I'm not sure we can fix this on our end.

0xazure commented 6 years ago

For IndexedDB.isSupported(), it simply checks if the indexedDB reference grabbed from global exists.

We could enhance this feature detection to actually attempt an operation on IndexedDB, such as opening a connection, test if it succeeds or fails, and then cache the result for future calls to isSupported(). I found an (MIT-licensed) example in Modernizr on how we could go about doing this.

humphd commented 6 years ago

@0xazure unfortunately, it's not that simple. I've discussed this with the IndexedDB devs at Mozilla in the past. Firefox will throw a security exception, which is un-catchable if you touch it. There is a way to do this, but it's a bit hacky:

  1. create an iframe
  2. postMessage to the iframe and ask it to test for you
  3. in the iframe, setup a timeout to respond back to the parent window indicating failure
  4. try to touch open a db connection and then postMessage back to the parent that it worked, removing your failure timeout.

In this way you can safely fail to access the db, and send back info on whether or not it exists and can be used.

0xazure commented 6 years ago

Firefox will throw a security exception, which is un-catchable if you touch it.

Interesting! On Firefox 61.0.2 (64-bit) and 63.0b8 (64-bit) I'm not able to reproduce this behaviuor with the following snippet:

var DBOpenRequest = window.indexedDB.open(`test-${Math.random()}`);
DBOpenRequest.onsuccess = function(e) {
  console.log('have IndexedDB instance');
}

DBOpenRequest.onerror = function(e) {
 console.log('open request failed');
}

Running the snippet from Scratchpad, in a normal window I get the have IndexedDB instance message and in a Private Browsing Mode window I get open request failed as expected. I don't get any thrown errors, un-catchable or otherwise.

Perhaps the behaviour changed in newer versions of Firefox? I don't have access to any pre-Quantum versions right now, so it would take some investigation to determine if this is the case.

humphd commented 6 years ago

Sounds like things have changed, which would be great.

0xazure commented 6 years ago

@humphd where would we like to go with this? I can have a look at implementing some better IndexedDB detection, but I'm not sure how we want to go about verifying behaviour on older versions of the supported browsers so we don't trigger unrecoverable security exceptions.