blob: 36d67d8f07dcaf8becc68d1e96711c6d98534a18 [file] [log] [blame]
pwnallde422a82017-02-08 01:30:141<!doctype html>
2<meta charset=utf-8>
3<title>IndexedDB: Exceptions thrown during key conversion</title>
James Graham6d984d22017-03-08 13:12:224<meta name=timeout content=long>
pwnallde422a82017-02-08 01:30:145<script src="/resources/testharness.js"></script>
6<script src="/resources/testharnessreport.js"></script>
7<script src="support.js"></script>
8<script>
9
10// Convenience function for tests that only need to run code in onupgradeneeded.
11function indexeddb_upgrade_only_test(upgrade_callback, description) {
12 indexeddb_test(upgrade_callback, t => { t.done(); }, description);
13}
14
15// Key that throws during conversion.
16function throwing_key(name) {
17 var throws = [];
18 throws.length = 1;
Boris Zbarskyf294a122020-01-24 00:24:0019 const err = new Error('throwing from getter');
20 err.name = name;
pwnallde422a82017-02-08 01:30:1421 Object.defineProperty(throws, '0', {get: function() {
pwnallde422a82017-02-08 01:30:1422 throw err;
23 }, enumerable: true});
Boris Zbarskyf294a122020-01-24 00:24:0024 return [throws, err];
pwnallde422a82017-02-08 01:30:1425}
26
27var valid_key = [];
28var invalid_key = {};
29
30// Calls method on receiver with the specified number of args (default 1)
31// and asserts that the method fails appropriately (rethrowing if
32// conversion throws, or DataError if not a valid key), and that
33// the first argument is fully processed before the second argument
34// (if appropriate).
35function check_method(receiver, method, args) {
36 args = args || 1;
37 if (args < 2) {
Boris Zbarskyf294a122020-01-24 00:24:0038 const [key, err] = throwing_key('getter');
39 assert_throws_exactly(err, () => {
40 receiver[method](key);
pwnallde422a82017-02-08 01:30:1441 }, 'key conversion with throwing getter should rethrow');
42
Stephen McGruerd5103042020-01-23 21:45:4543 assert_throws_dom('DataError', () => {
pwnallde422a82017-02-08 01:30:1444 receiver[method](invalid_key);
45 }, 'key conversion with invalid key should throw DataError');
46 } else {
Boris Zbarskyf294a122020-01-24 00:24:0047 const [key1, err1] = throwing_key('getter 1');
48 const [key2, err2] = throwing_key('getter 2');
49 assert_throws_exactly(err1, () => {
50 receiver[method](key1, key2);
pwnallde422a82017-02-08 01:30:1451 }, 'first key conversion with throwing getter should rethrow');
52
Stephen McGruerd5103042020-01-23 21:45:4553 assert_throws_dom('DataError', () => {
Boris Zbarskyf294a122020-01-24 00:24:0054 receiver[method](invalid_key, key2);
pwnallde422a82017-02-08 01:30:1455 }, 'first key conversion with invalid key should throw DataError');
56
Boris Zbarskyf294a122020-01-24 00:24:0057 assert_throws_exactly(err2, () => {
58 receiver[method](valid_key, key2);
pwnallde422a82017-02-08 01:30:1459 }, 'second key conversion with throwing getter should rethrow');
60
Stephen McGruerd5103042020-01-23 21:45:4561 assert_throws_dom('DataError', () => {
pwnallde422a82017-02-08 01:30:1462 receiver[method](valid_key, invalid_key);
63 }, 'second key conversion with invalid key should throw DataError');
64 }
65}
66
67// Static key comparison utility on IDBFactory.
68test(t => {
69 check_method(indexedDB, 'cmp', 2);
70}, 'IDBFactory cmp() static with throwing/invalid keys');
71
72// Continue methods on IDBCursor.
73indexeddb_upgrade_only_test((t, db) => {
74 var store = db.createObjectStore('store');
75 store.put('a', 1).onerror = t.unreached_func('put should succeed');
76
77 var request = store.openCursor();
78 request.onerror = t.unreached_func('openCursor should succeed');
79 request.onsuccess = t.step_func(() => {
80 var cursor = request.result;
81 assert_not_equals(cursor, null, 'cursor should find a value');
82 check_method(cursor, 'continue');
83 });
84}, 'IDBCursor continue() method with throwing/invalid keys');
85
86indexeddb_upgrade_only_test((t, db) => {
87 var store = db.createObjectStore('store');
88 var index = store.createIndex('index', 'prop');
89 store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed');
90
91 var request = index.openCursor();
92 request.onerror = t.unreached_func('openCursor should succeed');
93 request.onsuccess = t.step_func(() => {
94 var cursor = request.result;
95 assert_not_equals(cursor, null, 'cursor should find a value');
96
97 check_method(cursor, 'continuePrimaryKey', 2);
98 });
99}, null, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys');
100
101// Mutation methods on IDBCursor.
102indexeddb_upgrade_only_test((t, db) => {
103 var store = db.createObjectStore('store', {keyPath: 'prop'});
104 store.put({prop: 1}).onerror = t.unreached_func('put should succeed');
105
106 var request = store.openCursor();
107 request.onerror = t.unreached_func('openCursor should succeed');
108 request.onsuccess = t.step_func(() => {
109 var cursor = request.result;
110 assert_not_equals(cursor, null, 'cursor should find a value');
111
112 var value = {};
Boris Zbarskyf294a122020-01-24 00:24:00113 var err;
114 [value.prop, err] = throwing_key('getter');
115 assert_throws_exactly(err, () => {
pwnallde422a82017-02-08 01:30:14116 cursor.update(value);
117 }, 'throwing getter should rethrow during clone');
118
119 // Throwing from the getter during key conversion is
120 // not possible since (1) a clone is used, (2) only own
121 // properties are cloned, and (3) only own properties
122 // are used for key path evaluation.
123
124 value.prop = invalid_key;
Stephen McGruerd5103042020-01-23 21:45:45125 assert_throws_dom('DataError', () => {
pwnallde422a82017-02-08 01:30:14126 cursor.update(value);
127 }, 'key conversion with invalid key should throw DataError');
128 });
129}, 'IDBCursor update() method with throwing/invalid keys');
130
131// Static constructors on IDBKeyRange
132['only', 'lowerBound', 'upperBound'].forEach(method => {
133 test(t => {
134 check_method(IDBKeyRange, method);
135 }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys');
136});
137
138test(t => {
139 check_method(IDBKeyRange, 'bound', 2);
140}, 'IDBKeyRange bound() static with throwing/invalid keys');
141
142// Insertion methods on IDBObjectStore.
143['add', 'put'].forEach(method => {
144 indexeddb_upgrade_only_test((t, db) => {
145 var out_of_line = db.createObjectStore('out-of-line keys');
146 var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'});
Boris Zbarskyf294a122020-01-24 00:24:00147 var [key, err] = throwing_key('getter');
148 assert_throws_exactly(err, () => {
149 out_of_line[method]('value', key);
pwnallde422a82017-02-08 01:30:14150 }, 'key conversion with throwing getter should rethrow');
151
Stephen McGruerd5103042020-01-23 21:45:45152 assert_throws_dom('DataError', () => {
pwnallde422a82017-02-08 01:30:14153 out_of_line[method]('value', invalid_key);
154 }, 'key conversion with invalid key should throw DataError');
155
156 var value = {};
Boris Zbarskyf294a122020-01-24 00:24:00157 [value.prop, err] = throwing_key('getter');
158 assert_throws_exactly(err, () => {
pwnallde422a82017-02-08 01:30:14159 in_line[method](value);
160 }, 'throwing getter should rethrow during clone');
161
162 // Throwing from the getter during key conversion is
163 // not possible since (1) a clone is used, (2) only own
164 // properties are cloned, and (3) only own properties
165 // are used for key path evaluation.
166
167 value.prop = invalid_key;
Stephen McGruerd5103042020-01-23 21:45:45168 assert_throws_dom('DataError', () => {
pwnallde422a82017-02-08 01:30:14169 in_line[method](value);
170 }, 'key conversion with invalid key should throw DataError');
171 }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
172});
173
174// Generic (key-or-key-path) methods on IDBObjectStore.
175[
176 'delete', 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
177 'openKeyCursor'
178].forEach(method => {
179 indexeddb_upgrade_only_test((t, db) => {
180 var store = db.createObjectStore('store');
181
182 check_method(store, method);
183 }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
184});
185
186// Generic (key-or-key-path) methods on IDBIndex.
187[
188 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
189 'openKeyCursor'
190].forEach(method => {
191 indexeddb_upgrade_only_test((t, db) => {
192 var store = db.createObjectStore('store');
193 var index = store.createIndex('index', 'keyPath');
194
195 check_method(index, method);
196 }, `IDBIndex ${method}() method with throwing/invalid keys`);
197});
198
199</script>