Skip to content

Instantly share code, notes, and snippets.

@maximerety
Last active May 23, 2018 09:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maximerety/92431f6f4cc9ea8f684de8c124469995 to your computer and use it in GitHub Desktop.
Save maximerety/92431f6f4cc9ea8f684de8c124469995 to your computer and use it in GitHub Desktop.
Safari issue with instanceof when retrieving data in an iframe

Bug filed: https://bugs.webkit.org/show_bug.cgi?id=185906

This gist demonstrates an unexpected behavior in Safari after retrieving data from indexedDB inside an iframe: values cannot be properly checked against constructors with instanceof.

Tested on Safari Version 11.1 (13605.1.33.1.4) on macOS High Sierra 10.13.4.

Pseudo code that runs in an iframe:

const record = { array: [1, 2, 3] };

// Same record retrieved later from indexedDB:
const record = event.target.result;
record.array instanceof Array; // expected true but false in Safari 11.1
record.array instanceof window.parent.Array; // expected false but true in Safari 11.1

A lot of libraries and home-made code rely on instanceof to work as expected on values retrieved from indexedDB in an iframe.

Demo files:

  • ok-indexeddb-instanceof.html: store and retrieve a record having Array and Uint8Array properties
  • ko-indexeddb-iframe.html: same test run inside an iframe

Related issues:

Usage:

  • Download this gist as a zip
  • Start a local webserver (e.g. python3 -m http.server)
  • Open the .html files in Safari
Filed: https://bugs.webkit.org/show_bug.cgi?id=185906
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>KO: retrieve complex data types (Array, UintArray, ...) in an iframe</title>
</head>
<body>
<!-- Include test page in an iframe -->
<iframe
src="./ok-indexeddb-instanceof.html"
style="width: 90vw; height: 90vh; margin: 0; padding: 0; border: none;"
>
</iframe>
</body>
</html>
<!DOCTYPE html>
<meta charset="utf-8">
<title>OK: store and retrieve complex data types (Array, UintArray, ...)</title>
<!-- Logging -->
<style type="text/css">
textarea#log {
width: 100%;
min-height: 300px;
}
</style>
<h3>Log</h3>
<textarea id="log"></textarea>
<script type="text/javascript">
const log = (...args) => {
console.log(...args);
document.getElementById('log').value += args.join(' ') + "\n";
};
</script>
<!-- Test script -->
<script type="text/javascript">
let db;
const record = {
id: 1,
array: [1, 2, 3],
uint8: Uint8Array.from([1, 2, 3])
};
const open_rq = window.indexedDB.open("TestConstructors", 1);
open_rq.onupgradeneeded = function (e) {
db = e.target.result;
const objStore = db.createObjectStore("store", { keyPath: "id" });
const add_rq = objStore.add(record);
add_rq.onerror = function (e) {
log("failed to add record (see console)");
console.error(e);
}
};
open_rq.onsuccess = function (e) {
if (!db) {
db = e.target.result;
}
const rq = db.transaction("store")
.objectStore("store")
.get(1);
rq.onsuccess = function (e) {
const result = e.target.result;
log("result.array instanceof Array:", result.array instanceof Array);
log("result.array instanceof window.parent.Array:", result.array instanceof window.parent.Array);
log("result.uint8 instanceof Uint8Array:", result.uint8 instanceof Uint8Array);
log("result.uint8 instanceof window.parent.Uint8Array:", result.uint8 instanceof window.parent.Uint8Array);
};
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment