blob: 4dd5d9005b6cb6e4c2c7dccaef62804bfcdb73ec [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;
19 Object.defineProperty(throws, '0', {get: function() {
20 var err = new Error('throwing from getter');
21 err.name = name;
22 throw err;
23 }, enumerable: true});
24 return throws;
25}
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) {
38 assert_throws({name:'getter'}, () => {
39 receiver[method](throwing_key('getter'));
40 }, 'key conversion with throwing getter should rethrow');
41
42 assert_throws('DataError', () => {
43 receiver[method](invalid_key);
44 }, 'key conversion with invalid key should throw DataError');
45 } else {
46 assert_throws({name:'getter 1'}, () => {
47 receiver[method](throwing_key('getter 1'), throwing_key('getter 2'));
48 }, 'first key conversion with throwing getter should rethrow');
49
50 assert_throws('DataError', () => {
51 receiver[method](invalid_key, throwing_key('getter 2'));
52 }, 'first key conversion with invalid key should throw DataError');
53
54 assert_throws({name:'getter 2'}, () => {
55 receiver[method](valid_key, throwing_key('getter 2'));
56 }, 'second key conversion with throwing getter should rethrow');
57
58 assert_throws('DataError', () => {
59 receiver[method](valid_key, invalid_key);
60 }, 'second key conversion with invalid key should throw DataError');
61 }
62}
63
64// Static key comparison utility on IDBFactory.
65test(t => {
66 check_method(indexedDB, 'cmp', 2);
67}, 'IDBFactory cmp() static with throwing/invalid keys');
68
69// Continue methods on IDBCursor.
70indexeddb_upgrade_only_test((t, db) => {
71 var store = db.createObjectStore('store');
72 store.put('a', 1).onerror = t.unreached_func('put should succeed');
73
74 var request = store.openCursor();
75 request.onerror = t.unreached_func('openCursor should succeed');
76 request.onsuccess = t.step_func(() => {
77 var cursor = request.result;
78 assert_not_equals(cursor, null, 'cursor should find a value');
79 check_method(cursor, 'continue');
80 });
81}, 'IDBCursor continue() method with throwing/invalid keys');
82
83indexeddb_upgrade_only_test((t, db) => {
84 var store = db.createObjectStore('store');
85 var index = store.createIndex('index', 'prop');
86 store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed');
87
88 var request = index.openCursor();
89 request.onerror = t.unreached_func('openCursor should succeed');
90 request.onsuccess = t.step_func(() => {
91 var cursor = request.result;
92 assert_not_equals(cursor, null, 'cursor should find a value');
93
94 check_method(cursor, 'continuePrimaryKey', 2);
95 });
96}, null, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys');
97
98// Mutation methods on IDBCursor.
99indexeddb_upgrade_only_test((t, db) => {
100 var store = db.createObjectStore('store', {keyPath: 'prop'});
101 store.put({prop: 1}).onerror = t.unreached_func('put should succeed');
102
103 var request = store.openCursor();
104 request.onerror = t.unreached_func('openCursor should succeed');
105 request.onsuccess = t.step_func(() => {
106 var cursor = request.result;
107 assert_not_equals(cursor, null, 'cursor should find a value');
108
109 var value = {};
110 value.prop = throwing_key('getter');
111 assert_throws({name: 'getter'}, () => {
112 cursor.update(value);
113 }, 'throwing getter should rethrow during clone');
114
115 // Throwing from the getter during key conversion is
116 // not possible since (1) a clone is used, (2) only own
117 // properties are cloned, and (3) only own properties
118 // are used for key path evaluation.
119
120 value.prop = invalid_key;
121 assert_throws('DataError', () => {
122 cursor.update(value);
123 }, 'key conversion with invalid key should throw DataError');
124 });
125}, 'IDBCursor update() method with throwing/invalid keys');
126
127// Static constructors on IDBKeyRange
128['only', 'lowerBound', 'upperBound'].forEach(method => {
129 test(t => {
130 check_method(IDBKeyRange, method);
131 }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys');
132});
133
134test(t => {
135 check_method(IDBKeyRange, 'bound', 2);
136}, 'IDBKeyRange bound() static with throwing/invalid keys');
137
138// Insertion methods on IDBObjectStore.
139['add', 'put'].forEach(method => {
140 indexeddb_upgrade_only_test((t, db) => {
141 var out_of_line = db.createObjectStore('out-of-line keys');
142 var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'});
143
144 assert_throws({name:'getter'}, () => {
145 out_of_line[method]('value', throwing_key('getter'));
146 }, 'key conversion with throwing getter should rethrow');
147
148 assert_throws('DataError', () => {
149 out_of_line[method]('value', invalid_key);
150 }, 'key conversion with invalid key should throw DataError');
151
152 var value = {};
153 value.prop = throwing_key('getter');
154 assert_throws({name:'getter'}, () => {
155 in_line[method](value);
156 }, 'throwing getter should rethrow during clone');
157
158 // Throwing from the getter during key conversion is
159 // not possible since (1) a clone is used, (2) only own
160 // properties are cloned, and (3) only own properties
161 // are used for key path evaluation.
162
163 value.prop = invalid_key;
164 assert_throws('DataError', () => {
165 in_line[method](value);
166 }, 'key conversion with invalid key should throw DataError');
167 }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
168});
169
170// Generic (key-or-key-path) methods on IDBObjectStore.
171[
172 'delete', 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
173 'openKeyCursor'
174].forEach(method => {
175 indexeddb_upgrade_only_test((t, db) => {
176 var store = db.createObjectStore('store');
177
178 check_method(store, method);
179 }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
180});
181
182// Generic (key-or-key-path) methods on IDBIndex.
183[
184 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
185 'openKeyCursor'
186].forEach(method => {
187 indexeddb_upgrade_only_test((t, db) => {
188 var store = db.createObjectStore('store');
189 var index = store.createIndex('index', 'keyPath');
190
191 check_method(index, method);
192 }, `IDBIndex ${method}() method with throwing/invalid keys`);
193});
194
195</script>